aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.hgtags4
-rw-r--r--.rootkeys237
-rw-r--r--BitKeeper/etc/ignore25
-rw-r--r--BitKeeper/etc/logging_ok5
-rw-r--r--docs/misc/VMX_changes.txt90
-rw-r--r--linux-2.4.29-xen-sparse/arch/xen/Makefile2
-rw-r--r--linux-2.4.29-xen-sparse/arch/xen/config.in15
-rw-r--r--linux-2.4.29-xen-sparse/arch/xen/defconfig-xen02
-rw-r--r--linux-2.4.29-xen-sparse/arch/xen/defconfig-xenU1
-rw-r--r--linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/Makefile10
-rw-r--r--linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/Makefile3
-rw-r--r--linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile3
-rw-r--r--linux-2.4.29-xen-sparse/arch/xen/kernel/setup.c4
-rw-r--r--linux-2.4.29-xen-sparse/arch/xen/mm/fault.c4
-rw-r--r--linux-2.4.29-xen-sparse/drivers/usb/hcd.c1511
-rw-r--r--linux-2.4.29-xen-sparse/include/asm-xen/msr.h138
-rwxr-xr-xlinux-2.4.29-xen-sparse/mkbuildtree9
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/Kconfig22
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/configs/xen0_defconfig6
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/configs/xenU_defconfig5
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/i386/Kconfig83
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/i386/kernel/Makefile7
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/i386/kernel/cpu/common.c17
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/i386/kernel/entry.S66
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/i386/kernel/head.S24
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/i386/kernel/irq.c258
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/i386/kernel/process.c3
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/i386/kernel/setup.c5
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/i386/kernel/smp.c599
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/i386/kernel/smpboot.c1364
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/i386/kernel/time.c90
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/i386/kernel/traps.c12
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/i386/mm/fault.c8
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/i386/mm/hypervisor.c215
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/kernel/Makefile3
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/kernel/ctrl_if.c135
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/kernel/evtchn.c120
-rw-r--r--linux-2.6.10-xen-sparse/arch/xen/kernel/smp.c19
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/Makefile1
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/blkback/blkback.c71
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/blkback/common.h23
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/blkback/interface.c23
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/blkfront/blkfront.c139
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/blkfront/block.h1
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/blktap/Makefile3
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap.c86
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap.h239
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_controlmsg.c510
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_datapath.c468
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_userdev.c406
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/console/console.c2
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/evtchn/evtchn.c17
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/netback/common.h2
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/netback/interface.c25
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/netback/netback.c1
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/privcmd/privcmd.c12
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/usbback/common.h85
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/usbback/control.c77
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/usbback/interface.c252
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/usbback/usbback.c1049
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/usbfront/usbfront.c1691
-rw-r--r--linux-2.6.10-xen-sparse/drivers/xen/usbfront/xhci.h210
-rw-r--r--linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h18
-rw-r--r--linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h59
-rw-r--r--linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/msr.h272
-rw-r--r--linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/pgtable-2level.h12
-rw-r--r--linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/processor.h4
-rw-r--r--linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/spinlock.h224
-rw-r--r--linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/system.h64
-rw-r--r--linux-2.6.10-xen-sparse/include/asm-xen/evtchn.h11
-rw-r--r--linux-2.6.10-xen-sparse/include/asm-xen/hypervisor.h50
-rw-r--r--linux-2.6.10-xen-sparse/include/asm-xen/multicall.h84
-rw-r--r--netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c15
-rw-r--r--patches/linux-2.6.9/drm.patch12
-rw-r--r--patches/linux-2.6.9/nettel.patch30
-rw-r--r--tools/Makefile7
-rw-r--r--tools/examples/Makefile3
-rw-r--r--tools/examples/bochsrc19
-rw-r--r--tools/examples/mem-map.sxp10
-rw-r--r--tools/examples/xmexample.vmx93
-rw-r--r--tools/examples/xmexample13
-rw-r--r--tools/examples/xmexample24
-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.h199
-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.cc317
-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.cc4066
-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.cc556
-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.cc872
-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.cc893
-rw-r--r--tools/ioemu/iodev/pit82c54.h134
-rw-r--r--tools/ioemu/iodev/pit_wrap.cc438
-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.cc443
-rw-r--r--tools/ioemu/mk/helix.mk6
-rw-r--r--tools/libxc/Makefile3
-rw-r--r--tools/libxc/linux_boot_params.h165
-rw-r--r--tools/libxc/xc.h23
-rw-r--r--tools/libxc/xc_domain.c4
-rw-r--r--tools/libxc/xc_linux_build.c157
-rw-r--r--tools/libxc/xc_linux_restore.c42
-rw-r--r--tools/libxc/xc_linux_save.c9
-rwxr-xr-xtools/libxc/xc_plan9_build.c59
-rw-r--r--tools/libxc/xc_private.c150
-rw-r--r--tools/libxc/xc_private.h13
-rw-r--r--tools/libxc/xc_vmx_build.c802
-rw-r--r--tools/libxutil/Makefile2
-rw-r--r--tools/misc/xend43
-rw-r--r--tools/python/setup.py1
-rw-r--r--tools/python/xen/lowlevel/xc/xc.c107
-rw-r--r--tools/python/xen/lowlevel/xu/xu.c872
-rw-r--r--tools/python/xen/util/memmap.py41
-rw-r--r--tools/python/xen/xend/XendDomainInfo.py137
-rw-r--r--tools/python/xen/xend/server/SrvDaemon.py18
-rw-r--r--tools/python/xen/xend/server/SrvUsbif.py249
-rwxr-xr-xtools/python/xen/xend/server/channel.py9
-rw-r--r--tools/python/xen/xend/server/messages.py68
-rwxr-xr-xtools/python/xen/xend/server/netif.py22
-rw-r--r--tools/python/xen/xend/server/usbif.py368
-rw-r--r--tools/python/xen/xm/create.py50
-rw-r--r--tools/xcs/Makefile48
-rw-r--r--tools/xcs/bindings.c179
-rw-r--r--tools/xcs/connection.c157
-rw-r--r--tools/xcs/ctrl_interface.c269
-rw-r--r--tools/xcs/evtchn.c108
-rw-r--r--tools/xcs/xcs.c880
-rw-r--r--tools/xcs/xcs.h155
-rw-r--r--tools/xcs/xcs_proto.h101
-rw-r--r--tools/xcs/xcsdump.c182
-rw-r--r--xen/Makefile8
-rw-r--r--xen/Rules.mk6
-rw-r--r--xen/arch/x86/Makefile12
-rw-r--r--xen/arch/x86/Rules.mk2
-rw-r--r--xen/arch/x86/boot/x86_32.S2
-rw-r--r--xen/arch/x86/boot/x86_64.S66
-rw-r--r--xen/arch/x86/dom0_ops.c92
-rw-r--r--xen/arch/x86/domain.c784
-rw-r--r--xen/arch/x86/e820.c21
-rw-r--r--xen/arch/x86/i387.c21
-rw-r--r--xen/arch/x86/idle0_task.c22
-rw-r--r--xen/arch/x86/io_apic.c8
-rw-r--r--xen/arch/x86/irq.c31
-rw-r--r--xen/arch/x86/memory.c313
-rw-r--r--xen/arch/x86/microcode.c2
-rw-r--r--xen/arch/x86/mpparse.c2
-rw-r--r--xen/arch/x86/mtrr/generic.c5
-rw-r--r--xen/arch/x86/mtrr/main.c3
-rw-r--r--xen/arch/x86/nmi.c9
-rw-r--r--xen/arch/x86/pci-pc.c2
-rw-r--r--xen/arch/x86/pdb-linux.c100
-rw-r--r--xen/arch/x86/pdb-stub.c1280
-rw-r--r--xen/arch/x86/setup.c102
-rw-r--r--xen/arch/x86/shadow.c424
-rw-r--r--xen/arch/x86/smpboot.c31
-rw-r--r--xen/arch/x86/time.c13
-rw-r--r--xen/arch/x86/traps.c589
-rw-r--r--xen/arch/x86/vmx.c939
-rw-r--r--xen/arch/x86/vmx_io.c388
-rw-r--r--xen/arch/x86/vmx_platform.c555
-rw-r--r--xen/arch/x86/vmx_vmcs.c504
-rw-r--r--xen/arch/x86/x86_32/asm-offsets.c22
-rw-r--r--xen/arch/x86/x86_32/domain_build.c402
-rw-r--r--xen/arch/x86/x86_32/entry.S147
-rw-r--r--xen/arch/x86/x86_32/mm.c194
-rw-r--r--xen/arch/x86/x86_32/seg_fixup.c27
-rw-r--r--xen/arch/x86/x86_32/traps.c254
-rw-r--r--xen/arch/x86/x86_32/usercopy.c137
-rw-r--r--xen/arch/x86/x86_32/xen.lds6
-rw-r--r--xen/arch/x86/x86_64/asm-offsets.c19
-rw-r--r--xen/arch/x86/x86_64/domain_build.c412
-rw-r--r--xen/arch/x86/x86_64/entry.S190
-rw-r--r--xen/arch/x86/x86_64/mm.c304
-rw-r--r--xen/arch/x86/x86_64/traps.c233
-rw-r--r--xen/arch/x86/x86_64/usercopy.c196
-rw-r--r--xen/arch/x86/x86_64/xen.lds6
-rw-r--r--xen/common/Makefile11
-rw-r--r--xen/common/ac_timer.c7
-rw-r--r--xen/common/debug-linux.c267
-rw-r--r--xen/common/debug.c113
-rw-r--r--xen/common/dom0_ops.c134
-rw-r--r--xen/common/dom_mem_ops.c33
-rw-r--r--xen/common/domain.c120
-rw-r--r--xen/common/elf.c6
-rw-r--r--xen/common/event_channel.c177
-rw-r--r--xen/common/grant_table.c19
-rw-r--r--xen/common/kernel.c3
-rw-r--r--xen/common/keyhandler.c29
-rw-r--r--xen/common/lib.c32
-rw-r--r--xen/common/multicall.c1
-rw-r--r--xen/common/page_alloc.c59
-rw-r--r--xen/common/perfc.c9
-rw-r--r--xen/common/physdev.c54
-rw-r--r--xen/common/resource.c3
-rw-r--r--xen/common/sched_atropos.c11
-rw-r--r--xen/common/sched_bvt.c247
-rw-r--r--xen/common/sched_rrobin.c16
-rw-r--r--xen/common/schedule.c189
-rw-r--r--xen/common/slab.c1844
-rw-r--r--xen/common/softirq.c1
-rw-r--r--xen/common/string.c1
-rw-r--r--xen/common/trace.c1
-rw-r--r--xen/common/vsprintf.c41
-rw-r--r--xen/common/xmalloc.c173
-rw-r--r--xen/drivers/char/console.c7
-rw-r--r--xen/drivers/char/serial.c10
-rw-r--r--xen/drivers/pci/pci.c6
-rw-r--r--xen/drivers/pci/setup-res.c4
-rw-r--r--xen/include/asm-x86/config.h84
-rw-r--r--xen/include/asm-x86/cpufeature.h4
-rw-r--r--xen/include/asm-x86/desc.h101
-rw-r--r--xen/include/asm-x86/domain.h119
-rw-r--r--xen/include/asm-x86/domain_page.h34
-rw-r--r--xen/include/asm-x86/e820.h10
-rw-r--r--xen/include/asm-x86/fixmap.h12
-rw-r--r--xen/include/asm-x86/i387.h8
-rw-r--r--xen/include/asm-x86/init.h29
-rw-r--r--xen/include/asm-x86/irq.h83
-rw-r--r--xen/include/asm-x86/ldt.h16
-rw-r--r--xen/include/asm-x86/mm.h65
-rw-r--r--xen/include/asm-x86/msr.h32
-rw-r--r--xen/include/asm-x86/page.h41
-rw-r--r--xen/include/asm-x86/pda.h63
-rw-r--r--xen/include/asm-x86/pdb.h89
-rw-r--r--xen/include/asm-x86/processor.h168
-rw-r--r--xen/include/asm-x86/regs.h30
-rw-r--r--xen/include/asm-x86/shadow.h377
-rw-r--r--xen/include/asm-x86/smp.h5
-rw-r--r--xen/include/asm-x86/time.h7
-rw-r--r--xen/include/asm-x86/vmx.h251
-rw-r--r--xen/include/asm-x86/vmx_cpu.h35
-rw-r--r--xen/include/asm-x86/vmx_platform.h96
-rw-r--r--xen/include/asm-x86/vmx_vmcs.h214
-rw-r--r--xen/include/asm-x86/x86_32/asm_defns.h47
-rw-r--r--xen/include/asm-x86/x86_32/current.h16
-rw-r--r--xen/include/asm-x86/x86_32/domain_page.h29
-rw-r--r--xen/include/asm-x86/x86_32/regs.h26
-rw-r--r--xen/include/asm-x86/x86_32/uaccess.h124
-rw-r--r--xen/include/asm-x86/x86_64/asm_defns.h123
-rw-r--r--xen/include/asm-x86/x86_64/current.h33
-rw-r--r--xen/include/asm-x86/x86_64/desc.h118
-rw-r--r--xen/include/asm-x86/x86_64/domain_page.h13
-rw-r--r--xen/include/asm-x86/x86_64/regs.h143
-rw-r--r--xen/include/asm-x86/x86_64/uaccess.h449
-rw-r--r--xen/include/public/arch-x86_32.h13
-rw-r--r--xen/include/public/arch-x86_64.h74
-rw-r--r--xen/include/public/dom0_ops.h6
-rw-r--r--xen/include/public/event_channel.h15
-rw-r--r--xen/include/public/io/blkif.h24
-rw-r--r--xen/include/public/io/domain_controller.h229
-rw-r--r--xen/include/public/io/ioreq.h60
-rw-r--r--xen/include/public/io/ring.h254
-rw-r--r--xen/include/public/io/usbif.h67
-rw-r--r--xen/include/public/xen.h96
-rw-r--r--xen/include/xen/domain.h12
-rw-r--r--xen/include/xen/elf.h4
-rw-r--r--xen/include/xen/event.h28
-rw-r--r--xen/include/xen/init.h25
-rw-r--r--xen/include/xen/irq.h3
-rw-r--r--xen/include/xen/keyhandler.h2
-rw-r--r--xen/include/xen/list.h12
-rw-r--r--xen/include/xen/sched-if.h20
-rw-r--r--xen/include/xen/sched.h227
-rw-r--r--xen/include/xen/slab.h52
-rw-r--r--xen/include/xen/time.h5
-rw-r--r--xen/include/xen/types.h2
414 files changed, 87019 insertions, 8825 deletions
diff --git a/.hgtags b/.hgtags
index 22f47de447..09382d2d5f 100644
--- a/.hgtags
+++ b/.hgtags
@@ -1,6 +1,8 @@
42882b3e0dda89f3a8ec00da568f86e9b3c230f1 RELEASE-2.0.0
475a162b66e2c19b1e9468b234a4ba705334905e RELEASE-2.0.1
-82ba8bd1ceb2e03af769775fb8bc890dcab04f72 RELEASE-2.0.3
+dc2f08429f17e6614fd2f1ab88cc09ca0a850f32 RELEASE-2.0.2
+6e1bbc13911751efa0b1c018425c1b085820fa02 RELEASE-2.0.3
+fb875591fd72e15c31879c0e9034d99b80225595 RELEASE-2.0.4
487b2ee37d1cecb5f3e7a546b05ad097a0226f2f beta1
3d330e41f41ce1bc118c02346e18949ad5d67f6b latest-semistable
30c521db4c71960b0cf1d9c9e1b658e77b535a3e latest-stable
diff --git a/.rootkeys b/.rootkeys
index a6f49dc24c..d79a03aab0 100644
--- a/.rootkeys
+++ b/.rootkeys
@@ -15,6 +15,7 @@
4187c1c7IWmBinGdI19kL4MuZ6RLbQ docs/check_pkgs
3f9e7d60PWZJeVh5xdnk0nLUdxlqEA docs/figs/xenlogo.eps
418a3248xjIqmNKo0v_XQSfAvlBGFw docs/html.sty
+41c0c4116itF389v0CEWcmzue6zJkA docs/misc/VMX_changes.txt
4022a73cgxX1ryj1HgS-IwwB6NUi2A docs/misc/XenDebugger-HOWTO
412f4bd9sm5mCQ8BkrgKcAKZGadq7Q docs/misc/blkif-drivers-explained.txt
40d6ccbfKKBq8jE0ula4eHEzBiQuDA docs/misc/xen_config.html
@@ -62,6 +63,9 @@
4083dc16-Kd5y9psK_yk161sme5j5Q linux-2.4.29-xen-sparse/arch/xen/drivers/netif/Makefile
4083dc16UmHXxS9g_UFVnkUpN-oP2Q linux-2.4.29-xen-sparse/arch/xen/drivers/netif/backend/Makefile
405853f2wg7JXZJNltspMwOZJklxgw linux-2.4.29-xen-sparse/arch/xen/drivers/netif/frontend/Makefile
+41ee5e8b_2rt-qHzbDXtIoBzOli0EA linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/Makefile
+41ee5e8bUhF4tH7OoJaVbUxdXqneVw linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/Makefile
+41ee5e8bSPpxzhGO6TrY20TegW3cZg linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile
3e5a4e65lWzkiPXsZdzPt2RNnJGG1g linux-2.4.29-xen-sparse/arch/xen/kernel/Makefile
3e5a4e65_hqfuxtGG8IUy6wRM86Ecg linux-2.4.29-xen-sparse/arch/xen/kernel/entry.S
3e5a4e65Hy_1iUvMTPsNqGNXd9uFpg linux-2.4.29-xen-sparse/arch/xen/kernel/head.S
@@ -86,6 +90,7 @@
3f108aeaLcGDgQdFAANLTUEid0a05w linux-2.4.29-xen-sparse/drivers/char/mem.c
3e5a4e66rw65CxyolW9PKz4GG42RcA linux-2.4.29-xen-sparse/drivers/char/tty_io.c
40c9c0c1pPwYE3-4i-oI3ubUu7UgvQ linux-2.4.29-xen-sparse/drivers/scsi/aic7xxx/Makefile
+41f97f64nW0wmgLxhwzPTzkF4E5ERA linux-2.4.29-xen-sparse/drivers/usb/hcd.c
3e5a4e669uzIE54VwucPYtGwXLAbzA linux-2.4.29-xen-sparse/fs/exec.c
3e5a4e66wbeCpsJgVf_U8Jde-CNcsA linux-2.4.29-xen-sparse/include/asm-xen/bugs.h
3e5a4e66HdSkvIV6SJ1evG_xmTmXHA linux-2.4.29-xen-sparse/include/asm-xen/desc.h
@@ -97,7 +102,6 @@
40d70c240tW7TWArl1VUgIFH2nVO1A linux-2.4.29-xen-sparse/include/asm-xen/keyboard.h
3e5a4e678ddsQOpbSiRdy1GRcDc9WA linux-2.4.29-xen-sparse/include/asm-xen/mmu_context.h
40d06e5b2YWInUX1Xv9amVANwd_2Xg linux-2.4.29-xen-sparse/include/asm-xen/module.h
-3f8707e7ZmZ6TxyX0ZUEfvhA2Pb_xQ linux-2.4.29-xen-sparse/include/asm-xen/msr.h
3e5a4e67mnQfh-R8KcQCaVo2Oho6yg linux-2.4.29-xen-sparse/include/asm-xen/page.h
409ba2e7ZfV5hqTvIzxLtpClnxtIzg linux-2.4.29-xen-sparse/include/asm-xen/pci.h
3e5a4e67uTYU5oEnIDjxuaez8njjqg linux-2.4.29-xen-sparse/include/asm-xen/pgalloc.h
@@ -145,12 +149,15 @@
40f56238bnvciAuyzAiMkdzGErYt1A linux-2.6.10-xen-sparse/arch/xen/i386/kernel/head.S
40f58a0d31M2EkuPbG94ns_nOi0PVA linux-2.6.10-xen-sparse/arch/xen/i386/kernel/i386_ksyms.c
40faa751_zbZlAmLyQgCXdYekVFdWA linux-2.6.10-xen-sparse/arch/xen/i386/kernel/ioport.c
+41d00d82zN8IfLBRxc7G_i7lbwT3cQ linux-2.6.10-xen-sparse/arch/xen/i386/kernel/irq.c
40f56238ue3YRsK52HG7iccNzP1AwQ linux-2.6.10-xen-sparse/arch/xen/i386/kernel/ldt.c
41d54a76YMCA67S8J-TBT3J62Wx6yA linux-2.6.10-xen-sparse/arch/xen/i386/kernel/microcode.c
4107adf1cNtsuOxOB4T6paAoY2R2PA linux-2.6.10-xen-sparse/arch/xen/i386/kernel/pci-dma.c
40f56238a8iOVDEoostsbun_sy2i4g linux-2.6.10-xen-sparse/arch/xen/i386/kernel/process.c
40f56238YQIJoYG2ehDGEcdTgLmGbg linux-2.6.10-xen-sparse/arch/xen/i386/kernel/setup.c
40f56238nWMQg7CKbyTy0KJNvCzbtg linux-2.6.10-xen-sparse/arch/xen/i386/kernel/signal.c
+41811cac4lkCB-fHir6CcxuEJ2pGsQ linux-2.6.10-xen-sparse/arch/xen/i386/kernel/smp.c
+41811ca9mbGpqBrZVrUGEiv8CTV3ng linux-2.6.10-xen-sparse/arch/xen/i386/kernel/smpboot.c
40f56238qVGkpO_ycnQA8k03kQzAgA linux-2.6.10-xen-sparse/arch/xen/i386/kernel/time.c
40f56238NzTgeO63RGoxHrW5NQeO3Q linux-2.6.10-xen-sparse/arch/xen/i386/kernel/timers/Makefile
40f56238BMqG5PuSHufpjbvp_helBw linux-2.6.10-xen-sparse/arch/xen/i386/kernel/timers/timer_tsc.c
@@ -176,6 +183,7 @@
412dfae9eA3_6e6bCGUtg1mj8b56fQ linux-2.6.10-xen-sparse/arch/xen/kernel/gnttab.c
40f562392LBhwmOxVPsYdkYXMxI_ZQ linux-2.6.10-xen-sparse/arch/xen/kernel/reboot.c
414c113396tK1HTVeUalm3u-1DF16g linux-2.6.10-xen-sparse/arch/xen/kernel/skbuff.c
+418f90e4lGdeJK9rmbOB1kN-IKSjsQ linux-2.6.10-xen-sparse/arch/xen/kernel/smp.c
3f68905c5eiA-lBMQSvXLMWS1ikDEA linux-2.6.10-xen-sparse/arch/xen/kernel/xen_proc.c
41261688yS8eAyy-7kzG4KBs0xbYCA linux-2.6.10-xen-sparse/drivers/Makefile
4108f5c1WfTIrs0HZFeV39sttekCTw linux-2.6.10-xen-sparse/drivers/char/mem.c
@@ -194,6 +202,12 @@
40f56239-JNIaTzlviVJohVdoYOUpw linux-2.6.10-xen-sparse/drivers/xen/blkfront/blkfront.c
40f56239y9naBTXe40Pi2J_z3p-d1g linux-2.6.10-xen-sparse/drivers/xen/blkfront/block.h
40f56239BVfPsXBiWQitXgDRtOsiqg linux-2.6.10-xen-sparse/drivers/xen/blkfront/vbd.c
+41a226e0vjAcDXHOnXE5ummcdUD2mg linux-2.6.10-xen-sparse/drivers/xen/blktap/Makefile
+41a226e0VeZA1N8tbU6nvJ3OxUcJmw linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap.c
+41a226e1k4J5VMLnrYXDWRqElS49YQ linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap.h
+41a226e1-A_Hy7utS8vJKaXnH_tzfA linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_controlmsg.c
+41a226e19NoUUTOvs7jumDMRYDIO4Q linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_datapath.c
+41a226e1MNSyWWK5dEVgvSQ5OW0fDA linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_userdev.c
40f56239fsLjvtD8YBRAWphps4FDjg linux-2.6.10-xen-sparse/drivers/xen/console/Makefile
3e5a4e651TH-SXHoufurnWjgl5bfOA linux-2.6.10-xen-sparse/drivers/xen/console/console.c
40f56239KYxO0YabhPzCTeUuln-lnA linux-2.6.10-xen-sparse/drivers/xen/evtchn/Makefile
@@ -208,6 +222,12 @@
405853f6nbeazrNyEWNHBuoSg2PiPA linux-2.6.10-xen-sparse/drivers/xen/netfront/netfront.c
4108f5c1ppFXVpQzCOAZ6xXYubsjKA linux-2.6.10-xen-sparse/drivers/xen/privcmd/Makefile
3e5a4e65IUfzzMu2kZFlGEB8-rpTaA linux-2.6.10-xen-sparse/drivers/xen/privcmd/privcmd.c
+41ee5e8bYDQkjRVKnFn5uFyy0KreCw linux-2.6.10-xen-sparse/drivers/xen/usbback/common.h
+41ee5e8bt7xeBUJqG5XJS-ofukdsgA linux-2.6.10-xen-sparse/drivers/xen/usbback/control.c
+41ee5e8bSs3BGC7yegM_ek2Tn0Ahvw linux-2.6.10-xen-sparse/drivers/xen/usbback/interface.c
+41ee5e8bglvqKvZSY5uJ5JGQejEwyQ linux-2.6.10-xen-sparse/drivers/xen/usbback/usbback.c
+41ee5e8ckZ9xVNvu9NHIZDK7JqApmQ linux-2.6.10-xen-sparse/drivers/xen/usbfront/usbfront.c
+41ee5e8ck9scpGirfqEZRARbGDyTXA linux-2.6.10-xen-sparse/drivers/xen/usbfront/xhci.h
412f47e4RKD-R5IS5gEXvcT8L4v8gA linux-2.6.10-xen-sparse/include/asm-generic/pgtable.h
40f56239YAjS52QG2FIAQpHDZAdGHg linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/desc.h
4107adf1E5O4ztGHNGMzCCNhcvqNow linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/dma-mapping.h
@@ -218,8 +238,8 @@
40f5623aKXkBBxgpLx2NcvkncQ1Yyw linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h
40f5623aDMCsWOFO0jktZ4e8sjwvEg linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/mach-xen/setup_arch_post.h
40f5623arsFXkGdPvIqvFi3yFXGR0Q linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/mach-xen/setup_arch_pre.h
+41811f07Iri9hrvs97t-baxmhOwWDQ linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h
4120f807GCO0uqsLqdZj9csxR1Wthw linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/mmu_context.h
-40f5623aFTyFTR-vdiA-KaGxk5JOKQ linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/msr.h
40f5623adgjZq9nAgCt0IXdWl7udSA linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/page.h
40f5623a54NuG-7qHihGYmw4wWQnMA linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/param.h
41137cc1kkvg0cg7uxddcEfjL7L67w linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/pci.h
@@ -231,6 +251,7 @@
412ea0afQL2CAI-f522TbLjLPMibPQ linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/ptrace.h
40f5623bzLvxr7WoJIxVf2OH4rCBJg linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/segment.h
40f5623bG_LzgG6-qwk292nTc5Wabw linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/setup.h
+4198c32a8NzmcKVOzKaEJfaQxxiA0A linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/spinlock.h
40f5623bgzm_9vwxpzJswlAxg298Gg linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/synch_bitops.h
40f5623bVdKP7Dt7qm8twu3NcnGNbA linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/system.h
40f5623bc8LKPRO09wY5dGDnY_YCpw linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/tlbflush.h
@@ -292,8 +313,6 @@
413cb3b5F56TvQWAmO5TsuzhtzLFPQ netbsd-2.0-xen-sparse/sys/arch/xen/xen/xenkbc.c
413cb3b53nyOv1OIeDSsCXhBFDXvJA netbsd-2.0-xen-sparse/sys/nfs/files.nfs
413aa1d0oNP8HXLvfPuMe6cSroUfSA patches/linux-2.6.9/agpgart.patch
-413aa1d0ewvSv-ohnNnQQNGsbPTTNA patches/linux-2.6.9/drm.patch
-418abc69J3F638vPO9MYoDGeYilxoQ patches/linux-2.6.9/nettel.patch
3f776bd1Hy9rn69ntXBhPReUFw9IEA tools/Makefile
40e1b09db5mN69Ijj0X_Eol-S7dXiw tools/Rules.mk
4124b307nRyK3dhn1hAsvrY76NuV3g tools/check/Makefile
@@ -311,8 +330,10 @@
401d7e16UgeqroJQTIhwkrDVkoWgZQ tools/examples/README
41597996VhTbNuHbuscYSfRb-WR6fA tools/examples/block-enbd
41597996GHP2_yVih2UspXh328fgMQ tools/examples/block-file
+41dde8af16Hulg1pgW8aOnbbxyrl7w tools/examples/bochsrc
405ff55dawQyCHFEnJ067ChPRoXBBA tools/examples/init.d/xend
40278d94cIUWl2eRgnwZtr4hTyWT1Q tools/examples/init.d/xendomains
+41dde8afTUuvdtFUlOx0ZRusKxyd8w tools/examples/mem-map.sxp
40ee75a9xFz6S05sDKu-JCLqyVTkDA tools/examples/network
41fc0c18hVgK5rKJyZUsqybux9D9Dg tools/examples/network-nat
41e661e1giIEKbJ25qfiP-ke8u8hFA tools/examples/network-route
@@ -320,10 +341,174 @@
41fc0c18AFAVXA1uGm1JFWHMeeznVw tools/examples/vif-nat
41e661e1ooiRKlOfwumG6wwzc0PdhQ tools/examples/vif-route
40ee75a93cqxHp6MiYXxxwR5j2_8QQ tools/examples/xend-config.sxp
+41dde8af6M2Pm1Rrv_f5jEFC_BIOIA tools/examples/xmexample.vmx
41090ec8Pj_bkgCBpg2W7WfmNkumEA tools/examples/xmexample1
40cf2937oKlROYOJTN8GWwWM5AmjBg tools/examples/xmexample2
41fc0c18_k4iL81hu4pMIWQu9dKpKA tools/examples/xmexample3
+41e2ff6dNPgvIrdIF6dC1azdex1U3A tools/ioemu/Makefile
+41e2ff6aoF5fgddZi0QpEWqFr89E5g tools/ioemu/font/vga.bitmap.h
+41e2ff6avgnBNvZRiL4ynyGGq2UKlw tools/ioemu/gui/Makefile
+41e2ff6a30Xuw7pDX3SlVBx3ssOMDQ tools/ioemu/gui/Makefile.in
+41e2ff6aGGn5D3-Yh856G7xWJ5ZJsA tools/ioemu/gui/bitmaps/cdromd.h
+41e2ff6abNiWU34DwftxJ30sI6TQmw tools/ioemu/gui/bitmaps/cdromd.xpm
+41e2ff6adSUYHlvyVpz7q1Izcx5_gQ tools/ioemu/gui/bitmaps/configbutton.h
+41e2ff6aLWWXfMqIH2jSCNUzuc4_Yg tools/ioemu/gui/bitmaps/configbutton.xpm
+41e2ff6ahsqMjwuhpbqfrFHCBqYhEA tools/ioemu/gui/bitmaps/copy.h
+41e2ff6ajL41CnUeGefMrNijudQlCg tools/ioemu/gui/bitmaps/copy.xpm
+41e2ff6aXn5GhkDNOGqUcfCLbDZf3w tools/ioemu/gui/bitmaps/floppya.h
+41e2ff6agOpnECodSZ62L-Uijy5fsQ tools/ioemu/gui/bitmaps/floppya.xpm
+41e2ff6akrHp6jG_Y2BmFpEcaswUqg tools/ioemu/gui/bitmaps/floppyb.h
+41e2ff6aGbvPO1cQLMLduGl16rntbg tools/ioemu/gui/bitmaps/floppyb.xpm
+41e2ff6aEcsgeBHQZ_5e3rfgo0USMA tools/ioemu/gui/bitmaps/mouse.h
+41e2ff6aO8pXESvDVxMG7TgZL7UvFA tools/ioemu/gui/bitmaps/mouse.xpm
+41e2ff6aSd1H6Z0dUVUYLsW-6EDrYw tools/ioemu/gui/bitmaps/paste.h
+41e2ff6aRGfY6Jd2TThqWtXoh2CHuQ tools/ioemu/gui/bitmaps/paste.xpm
+41e2ff6aKDap56ifPVgdBVPc9yfmvw tools/ioemu/gui/bitmaps/power.h
+41e2ff6aDLfEO8dFUd9IpsfUpMk-Vg tools/ioemu/gui/bitmaps/power.xpm
+41e2ff6aKWtTsWCds4vL2azV3w-XtQ tools/ioemu/gui/bitmaps/reset.h
+41e2ff6a_AU4_ytzHU0Btr3trcbVmA tools/ioemu/gui/bitmaps/reset.xpm
+41e2ff6a-hGpcXEChJQDo-xRyH5oGQ tools/ioemu/gui/bitmaps/snapshot.h
+41e2ff6aRoGi5nKyQFtcUzK0-9dRDA tools/ioemu/gui/bitmaps/snapshot.xpm
+41e2ff6aZdTp9lSJjyUI7YoXqQnCng tools/ioemu/gui/bitmaps/userbutton.h
+41e2ff6aWc4p23rAKngLMu8eLZiXlw tools/ioemu/gui/bitmaps/userbutton.xpm
+41e2ff6a7gMd57Q5DL0kRD-mR7JzZg tools/ioemu/gui/gui.cc
+41e2ff6a-USvofVXiSpY76RT4C0IVw tools/ioemu/gui/gui.h
+41e2ff6aYAuOb0x4zTVB7cWYIFIdOA tools/ioemu/gui/icon_bochs.h
+41e2ff6aZbFf-Djysg393N4vCEJ7ig tools/ioemu/gui/icon_bochs.xpm
+41e2ff6ai-vJcSE9hfz4SHZ20rK5QA tools/ioemu/gui/keymap.cc
+41e2ff6a_TY9EJnCcbr5EKV_pi90kg tools/ioemu/gui/keymap.h
+41e2ff6aP0co3DAK04MrugZCkp0roQ tools/ioemu/gui/keymaps/convertmap.pl
+41e2ff6a-GiP9bzqtVXEjxmxiYgzeg tools/ioemu/gui/keymaps/sdl-pc-de.map
+41e2ff6aa5xj7jyze5bcPnj-UHYgTQ tools/ioemu/gui/keymaps/sdl-pc-us.map
+41e2ff6ahemkf0kG8SzDXq8g2qp9Pg tools/ioemu/gui/keymaps/x11-pc-be.map
+41e2ff6ajdaBBS85yriZ3S9ecy5Odg tools/ioemu/gui/keymaps/x11-pc-da.map
+41e2ff6aGkLyRvwOTZnDqvobziAoiQ tools/ioemu/gui/keymaps/x11-pc-de.map
+41e2ff6aWcqOK6RjpY28Y4bVjMy9yg tools/ioemu/gui/keymaps/x11-pc-es.map
+41e2ff6aF46Uu09XOmmkcGDotToSxw tools/ioemu/gui/keymaps/x11-pc-fr.map
+41e2ff6aHM040MYLmOeW_PKIx1TWWg tools/ioemu/gui/keymaps/x11-pc-it.map
+41e2ff6aCa-6fHjBOoPWP8hDweZ1Fw tools/ioemu/gui/keymaps/x11-pc-se.map
+41e2ff6aUH4wvnqRwo91dJBnhxEYUg tools/ioemu/gui/keymaps/x11-pc-uk.map
+41e2ff6aF7b08llRJQBLgNAEfyn9wQ tools/ioemu/gui/keymaps/x11-pc-us.map
+41e2ff6a2gbWdoaE7X9vtizvQ4QqdQ tools/ioemu/gui/nogui.cc
+41e2ff6a_rWAWre2toEtNUMKliCJPA tools/ioemu/gui/rfb.cc
+41e2ff6aQfuugiO3YE07l03L6ASP9g tools/ioemu/gui/rfb.h
+41e2ff6aTWFzmW0sjxXpQq7ulaj_Pw tools/ioemu/gui/rfbproto.h
+41e2ff6bf4pfJkZTN5vA6HbiJJqeNA tools/ioemu/gui/sdl.h
+41e2ff6bVnojmIqKJCbhVUKtMcUWJg tools/ioemu/gui/sdlkeys.h
+41e2ff6bKVx97oSdGGToXQXvbQgkZA tools/ioemu/gui/siminterface.cc
+41e2ff6bDB5XABCVAA7nMolZPe5ZoA tools/ioemu/gui/siminterface.h
+41e2ff6benMg1o7HQ2C5PGS3KFHFow tools/ioemu/gui/svga.cc
+41e2ff6bz3XZGzzwvXGqFadb3QqWWQ tools/ioemu/gui/term.cc
+41e2ff6b8jzKgyKu2gNVlRWepPNA0A tools/ioemu/gui/textconfig.cc
+41e2ff6bUKaJhGtIDqUYzAesLg1MGA tools/ioemu/gui/textconfig.h
+41e2ff6b__Pd6Q2aYDZ5vB9bGJEMNA tools/ioemu/gui/x.cc
+41e2ff6bp96y5NyMIFjH-HpCRcGBPg tools/ioemu/include/bochs.h
+41e2ff6bqIMIJlitAnubjNjf70s3dw tools/ioemu/include/bxversion.h
+41e2ff6bTfksDlUXSWC_wC_g30r1cQ tools/ioemu/include/config.h
+41e2ff6bwDEGCUwYTf1oo9ZCva2nkw tools/ioemu/include/cpu/cpu.h
+41e2ff6bH1PTh2iMScpOn9v9R3SDag tools/ioemu/include/extplugin.h
+41e2ff6bFS9XP8ndI6IhGFitzsvTtw tools/ioemu/include/instrument.h
+41e2ff6bz71jKff_NUdmI279ArbMgw tools/ioemu/include/ltdl.h
+41e2ff6bYayW_YSVmb1sJCvk9z9-ug tools/ioemu/include/ltdlconf.h
+41e2ff6b_MdkIIjsFYTFMIKIt7Royw tools/ioemu/include/osdep.h
+41e2ff6bPJNSITgePniKtvlujrmcLA tools/ioemu/include/pc_system.h
+41e2ff6bmHZyZrzF7iHpD212GeAT-w tools/ioemu/include/plugin.h
+41e2ff6bHgstm2ZhCIdsag_c3_dVjA tools/ioemu/include/state_file.h
+41e2ff6bJjm8-4K6Cu2k6zoanQ8Yyg tools/ioemu/iodev/Makefile
+41e2ff6bKj9bQ4ELP2msSYoT7XrxHQ tools/ioemu/iodev/aspi-win32.h
+41e2ff6b95DLt3iA-okw7D4NJcaDCg tools/ioemu/iodev/biosdev.cc
+41e2ff6b1ra22hFnE6Tm9lxVaH4Mjw tools/ioemu/iodev/biosdev.h
+41e2ff6bftET40KQA19RAisCxyDHVQ tools/ioemu/iodev/cdrom.cc
+41e2ff6buuSLUZPj9EtlGA3tufslNQ tools/ioemu/iodev/cdrom.h
+41e2ff6bvD6jE2JHKP0wd7I_mB7MJg tools/ioemu/iodev/cdrom_beos.h
+41e2ff6b99qviTPyKLjy0-D5DIqACw tools/ioemu/iodev/cmos.cc
+41e2ff6bpeZbWqQfuwM_Xj-kElElAA tools/ioemu/iodev/cmos.h
+41e2ff6bRf7QN_i1c7BAzkQha8AFUg tools/ioemu/iodev/cpu.cc
+41e2ff6byVHp6G3fxAlly1u1sx_DEg tools/ioemu/iodev/crc32.cc
+41e2ff6bHWz28hOKgLKRizX9UjsyOQ tools/ioemu/iodev/crc32.h
+41e2ff6b3tvq7uKSC9DWkOswq0Re8w tools/ioemu/iodev/devices.cc
+41e2ff6bO-SYXzx1RB-1If_FNkyjLg tools/ioemu/iodev/dma.cc
+41e2ff6bdI7Ri1mVb1MzkvBKlNSx6Q tools/ioemu/iodev/dma.h
+41e2ff6bfnGRrb25sneyvOXxSi8pLg tools/ioemu/iodev/eth.cc
+41e2ff6bteOXqvNO1FIR5iFHUwqUuA tools/ioemu/iodev/eth.h
+41e2ff6bTQxXrfWSsDCISUAdzlAe9w tools/ioemu/iodev/eth_arpback.cc
+41e2ff6brorlh9N9Myd1_g7ktKcIfQ tools/ioemu/iodev/eth_fbsd.cc
+41e2ff6b5xRFy8_OISEtd2UrHEUdfw tools/ioemu/iodev/eth_linux.cc
+41e2ff6biySiByowEn40XP_yx_lxKg tools/ioemu/iodev/eth_null.cc
+41e2ff6bFAVD0UO_ob40usJOnEPAZg tools/ioemu/iodev/eth_packetmaker.cc
+41e2ff6bsR-mjksFNRC9HiDDVUfI2w tools/ioemu/iodev/eth_packetmaker.h
+41e2ff6bMnzZ7cpqVPQY0_0smpqjHw tools/ioemu/iodev/eth_tap.cc
+41e2ff6bGa18jj0cqoOAqBPDzk2Aog tools/ioemu/iodev/eth_tuntap.cc
+41e2ff6bY1u244mkTGfttym3HoLo5Q tools/ioemu/iodev/extfpuirq.cc
+41e2ff6b_wh3dgYBx38KIJ00Qv4XUA tools/ioemu/iodev/extfpuirq.h
+41e2ff6b3uiKo02slxJn11bvZKsF3g tools/ioemu/iodev/floppy.cc
+41e2ff6bKba0nlJHGy2kWUr_3e_nvw tools/ioemu/iodev/floppy.h
+41e2ff6bC1KaCAEBYYTkJJ5_pBydkQ tools/ioemu/iodev/gameport.cc
+41e2ff6bePGww4K0p8vTLphdE_zdig tools/ioemu/iodev/gameport.h
+41e2ff6biLQpMiiiKokz7qUXpBn5cg tools/ioemu/iodev/guest2host.h
+41e2ff6bji1Iix0CzQTeh9yB-Ao14Q tools/ioemu/iodev/harddrv.cc
+41e2ff6bcSDALK1SdvKvTCxemzpWwQ tools/ioemu/iodev/harddrv.h
+41e2ff6b36hFBfV06tX0a5CRjFpuxA tools/ioemu/iodev/ioapic.cc
+41e2ff6brajF6a0a7RkLHiX0M9oH7w tools/ioemu/iodev/ioapic.h
+41e2ff6btDX2IfOnC_LkP08ZlKxjJw tools/ioemu/iodev/iodebug.cc
+41e2ff6b-__Z4ECo9pHWVM-Rz-0ehw tools/ioemu/iodev/iodebug.h
+41e2ff6btRbGfsUt5k4MClieCZ-EBQ tools/ioemu/iodev/iodev.h
+41e2ff6bH5C9aG3f2QhoD6zCdShJYQ tools/ioemu/iodev/keyboard.cc
+41e2ff6bUOmeloSf5s9Gkdffo1bEyA tools/ioemu/iodev/keyboard.h
+41e2ff6b55oybF1yhInYSZX2bxiJSw tools/ioemu/iodev/load32bitOShack.cc
+41e2ff6b5WcmfYXaREzUm0KQu7pKCQ tools/ioemu/iodev/logio.cc
+41e2ff6bqqHfrDtizlRKA-_oPRbGAw tools/ioemu/iodev/main.cc
+41e2ff6cWAAGa6Pt6eE4URbCOq8wQA tools/ioemu/iodev/ne2k.cc
+41e2ff6cap6qrVL42AgTpxjav0QMQg tools/ioemu/iodev/ne2k.h
+41e2ff6cHH0UoJW74RKZFnPBSt1jUw tools/ioemu/iodev/osdep.cc
+41e2ff6ckuFNtxuAQDMVwJtYwL2QCg tools/ioemu/iodev/parallel.cc
+41e2ff6cbqWnJwLAQ9NDZJwUyGiIww tools/ioemu/iodev/parallel.h
+41e2ff6cAdkxmfzVhbQn9Plq3X4S_w tools/ioemu/iodev/pc_system.cc
+41e2ff6csu1e9S_rywWOq9B85IaZzA tools/ioemu/iodev/pci.cc
+41e2ff6cjcmNZLD17naGuKj_Qon6Ow tools/ioemu/iodev/pci.h
+41e2ff6c91zYiAb9XulXkl2vLERo-w tools/ioemu/iodev/pci2isa.cc
+41e2ff6cV7IdLNbFXwlWvdcOz4F1Aw tools/ioemu/iodev/pci2isa.h
+41e2ff6cviwF37ZllnYtHA3MEHRMWw tools/ioemu/iodev/pciusb.cc
+41e2ff6ceFmfyqr1MgYhEoRM1s6icQ tools/ioemu/iodev/pciusb.h
+41e2ff6cd-1VHyISVo789tv3ImNgLw tools/ioemu/iodev/pcivga.cc
+41e2ff6cVkXDlrNUTdt7D6BULEp1Tg tools/ioemu/iodev/pcivga.h
+41e2ff6c3xjAFB8X5OLFz_8Of62v2Q tools/ioemu/iodev/pic.cc
+41e2ff6c4UHzse5_N0Mx6u5dqKrVkw tools/ioemu/iodev/pic.h
+41e2ff6cdD9yovRmQNNJu8QVtZg7Iw tools/ioemu/iodev/pit.cc
+41e2ff6cXtvewmYJyoxrWGic2sOayg tools/ioemu/iodev/pit.h
+41e2ff6cXaqNRxMagdpNiT1kTWJJUA tools/ioemu/iodev/pit82c54.cc
+41e2ff6cHAkpKzMwyz3diMZWTswxmg tools/ioemu/iodev/pit82c54.h
+41e2ff6cMK9E2gjqHoWV9ZQfz-cP1Q tools/ioemu/iodev/pit_wrap.cc
+41e2ff6cbie7fPpQMgBImJ885GAPdw tools/ioemu/iodev/pit_wrap.h
+41e2ff6c0wLrWtBHxxboIzHsrZzkRA tools/ioemu/iodev/plugin.cc
+41e2ff6cN4Z6pnguPQaqiCkWp42MOQ tools/ioemu/iodev/scancodes.cc
+41e2ff6chK1sqb78l1sqhF3fJhjzBw tools/ioemu/iodev/scancodes.h
+41e2ff6cIyPvY7hNE5rP_PMZELhyVw tools/ioemu/iodev/scsi_commands.h
+41e2ff6cF3wH8A_66_yG92Wk7I2IWQ tools/ioemu/iodev/scsidefs.h
+41e2ff6cbAin6eD3Gfz2CozOS4_bwA tools/ioemu/iodev/scsipt.h
+41e2ff6cce6mNXZPGmlQ1bg_I0ef8Q tools/ioemu/iodev/serial.cc
+41e2ff6cxsITO-ikpd4vBYZUYO3qSw tools/ioemu/iodev/serial.h
+41e2ff6cbaCEgMJ92UELiRE2wEYe3g tools/ioemu/iodev/serial_raw.h
+41e2ff6cwDKTU8OukKNBNMDiAYUWvQ tools/ioemu/iodev/slowdown_timer.cc
+41e2ff6cM5XYdcgL417IBOzW-QipFg tools/ioemu/iodev/slowdown_timer.h
+41e2ff6c5X0WxdBPUyZlNmW6Zv_LRQ tools/ioemu/iodev/soundlnx.cc
+41e2ff6cIuE1VxGF_L6rdBtD6rZ_aA tools/ioemu/iodev/soundlnx.h
+41e2ff6cDIv87LKamP0Y-yjrdqALzQ tools/ioemu/iodev/soundwin.cc
+41e2ff6cB55j_uYIqYh-UiLS4wlm_g tools/ioemu/iodev/soundwin.h
+41e2ff6dRPBmtxjFbEM5WYuilnSSZg tools/ioemu/iodev/state_file.cc
+41e2ff6dMwkI1Dpa-UHSEzHCvjpOyw tools/ioemu/iodev/unmapped.cc
+41e2ff6d_yJMFHYPENtVmJz6wyldQA tools/ioemu/iodev/unmapped.h
+41e2ff6dU5hJI6Kn70mFingJo4cHUw tools/ioemu/iodev/vga.cc
+41e2ff6dh8xDcCXkZzpSqnFP-OXggw tools/ioemu/iodev/vga.h
+41e2ff6dayXwb5dxf0K5pd3q4QppRA tools/ioemu/iodev/virt_timer.cc
+41e2ff6dI_rNgBwki594UAWN337-zw tools/ioemu/iodev/virt_timer.h
+41e2ff6dCCtE_btrlEopLaCsLO3JDA tools/ioemu/memory/Makefile
+41e2ff6dZtwsTW8s-Gqv7bqObdvaXw tools/ioemu/memory/memory.cc
+41e2ff6dpk6EFzlHlsAsFEFdyG4wrA tools/ioemu/memory/memory.h
+41e2ff6d2i-wqgCe4iAXdckUc1GD-A tools/ioemu/memory/misc_mem.cc
+41e2ff6dCYuZgf6pxRmphkh5yeuA9Q tools/ioemu/mk/helix.mk
3fbba6dbDfYvJSsw9500b4SZyUhxjQ tools/libxc/Makefile
+41dde8afKYRKxS4XtLv1KUegGQy_bg tools/libxc/linux_boot_params.h
41cc934abX-QLXJXW_clV_wRjM0zYg tools/libxc/plan9a.out.h
3fbba6dc1uU7U3IFeF6A-XEOYF2MkQ tools/libxc/rpm.spec
3fbba6dcrNxtygEcgJYAJJ1gCQqfsA tools/libxc/xc.h
@@ -343,6 +528,7 @@
3fbba6dctWRWlFJkYb6hdix2X4WMuw tools/libxc/xc_private.c
3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/libxc/xc_private.h
40589968UQFnJeOMn8UIFLbXBuwXjw tools/libxc/xc_rrobin.c
+41dde8b0pLfAKMs_L9Uri2hnzHiCRQ tools/libxc/xc_vmx_build.c
40e1b09dMYB4ItGCqcMIzirdMd9I-w tools/libxutil/Makefile
40e033325Sjqs-_4TuzeUEprP_gYFg tools/libxutil/allocate.c
40e03332KYz7o1bn2MG_KPbBlyoIMA tools/libxutil/allocate.h
@@ -469,6 +655,7 @@
40dfd40aGqGkiopOOgJxSF4iCbHM0Q tools/python/xen/util/__init__.py
4055ee4dwy4l0MghZosxoiu6zmhc9Q tools/python/xen/util/console_client.py
40c9c468IienauFHQ_xJIcqnPJ8giQ tools/python/xen/util/ip.py
+41dde8b0yuJX-S79w4xJKxBQ-Mhp1A tools/python/xen/util/memmap.py
4059c6a0pnxhG8hwSOivXybbGOwuXw tools/python/xen/util/tempfile.py
40c9c468SNuObE_YWARyS0hzTPSzKg tools/python/xen/xend/Args.py
41597996WNvJA-DVCBmc0xU9w_XmoA tools/python/xen/xend/Blkctl.py
@@ -506,6 +693,7 @@
40c9c4694eu5759Dehr4Uhakei0EMg tools/python/xen/xend/server/SrvNode.py
40c9c469TaZ83ypsrktmPSHLEZiP5w tools/python/xen/xend/server/SrvRoot.py
40c9c469W3sgDMbBJYQdz5wbQweL0Q tools/python/xen/xend/server/SrvServer.py
+41ee5e8cFlODpYxhBMZqo9ZgGtcHbg tools/python/xen/xend/server/SrvUsbif.py
40c9c469aq7oXrE1Ngqf3_lBqL0RoQ tools/python/xen/xend/server/SrvVnetDir.py
4108f181GtRoD1U9TBuJXMfBbGJwdQ tools/python/xen/xend/server/SrvXendLog.py
40c9c469Y_aimoOFfUZoS-4eV8gEKg tools/python/xen/xend/server/__init__.py
@@ -517,6 +705,7 @@
40c9c469yrm31i60pGKslTi2Zgpotg tools/python/xen/xend/server/messages.py
40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/python/xen/xend/server/netif.py
40c9c469ZqILEQ8x6yWy0_51jopiCg tools/python/xen/xend/server/params.py
+41ee5e8dq9NtihbL4nWKjuSLOhXPUg tools/python/xen/xend/server/usbif.py
40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py
4189125cL90jKSOcBJ3Vx4nWGiXXvA tools/python/xen/xend/util.py
40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py
@@ -618,6 +807,15 @@
4194e8612TrrMvC8ZlA4h2ZYCPWz4g tools/x2d2/minixend.c
4194e861x2eqNCD61RYPCUEBVdMYuw tools/x2d2/minixend.h
4194e861A4V9VbD_FYmgXpYEj5YwVg tools/x2d2/util.c
+41d58ba63w1WfBmd6Cr_18nhLNv7PA tools/xcs/Makefile
+41d58ba6NxgkfzD_rmsGjgd_zJ3H_w tools/xcs/bindings.c
+41d58ba6I2umi60mShq4Pl0RDg7lzQ tools/xcs/connection.c
+41d58ba6YyYu53bFuoIAw9hNNmneEg tools/xcs/ctrl_interface.c
+41d58ba6Ru9ZbhTjgYX_oiszSIwCww tools/xcs/evtchn.c
+41d58ba6x9KO1CQBT7kKOKq_pJYC3g tools/xcs/xcs.c
+41d58ba6R6foSMtSFEcu-yxWFrT8VQ tools/xcs/xcs.h
+41d58ba6qyr2BkTcH2WlNBYLRyl2Yw tools/xcs/xcs_proto.h
+41d58ba6ijEF6fedqRO5vFu7uCirZg tools/xcs/xcsdump.c
403a3edbrr8RE34gkbR40zep98SXbg tools/xentrace/Makefile
40a107afN60pFdURgBv9KwEzgRl5mQ tools/xentrace/formats
4050c413PhhLNAYk3TEwP37i_iLw9Q tools/xentrace/xentrace.8
@@ -684,8 +882,6 @@
3ddb79bcZ_2FxINljqNSkqa17ISyJw xen/arch/x86/pci-pc.c
3ddb79bdeJ7_86z03yTAPIeeywOg3Q xen/arch/x86/pci-x86.c
3ddb79bdIKgipvGoqExEQ7jawfVowA xen/arch/x86/pci-x86.h
-40a4dfced2dnSzbKgJFlD3chKHexjQ xen/arch/x86/pdb-linux.c
-4022a73czgX7d-2zfF_cb33oVemApQ xen/arch/x86/pdb-stub.c
3ddb79bc7KxGCEJsgBnkDX7XjD_ZEQ xen/arch/x86/rwlock.c
3ddb79bcrD6Z_rUvSDgrvjyb4846Eg xen/arch/x86/setup.c
405b8599xI_PoEr3zZoJ2on-jdn7iw xen/arch/x86/shadow.c
@@ -694,22 +890,28 @@
3ddb79bc-Udq7ol-NX4q9XsYnN7A2Q xen/arch/x86/time.c
3ddb79bccYVzXZJyVaxuv5T42Z1Fsw xen/arch/x86/trampoline.S
3ddb79bcOftONV9h4QCxXOfiT0h91w xen/arch/x86/traps.c
+41c0c411tD3C7TpfDMiFTf7BaNd_Dg xen/arch/x86/vmx.c
+41c0c411ODt8uEmV-yUxpQLpqimE5Q xen/arch/x86/vmx_io.c
+41f97ef5139vN42cOYHfX_Ac8WOOjA xen/arch/x86/vmx_platform.c
+41c0c4128URE0dxcO15JME_MuKBPfg xen/arch/x86/vmx_vmcs.c
419cbedeQDg8IrO3izo3o5rQNlo0kQ xen/arch/x86/x86_32/asm-offsets.c
+4202391dkvdTZ8GhWXe3Gqf9EOgWXg xen/arch/x86/x86_32/domain_build.c
3e32af9aRnYGl4GMOaDKp7JdfhOGhg xen/arch/x86/x86_32/domain_page.c
3ddb79bcecupHj56ZbTa3B0FxDowMg xen/arch/x86/x86_32/entry.S
3ddb79bcHwuCQDjBICDTSis52hWguw xen/arch/x86/x86_32/mm.c
40f92331jfOlE7MfKwpdkEb1CEf23g xen/arch/x86/x86_32/seg_fixup.c
+42000d3ckiFc1qxa4AWqsd0t3lxuyw xen/arch/x86/x86_32/traps.c
3ddb79bc4nTpGQOe6_-MbyZzkhlhFQ xen/arch/x86/x86_32/usercopy.c
3ddb79bcOMCu9-5mKpjIh5d0qqBDPg xen/arch/x86/x86_32/xen.lds
41bf1717Ty3hwN3E9swdu8QfnvGqww xen/arch/x86/x86_64/asm-offsets.c
+4202391dA91ZovYX9d_5zJi9yGvLoQ xen/arch/x86/x86_64/domain_build.c
40e96d3aLDI-nViMuYneD7VKYlZrVg xen/arch/x86/x86_64/entry.S
41bf1717XhPz_dNT5OKSjgmbFuWBuA xen/arch/x86/x86_64/mm.c
+42000d3cMb8o1WuFBXC07c8i3lPZBw xen/arch/x86/x86_64/traps.c
40e96d3ahBTZqbTViInnq0lM03vs7A xen/arch/x86/x86_64/usercopy.c
40e96d3akN3Hu_J5Bk-WXD8OGscrYQ xen/arch/x86/x86_64/xen.lds
3ddb79bdff-gj-jFGKjOejeHLqL8Lg xen/common/Makefile
3e397e66AyyD5fYraAySWuwi9uqSXg xen/common/ac_timer.c
-4022a73c_BbDFd2YJ_NQYVvKX5Oz7w xen/common/debug-linux.c
-3fa152581E5KhrAtqZef2Sr5NKTz4w xen/common/debug.c
3ddb79bdLX_P6iB7ILiblRLWvebapg xen/common/dom0_ops.c
3e6377e4i0c9GtKN65e99OtRbw3AZw xen/common/dom_mem_ops.c
3ddb79bdYO5D8Av12NHqPeSviav7cg xen/common/domain.c
@@ -728,11 +930,11 @@
40589968dD2D1aejwSOvrROg7fOvGQ xen/common/sched_bvt.c
40589968be_t_n0-w6ggceW7h-sx0w xen/common/sched_rrobin.c
3e397e6619PgAfBbw2XFbXkewvUWgw xen/common/schedule.c
-3ddb79bdB9RNMnkQnUyZ5C9hhMSQQw xen/common/slab.c
3ddb79bd0gVQYmL2zvuJnldvD0AGxQ xen/common/softirq.c
3e7f358awXBC3Vw-wFRwPw18qL1khg xen/common/string.c
403a3edbejm33XLTGMuinKEwQBrOIg xen/common/trace.c
3ddb79bd3zgV33PHdt-cgh3sxcb1hw xen/common/vsprintf.c
+4203fb92Qcy7mGpauBdq09J-WAqfoA xen/common/xmalloc.c
3ddb79c0ppNeJtjC4va8j41ADCnchA xen/drivers/Makefile
40715b2bi9gU43-cYzlmPDgreYQchw xen/drivers/acpi/Makefile
40715b2bDxNCz5LFV8FAXihmYJZFUQ xen/drivers/acpi/acpi_ksyms.c
@@ -797,12 +999,14 @@
3ddb79c3r9-31dIsewPV3P3i8HALsQ xen/include/asm-x86/delay.h
3ddb79c34BFiXjBJ_cCKB0aCsV1IDw xen/include/asm-x86/desc.h
40715b2dTokMLYGSuD58BnxOqyWVew xen/include/asm-x86/div64.h
-3e20b82fl1jmQiKdLy7fxMcutfpjWA xen/include/asm-x86/domain_page.h
+4204e7acwzqgXyTAPKa1nM-L7Ec0Qw xen/include/asm-x86/domain.h
+41febc4bBKTKHhnAu_KPYwgNkHjFlg xen/include/asm-x86/domain_page.h
41d3eaaeIBzW621S1oa0c2yk7X43qQ xen/include/asm-x86/e820.h
3ddb79c3NU8Zy40OTrq3D-i30Y3t4A xen/include/asm-x86/fixmap.h
3e2d29944GI24gf7vOP_7x8EyuqxeA xen/include/asm-x86/flushtlb.h
3ddb79c39o75zPP0T1aQQ4mNrCAN2w xen/include/asm-x86/hardirq.h
3ddb79c3TMDjkxVndKFKnGiwY0HzDg xen/include/asm-x86/i387.h
+4204e7acwXDo-5iAAiO2eQbtDeYZXA xen/include/asm-x86/init.h
3ddb79c3fQ_O3o5NHK2N8AJdk0Ea4Q xen/include/asm-x86/io.h
3ddb79c2TKeScYHQZreTdHqYNLbehQ xen/include/asm-x86/io_apic.h
3ddb79c2L7rTlFzazOLW1XuSZefpFw xen/include/asm-x86/irq.h
@@ -815,8 +1019,6 @@
41a61536MFhNalgbVmYGXAhQsPTZNw xen/include/asm-x86/multicall.h
3ddb79c3xjYnrv5t3VqYlR4tNEOl4Q xen/include/asm-x86/page.h
3ddb79c3ysKUbxZuwKBRK3WXU2TlEg xen/include/asm-x86/pci.h
-404f1bb41Yl-5ZjIWnG66HDCj6OIWA xen/include/asm-x86/pda.h
-4022a73diKn2Ax4-R4gzk59lm1YdDg xen/include/asm-x86/pdb.h
3ddb79c2QF5-pZGzuX4QukPCDAl59A xen/include/asm-x86/processor.h
40cf1596bim9F9DNdV75klgRSZ6Y2A xen/include/asm-x86/regs.h
3ddb79c2plf7ciNgoNjU-RsbUzawsw xen/include/asm-x86/rwlock.h
@@ -826,16 +1028,22 @@
3ddb79c3NiyQE2vQnyGiaBnNjBO1rA xen/include/asm-x86/spinlock.h
40e1966akOHWvvunCED7x3HPv35QvQ xen/include/asm-x86/string.h
3ddb79c3ezddh34MdelJpa5tNR00Dw xen/include/asm-x86/system.h
+42033fc1Bb8ffTshBYFGouGkiAMoUQ xen/include/asm-x86/time.h
3ddb79c4HugMq7IYGxcQKFBpKwKhzA xen/include/asm-x86/types.h
40cf1596saFaHD5DC5zvrSn7CDCWGQ xen/include/asm-x86/uaccess.h
+41c0c412k6GHYF3cJtDdw37ee3TVaw xen/include/asm-x86/vmx.h
+41c0c412hck3QX-6_MaXaISGkngQuA xen/include/asm-x86/vmx_cpu.h
+41c0c41243jC1mcArZx_t3YkBL4lTA xen/include/asm-x86/vmx_platform.h
+41c0c412lQ0NVVN9PsOSznQ-qhOiPA xen/include/asm-x86/vmx_vmcs.h
418fbcfe_WliJPToeVM-9VStvym-hw xen/include/asm-x86/x86_32/asm_defns.h
3ddb79c2ADvRmdexd9y3AYK9_NTx-Q xen/include/asm-x86/x86_32/current.h
+3e20b82fl1jmQiKdLy7fxMcutfpjWA xen/include/asm-x86/x86_32/domain_page.h
3ddb79c3mbqEM7QQr3zVq7NiBNhouA xen/include/asm-x86/x86_32/regs.h
3e7f358aG11EvMI9VJ4_9hD4LUO7rQ xen/include/asm-x86/x86_32/string.h
3ddb79c3M2n1ROZH6xk3HbyN4CPDqg xen/include/asm-x86/x86_32/uaccess.h
41bf1717bML6GxpclTWJabiaO5W5vg xen/include/asm-x86/x86_64/asm_defns.h
404f1b9ceJeGVaPNIENm2FkK0AgEOQ xen/include/asm-x86/x86_64/current.h
-404f1b9fl6AQ_a-T1TDK3fuwTPXmHw xen/include/asm-x86/x86_64/desc.h
+41febc4b1aCGLsm0Y0b_82h7lFtrEA xen/include/asm-x86/x86_64/domain_page.h
404f1badfXZJZ2sU8sh9PS2EZvd19Q xen/include/asm-x86/x86_64/ldt.h
404f1bb86rAXB3aLS1vYdcqpJiEcyg xen/include/asm-x86/x86_64/regs.h
40e1966azOJZfNI6Ilthe6Q-T3Hewg xen/include/asm-x86/x86_64/string.h
@@ -848,7 +1056,10 @@
4121d149udGfSUGhn3k1ECz0bM31nQ xen/include/public/grant_table.h
40f5623bqoi4GEoBiiUc6TZk1HjsMg xen/include/public/io/blkif.h
40dc4076pVeE1kEEWzcUaNZin65kCA xen/include/public/io/domain_controller.h
+41c0c412FLc0gunlJl91qMYscFtXVA xen/include/public/io/ioreq.h
40f5623cTZ80EwjWUBlh44A9F9i_Lg xen/include/public/io/netif.h
+41d40e9b8zCk5VDqhVbuQyhc7G3lqA xen/include/public/io/ring.h
+41ee5e8c6mLxIx82KPsbpt_uts_vSA xen/include/public/io/usbif.h
4051db79512nOCGweabrFWO2M2h5ng xen/include/public/physdev.h
40589968wmhPmV5-ENbBYmMjnedgKw xen/include/public/sched_ctl.h
404f3d2eR2Owk-ZcGOx9ULGHg3nrww xen/include/public/trace.h
diff --git a/BitKeeper/etc/ignore b/BitKeeper/etc/ignore
index 0b96e34b39..46839b66ec 100644
--- a/BitKeeper/etc/ignore
+++ b/BitKeeper/etc/ignore
@@ -8,11 +8,13 @@
*.tar.bz2
*.tar.gz
*~
+BLOG
BitKeeper/*/*
PENDING/*
TAGS
Twisted-1.3.0.tar.gz
Twisted-1.3.0/*
+dist/*
docs/*.aux
docs/*.dvi
docs/*.log
@@ -43,35 +45,45 @@ docs/user/labels.pl
docs/user/user.css
docs/user/user.html
extras/mini-os/h/hypervisor-ifs
-dist/*
+install/*
linux-*-xen0/*
linux-*-xenU/*
-linux-xen-sparse
linux-*.patch
+linux-xen-sparse
+mkddbxen
netbsd-*-tools/*
netbsd-*-xen0/*
netbsd-*-xenU/*
netbsd-*.patch
+patches/ebtables-brnf-5_vs_2.4.25.diff
+patches/ebtables.diff
patches/tmp/*
pristine-*
tools/*/build/lib*/*.py
tools/balloon/balloon
tools/check/.*
+tools/ioemu/iodev/device-model
tools/libxc/xen/*
tools/misc/miniterm/miniterm
+tools/misc/xen_cpuperf
tools/misc/xenperf
tools/vnet/gc
tools/vnet/gc*/*
-tools/vnet/vnet-module/.tmp_versions/*
-tools/vnet/vnet-module/.*.cmd
tools/vnet/vnet-module/*.ko
+tools/vnet/vnet-module/.*.cmd
+tools/vnet/vnet-module/.tmp_versions/*
tools/vnet/vnet-module/vnet_module.mod.*
tools/vnetd/vnetd
tools/web-shutdown.tap
+tools/x2d2/minixend
+tools/xcs/xcs
+tools/xcs/xcsdump
tools/xentrace/xentrace
tools/xfrd/xfrd
+xen/BLOG
xen/arch/x86/asm-offsets.s
xen/arch/x86/boot/mkelf32
+xen/ddb/*
xen/drivers/pci/classlist.h
xen/drivers/pci/devlist.h
xen/drivers/pci/gen-devlist
@@ -87,8 +99,3 @@ xen/tools/figlet/figlet
xen/xen
xen/xen-syms
xen/xen.*
-install/*
-patches/ebtables-brnf-5_vs_2.4.25.diff
-patches/ebtables.diff
-tools/x2d2/minixend
-BLOG
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index f2a27dc63d..ccf69153cb 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -17,18 +17,23 @@ cwc22@centipede.cl.cam.ac.uk
djm@kirby.fc.hp.com
gm281@boulderdash.cl.cam.ac.uk
gm281@tetrapod.cl.cam.ac.uk
+harry@dory.(none)
iap10@freefall.cl.cam.ac.uk
iap10@labyrinth.cl.cam.ac.uk
iap10@nidd.cl.cam.ac.uk
+iap10@pb001.cl.cam.ac.uk
iap10@pb007.cl.cam.ac.uk
iap10@striker.cl.cam.ac.uk
iap10@tetris.cl.cam.ac.uk
jws22@gauntlet.cl.cam.ac.uk
jws@cairnwell.research
kaf24@camelot.eng.3leafnetworks.com
+kaf24@firebug.cl.cam.ac.uk
kaf24@freefall.cl.cam.ac.uk
kaf24@labyrinth.cl.cam.ac.uk
+kaf24@pb001.cl.cam.ac.uk
kaf24@penguin.local
+kaf24@planb.cl.cam.ac.uk
kaf24@plym.cl.cam.ac.uk
kaf24@scramble.cl.cam.ac.uk
kaf24@striker.cl.cam.ac.uk
diff --git a/docs/misc/VMX_changes.txt b/docs/misc/VMX_changes.txt
new file mode 100644
index 0000000000..739d315e79
--- /dev/null
+++ b/docs/misc/VMX_changes.txt
@@ -0,0 +1,90 @@
+Changes to Xen in support of Intel(R) Vanderpool Technology
+-------------------------------------------------------------
+
+Our VT extensions to the Xen hypervisor provide full platform
+virtualization, including CPU(s), memory, and I/O infrastructure. The
+generic code in Xen handles and schedules those virtual machines as it
+does for the existing para-virtualized domains.
+
+Full virtualization required by the OS guests requires full device
+virtualization as well. The device models in BOCHS
+(http://bochs.sourceforge.net/) were decoupled from the CPU
+virtualization, and are used to virtualize the legacy devices (such as
+keyboard, mouse, VGA, IDE) in the PC platform. At this point, the
+device models run in user mode on domain 0, not in the Xen hypervisor.
+
+We would like to thank Ian Pratt and Keir Fraser for reviewing our
+design and code intensively, and for providing numerous useful
+suggestions to improve the architecture and code.
+
+We have a list of Intel team members who take credit for making this
+release happen: Yunhong Jiang, Nitin Kamble, Chengyuan Li, Xin Li,
+Xiaofeng Ling, Benjamin Liu, Asit Mallick, Jun Nakajima, Sunil Saxena,
+Arun Sharma, Edwin Zhai, Jeff Zheng, and Louis Zhuang. We'll continue
+to add more features to complete full virtualization in Xen using VT.
+
+The notes document the changes to the Xen hypervisor in order to add
+VT support. The changes to other areas, such as Control Panel will be
+added as we deliver the code.
+
+Summary of changes for the first release
+----------------------------------------
+December 15, 2004
+
+ * VT specific event handling and domain management were added.
+
+ * Shadow mode was extended to support full 32-bit guests
+
+ * Domain switching code was extended to support VT domain
+
+ * I/O request handling was added to communicate with the device model
+
+ * Domain builder was extended to provide the environment when the
+ guest enters the protected mode, including E820 memory and VGA
+ info, typically obtained by BIOS calls.
+
+New code:
+---------
+ VT (Vanderpool Technology) is based on the new VMX (Virtual
+ Machine Extensions) architecture. The current release of the
+ software supports 32-bit only.
+
+ * arch/x86/vmx.[ch] and arch/x86/vmx_*.[ch]: created to handle
+ VMX-specific events in order to provide virtual machine.
+
+ * arch/x86/x86_32/entry.S: new code path was added to have the
+ first-level handler from VM exits. The first-level handler calls
+ the second-level handler in arch/x86/vmx.c.
+
+ * arch/x86/setup.c: new function start_vmx() to init_intel() to
+ enable VMX mode.
+
+ * include/asm-x86/config.h: #ifdef CONFIG_VMX was added.
+
+ * arch/x86/domain.c: new code patch was added to create a VMX
+ domain given the flag from the control panel.
+
+ * include/public/io/ioreq.h: A new data structure was added to
+ define the I/O requests between the Xen hypervisor and the
+ device models.
+
+Changes to the existing code:
+-----------------------------
+
+ * arch/x86/shadow.[ch]: new mode SHM_full_32 was added to support
+ full virtualization. The current Xen code assumes that the guest
+ page directory and tables have _machine_ (or host) physical page
+ frame numbers, and the new code allows to support _guest_
+ physical page frame numbers
+
+ * include/asm-x86/processor.h: struct arch_vmx_struct arch_vmx has
+ been added to the thread_struct data structure. The arch_vmx has
+ the addtional VMX-related CPU context.
+
+ * arch/x86/io_apic.c: reverse mapping between vector and irq has
+ been added. We will revisit this code when considering MSI
+ support.
+
+--- Jun
+
+
diff --git a/linux-2.4.29-xen-sparse/arch/xen/Makefile b/linux-2.4.29-xen-sparse/arch/xen/Makefile
index 0f1d0580da..ac4933244d 100644
--- a/linux-2.4.29-xen-sparse/arch/xen/Makefile
+++ b/linux-2.4.29-xen-sparse/arch/xen/Makefile
@@ -61,6 +61,7 @@ SUBDIRS += arch/xen/drivers/console
SUBDIRS += arch/xen/drivers/evtchn
SUBDIRS += arch/xen/drivers/blkif
SUBDIRS += arch/xen/drivers/netif
+SUBDIRS += arch/xen/drivers/usbif
SUBDIRS += arch/xen/drivers/balloon
ifdef CONFIG_XEN_PRIVILEGED_GUEST
SUBDIRS += arch/xen/drivers/dom0
@@ -71,6 +72,7 @@ CORE_FILES += arch/xen/drivers/evtchn/drv.o
CORE_FILES += arch/xen/drivers/console/drv.o
DRIVERS += arch/xen/drivers/blkif/drv.o
DRIVERS += arch/xen/drivers/netif/drv.o
+DRIVERS += arch/xen/drivers/usbif/drv.o
ifdef CONFIG_XEN_PRIVILEGED_GUEST
CORE_FILES += arch/xen/drivers/dom0/drv.o
endif
diff --git a/linux-2.4.29-xen-sparse/arch/xen/config.in b/linux-2.4.29-xen-sparse/arch/xen/config.in
index b69fbf5930..d1913f089e 100644
--- a/linux-2.4.29-xen-sparse/arch/xen/config.in
+++ b/linux-2.4.29-xen-sparse/arch/xen/config.in
@@ -16,14 +16,18 @@ mainmenu_option next_comment
comment 'Xen'
bool 'Support for privileged operations (domain 0)' CONFIG_XEN_PRIVILEGED_GUEST
bool 'Device-driver domain (physical device access)' CONFIG_XEN_PHYSDEV_ACCESS
+if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" ]; then
+ bool 'USB-device backend driver' CONFIG_XEN_USB_BACKEND
+fi
bool 'Scrub memory before freeing it to Xen' CONFIG_XEN_SCRUB_PAGES
bool 'Network-device frontend driver' CONFIG_XEN_NETDEV_FRONTEND
bool 'Block-device frontend driver' CONFIG_XEN_BLKDEV_FRONTEND
+bool 'USB-device frontend driver' CONFIG_XEN_USB_FRONTEND
endmenu
# The IBM S/390 patch needs this.
define_bool CONFIG_NO_IDLE_HZ y
-if [ "$CONFIG_XEN_PHYSDEV_ACCESS" == "y" ]; then
+if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" ]; then
define_bool CONFIG_FOREIGN_PAGES y
else
define_bool CONFIG_FOREIGN_PAGES n
@@ -262,7 +266,7 @@ fi
source drivers/char/Config.in
-if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" ]; then
+if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" -o "$CONFIG_XEN_USB_FRONTEND" = "y" ]; then
source drivers/media/Config.in
fi
@@ -295,9 +299,16 @@ if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" ]; then
source drivers/sound/Config.in
fi
endmenu
+fi
+if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" -o "$CONFIG_XEN_USB_FRONTEND" = "y" ]; then
+ if [ "$CONFIG_XEN_USB_FRONTEND" = "y" -o "$CONFIG_XEN_USB_BACKEND" = "y" ]; then
+ define_bool CONFIG_USB y
+ fi
source drivers/usb/Config.in
+fi
+if [ "$CONFIG_XEN_PHYSDEV_ACCESS" = "y" ]; then
source net/bluetooth/Config.in
fi
diff --git a/linux-2.4.29-xen-sparse/arch/xen/defconfig-xen0 b/linux-2.4.29-xen-sparse/arch/xen/defconfig-xen0
index 4769ac7822..2864c85cea 100644
--- a/linux-2.4.29-xen-sparse/arch/xen/defconfig-xen0
+++ b/linux-2.4.29-xen-sparse/arch/xen/defconfig-xen0
@@ -12,9 +12,11 @@ CONFIG_UID16=y
#
CONFIG_XEN_PRIVILEGED_GUEST=y
CONFIG_XEN_PHYSDEV_ACCESS=y
+# CONFIG_XEN_USB_BACKEND is not set
CONFIG_XEN_SCRUB_PAGES=y
CONFIG_XEN_NETDEV_FRONTEND=y
CONFIG_XEN_BLKDEV_FRONTEND=y
+# CONFIG_XEN_USB_FRONTEND is not set
CONFIG_NO_IDLE_HZ=y
CONFIG_FOREIGN_PAGES=y
diff --git a/linux-2.4.29-xen-sparse/arch/xen/defconfig-xenU b/linux-2.4.29-xen-sparse/arch/xen/defconfig-xenU
index 6527523b71..886199d7d3 100644
--- a/linux-2.4.29-xen-sparse/arch/xen/defconfig-xenU
+++ b/linux-2.4.29-xen-sparse/arch/xen/defconfig-xenU
@@ -15,6 +15,7 @@ CONFIG_UID16=y
CONFIG_XEN_SCRUB_PAGES=y
CONFIG_XEN_NETDEV_FRONTEND=y
CONFIG_XEN_BLKDEV_FRONTEND=y
+# CONFIG_XEN_USB_FRONTEND is not set
CONFIG_NO_IDLE_HZ=y
# CONFIG_FOREIGN_PAGES is not set
CONFIG_NETDEVICES=y
diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/Makefile b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/Makefile
new file mode 100644
index 0000000000..1b3eb41a24
--- /dev/null
+++ b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/Makefile
@@ -0,0 +1,10 @@
+
+O_TARGET := drv.o
+
+subdir-$(CONFIG_XEN_USB_FRONTEND) += frontend
+obj-$(CONFIG_XEN_USB_FRONTEND) += frontend/drv.o
+
+subdir-$(CONFIG_XEN_USB_BACKEND) += backend
+obj-$(CONFIG_XEN_USB_BACKEND) += backend/drv.o
+
+include $(TOPDIR)/Rules.make
diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/Makefile b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/Makefile
new file mode 100644
index 0000000000..b5226dd039
--- /dev/null
+++ b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/backend/Makefile
@@ -0,0 +1,3 @@
+O_TARGET := drv.o
+obj-y := main.o interface.o control.o # vrh.o don't think I need this!
+include $(TOPDIR)/Rules.make
diff --git a/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile
new file mode 100644
index 0000000000..032d02d7cc
--- /dev/null
+++ b/linux-2.4.29-xen-sparse/arch/xen/drivers/usbif/frontend/Makefile
@@ -0,0 +1,3 @@
+O_TARGET := drv.o
+obj-y := main.o
+include $(TOPDIR)/Rules.make
diff --git a/linux-2.4.29-xen-sparse/arch/xen/kernel/setup.c b/linux-2.4.29-xen-sparse/arch/xen/kernel/setup.c
index 3b27174ba6..f08f3a4369 100644
--- a/linux-2.4.29-xen-sparse/arch/xen/kernel/setup.c
+++ b/linux-2.4.29-xen-sparse/arch/xen/kernel/setup.c
@@ -62,8 +62,8 @@ shared_info_t *HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
unsigned long *phys_to_machine_mapping, *pfn_to_mfn_frame_list;
-multicall_entry_t multicall_list[8];
-int nr_multicall_ents = 0;
+DEFINE_PER_CPU(multicall_entry_t, multicall_list[8]);
+DEFINE_PER_CPU(int, nr_multicall_ents);
/*
* Machine setup..
diff --git a/linux-2.4.29-xen-sparse/arch/xen/mm/fault.c b/linux-2.4.29-xen-sparse/arch/xen/mm/fault.c
index 76d95ff03a..d19218fe32 100644
--- a/linux-2.4.29-xen-sparse/arch/xen/mm/fault.c
+++ b/linux-2.4.29-xen-sparse/arch/xen/mm/fault.c
@@ -84,8 +84,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs,
error_code &= 3;
error_code |= (regs->xcs & 2) << 1;
- if ( flush_page_update_queue() != 0 )
- return;
+ /* ensure all updates have completed */
+ flush_page_update_queue();
/*
* We fault-in kernel-space virtual memory on-demand. The
diff --git a/linux-2.4.29-xen-sparse/drivers/usb/hcd.c b/linux-2.4.29-xen-sparse/drivers/usb/hcd.c
new file mode 100644
index 0000000000..bc184e896d
--- /dev/null
+++ b/linux-2.4.29-xen-sparse/drivers/usb/hcd.c
@@ -0,0 +1,1511 @@
+/*
+ * Copyright (c) 2001-2002 by David Brownell
+ *
+ * This program 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 program 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 program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/uts.h> /* for UTS_SYSNAME */
+
+
+#ifdef CONFIG_USB_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+
+#include <linux/usb.h>
+#include "hcd.h"
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * USB Host Controller Driver framework
+ *
+ * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing
+ * HCD-specific behaviors/bugs. Think of it as the "upper level" of
+ * some drivers, where the "lower level" is hardware-specific.
+ *
+ * This does error checks, tracks devices and urbs, and delegates to a
+ * "hc_driver" only for code (and data) that really needs to know about
+ * hardware differences. That includes root hub registers, i/o queues,
+ * and so on ... but as little else as possible.
+ *
+ * Shared code includes most of the "root hub" code (these are emulated,
+ * though each HC's hardware works differently) and PCI glue, plus request
+ * tracking overhead. The HCD code should only block on spinlocks or on
+ * hardware handshaking; blocking on software events (such as other kernel
+ * threads releasing resources, or completing actions) is all generic.
+ *
+ * Happens the USB 2.0 spec says this would be invisible inside the "USBD",
+ * and includes mostly a "HCDI" (HCD Interface) along with some APIs used
+ * only by the hub driver ... and that neither should be seen or used by
+ * usb client device drivers.
+ *
+ * Contributors of ideas or unattributed patches include: David Brownell,
+ * Roman Weissgaerber, Rory Bolt, ...
+ *
+ * HISTORY:
+ * 2002-sept Merge some 2.5 updates so we can share hardware level HCD
+ * code between the 2.4.20+ and 2.5 trees.
+ * 2002-feb merge to 2.4.19
+ * 2001-12-12 Initial patch version for Linux 2.5.1 kernel.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* host controllers we manage */
+static LIST_HEAD (hcd_list);
+
+/* used when updating list of hcds */
+static DECLARE_MUTEX (hcd_list_lock);
+
+/* used when updating hcd data */
+static spinlock_t hcd_data_lock = SPIN_LOCK_UNLOCKED;
+
+static struct usb_operations hcd_operations;
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Sharable chunks of root hub code.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+#define KERNEL_REL ((LINUX_VERSION_CODE >> 16) & 0x0ff)
+#define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff)
+
+/* usb 2.0 root hub device descriptor */
+static const u8 usb2_rh_dev_descriptor [18] = {
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x00, 0x02, /* __u16 bcdUSB; v2.0 */
+
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x01, /* __u8 bDeviceProtocol; [ usb 2.0 single TT ]*/
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+
+ 0x00, 0x00, /* __u16 idVendor; */
+ 0x00, 0x00, /* __u16 idProduct; */
+ KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */
+
+ 0x03, /* __u8 iManufacturer; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+/* no usb 2.0 root hub "device qualifier" descriptor: one speed only */
+
+/* usb 1.1 root hub device descriptor */
+static const u8 usb11_rh_dev_descriptor [18] = {
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x10, 0x01, /* __u16 bcdUSB; v1.1 */
+
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+
+ 0x00, 0x00, /* __u16 idVendor; */
+ 0x00, 0x00, /* __u16 idProduct; */
+ KERNEL_VER, KERNEL_REL, /* __u16 bcdDevice */
+
+ 0x03, /* __u8 iManufacturer; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Configuration descriptors for our root hubs */
+
+static const u8 fs_rh_config_descriptor [] = {
+
+ /* one configuration */
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, 0x00, /* __u16 wTotalLength; */
+ 0x01, /* __u8 bNumInterfaces; (1) */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered,
+ 6: Self-powered,
+ 5 Remote-wakwup,
+ 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* USB 1.1:
+ * USB 2.0, single TT organization (mandatory):
+ * one interface, protocol 0
+ *
+ * USB 2.0, multiple TT organization (optional):
+ * two interfaces, protocols 1 (like single TT)
+ * and 2 (multiple TT mode) ... config is
+ * sometimes settable
+ * NOT IMPLEMENTED
+ */
+
+ /* one interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* one endpoint (status change endpoint) */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
+ 0xff /* __u8 ep_bInterval; (255ms -- usb 2.0 spec) */
+};
+
+static const u8 hs_rh_config_descriptor [] = {
+
+ /* one configuration */
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, 0x00, /* __u16 wTotalLength; */
+ 0x01, /* __u8 bNumInterfaces; (1) */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered,
+ 6: Self-powered,
+ 5 Remote-wakwup,
+ 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* USB 1.1:
+ * USB 2.0, single TT organization (mandatory):
+ * one interface, protocol 0
+ *
+ * USB 2.0, multiple TT organization (optional):
+ * two interfaces, protocols 1 (like single TT)
+ * and 2 (multiple TT mode) ... config is
+ * sometimes settable
+ * NOT IMPLEMENTED
+ */
+
+ /* one interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; [usb1.1 or single tt] */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* one endpoint (status change endpoint) */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x02, 0x00, /* __u16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */
+ 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * helper routine for returning string descriptors in UTF-16LE
+ * input can actually be ISO-8859-1; ASCII is its 7-bit subset
+ */
+static int ascii2utf (char *s, u8 *utf, int utfmax)
+{
+ int retval;
+
+ for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) {
+ *utf++ = *s++;
+ *utf++ = 0;
+ }
+ return retval;
+}
+
+/*
+ * rh_string - provides manufacturer, product and serial strings for root hub
+ * @id: the string ID number (1: serial number, 2: product, 3: vendor)
+ * @pci_desc: PCI device descriptor for the relevant HC
+ * @type: string describing our driver
+ * @data: return packet in UTF-16 LE
+ * @len: length of the return packet
+ *
+ * Produces either a manufacturer, product or serial number string for the
+ * virtual root hub device.
+ */
+static int rh_string (
+ int id,
+ struct usb_hcd *hcd,
+ u8 *data,
+ int len
+) {
+ char buf [100];
+
+ // language ids
+ if (id == 0) {
+ *data++ = 4; *data++ = 3; /* 4 bytes string data */
+ *data++ = 0; *data++ = 0; /* some language id */
+ return 4;
+
+ // serial number
+ } else if (id == 1) {
+ strcpy (buf, hcd->bus->bus_name);
+
+ // product description
+ } else if (id == 2) {
+ strcpy (buf, hcd->product_desc);
+
+ // id 3 == vendor description
+ } else if (id == 3) {
+ sprintf (buf, "%s %s %s", UTS_SYSNAME, UTS_RELEASE,
+ hcd->description);
+
+ // unsupported IDs --> "protocol stall"
+ } else
+ return 0;
+
+ data [0] = 2 * (strlen (buf) + 1);
+ data [1] = 3; /* type == string */
+ return 2 + ascii2utf (buf, data + 2, len - 2);
+}
+
+
+/* Root hub control transfers execute synchronously */
+static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
+{
+ struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
+ u16 typeReq, wValue, wIndex, wLength;
+ const u8 *bufp = 0;
+ u8 *ubuf = urb->transfer_buffer;
+ int len = 0;
+
+ typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
+ wValue = le16_to_cpu (cmd->wValue);
+ wIndex = le16_to_cpu (cmd->wIndex);
+ wLength = le16_to_cpu (cmd->wLength);
+
+ if (wLength > urb->transfer_buffer_length)
+ goto error;
+
+ /* set up for success */
+ urb->status = 0;
+ urb->actual_length = wLength;
+ switch (typeReq) {
+
+ /* DEVICE REQUESTS */
+
+ case DeviceRequest | USB_REQ_GET_STATUS:
+ // DEVICE_REMOTE_WAKEUP
+ ubuf [0] = 1; // selfpowered
+ ubuf [1] = 0;
+ /* FALLTHROUGH */
+ case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+ case DeviceOutRequest | USB_REQ_SET_FEATURE:
+ dbg ("no device features yet yet");
+ break;
+ case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+ ubuf [0] = 1;
+ /* FALLTHROUGH */
+ case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+ break;
+ case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+ switch (wValue & 0xff00) {
+ case USB_DT_DEVICE << 8:
+ if (hcd->driver->flags & HCD_USB2)
+ bufp = usb2_rh_dev_descriptor;
+ else if (hcd->driver->flags & HCD_USB11)
+ bufp = usb11_rh_dev_descriptor;
+ else
+ goto error;
+ len = 18;
+ break;
+ case USB_DT_CONFIG << 8:
+ if (hcd->driver->flags & HCD_USB2) {
+ bufp = hs_rh_config_descriptor;
+ len = sizeof hs_rh_config_descriptor;
+ } else {
+ bufp = fs_rh_config_descriptor;
+ len = sizeof fs_rh_config_descriptor;
+ }
+ break;
+ case USB_DT_STRING << 8:
+ urb->actual_length = rh_string (
+ wValue & 0xff, hcd,
+ ubuf, wLength);
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case DeviceRequest | USB_REQ_GET_INTERFACE:
+ ubuf [0] = 0;
+ /* FALLTHROUGH */
+ case DeviceOutRequest | USB_REQ_SET_INTERFACE:
+ break;
+ case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+ // wValue == urb->dev->devaddr
+ dbg ("%s root hub device address %d",
+ hcd->bus->bus_name, wValue);
+ break;
+
+ /* INTERFACE REQUESTS (no defined feature/status flags) */
+
+ /* ENDPOINT REQUESTS */
+
+ case EndpointRequest | USB_REQ_GET_STATUS:
+ // ENDPOINT_HALT flag
+ ubuf [0] = 0;
+ ubuf [1] = 0;
+ /* FALLTHROUGH */
+ case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
+ case EndpointOutRequest | USB_REQ_SET_FEATURE:
+ dbg ("no endpoint features yet");
+ break;
+
+ /* CLASS REQUESTS (and errors) */
+
+ default:
+ /* non-generic request */
+ urb->status = hcd->driver->hub_control (hcd,
+ typeReq, wValue, wIndex,
+ ubuf, wLength);
+ break;
+error:
+ /* "protocol stall" on error */
+ urb->status = -EPIPE;
+ dbg ("unsupported hub control message (maxchild %d)",
+ urb->dev->maxchild);
+ }
+ if (urb->status) {
+ urb->actual_length = 0;
+ dbg ("CTRL: TypeReq=0x%x val=0x%x idx=0x%x len=%d ==> %d",
+ typeReq, wValue, wIndex, wLength, urb->status);
+ }
+ if (bufp) {
+ if (urb->transfer_buffer_length < len)
+ len = urb->transfer_buffer_length;
+ urb->actual_length = len;
+ // always USB_DIR_IN, toward host
+ memcpy (ubuf, bufp, len);
+ }
+
+ /* any errors get returned through the urb completion */
+ usb_hcd_giveback_urb (hcd, urb, 0);
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Root Hub interrupt transfers are synthesized with a timer.
+ * Completions are called in_interrupt() but not in_irq().
+ */
+
+static void rh_report_status (unsigned long ptr);
+
+static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb)
+{
+ int len = 1 + (urb->dev->maxchild / 8);
+
+ /* rh_timer protected by hcd_data_lock */
+ if (timer_pending (&hcd->rh_timer)
+ || urb->status != -EINPROGRESS
+ || !HCD_IS_RUNNING (hcd->state)
+ || urb->transfer_buffer_length < len) {
+ dbg ("not queuing status urb, stat %d", urb->status);
+ return -EINVAL;
+ }
+
+ urb->hcpriv = hcd; /* nonzero to indicate it's queued */
+ init_timer (&hcd->rh_timer);
+ hcd->rh_timer.function = rh_report_status;
+ hcd->rh_timer.data = (unsigned long) urb;
+ /* USB 2.0 spec says 256msec; this is close enough */
+ hcd->rh_timer.expires = jiffies + HZ/4;
+ add_timer (&hcd->rh_timer);
+ return 0;
+}
+
+/* timer callback */
+
+static void rh_report_status (unsigned long ptr)
+{
+ struct urb *urb;
+ struct usb_hcd *hcd;
+ int length;
+ unsigned long flags;
+
+ urb = (struct urb *) ptr;
+ spin_lock_irqsave (&urb->lock, flags);
+ if (!urb->dev) {
+ spin_unlock_irqrestore (&urb->lock, flags);
+ return;
+ }
+
+ hcd = urb->dev->bus->hcpriv;
+ if (urb->status == -EINPROGRESS) {
+ if (HCD_IS_RUNNING (hcd->state)) {
+ length = hcd->driver->hub_status_data (hcd,
+ urb->transfer_buffer);
+ spin_unlock_irqrestore (&urb->lock, flags);
+ if (length > 0) {
+ urb->actual_length = length;
+ urb->status = 0;
+ urb->complete (urb);
+ }
+ spin_lock_irqsave (&hcd_data_lock, flags);
+ urb->status = -EINPROGRESS;
+ if (HCD_IS_RUNNING (hcd->state)
+ && rh_status_urb (hcd, urb) != 0) {
+ /* another driver snuck in? */
+ dbg ("%s, can't resubmit roothub status urb?",
+ hcd->bus->bus_name);
+ spin_unlock_irqrestore (&hcd_data_lock, flags);
+ BUG ();
+ }
+ spin_unlock_irqrestore (&hcd_data_lock, flags);
+ } else
+ spin_unlock_irqrestore (&urb->lock, flags);
+ } else {
+ /* this urb's been unlinked */
+ urb->hcpriv = 0;
+ spin_unlock_irqrestore (&urb->lock, flags);
+
+ usb_hcd_giveback_urb (hcd, urb, 0);
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
+{
+ if (usb_pipeint (urb->pipe)) {
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave (&hcd_data_lock, flags);
+ retval = rh_status_urb (hcd, urb);
+ spin_unlock_irqrestore (&hcd_data_lock, flags);
+ return retval;
+ }
+ if (usb_pipecontrol (urb->pipe))
+ return rh_call_control (hcd, urb);
+ else
+ return -EINVAL;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void rh_status_dequeue (struct usb_hcd *hcd, struct urb *urb)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave (&hcd_data_lock, flags);
+ del_timer_sync (&hcd->rh_timer);
+ hcd->rh_timer.data = 0;
+ spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+ /* we rely on RH callback code not unlinking its URB! */
+ usb_hcd_giveback_urb (hcd, urb, 0);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_PCI
+
+/* PCI-based HCs are normal, but custom bus glue should be ok */
+
+static void hcd_irq (int irq, void *__hcd, struct pt_regs *r);
+static void hc_died (struct usb_hcd *hcd);
+
+/*-------------------------------------------------------------------------*/
+
+/* configure so an HC device and id are always provided */
+/* always called with process context; sleeping is OK */
+
+/**
+ * usb_hcd_pci_probe - initialize PCI-based HCDs
+ * @dev: USB Host Controller being probed
+ * @id: pci hotplug id connecting controller to HCD framework
+ * Context: !in_interrupt()
+ *
+ * Allocates basic PCI resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ * Store this function in the HCD's struct pci_driver as probe().
+ */
+int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct hc_driver *driver;
+ unsigned long resource, len;
+ void *base;
+ struct usb_bus *bus;
+ struct usb_hcd *hcd;
+ int retval, region;
+ char buf [8], *bufp = buf;
+
+ if (!id || !(driver = (struct hc_driver *) id->driver_data))
+ return -EINVAL;
+
+ if (pci_enable_device (dev) < 0)
+ return -ENODEV;
+
+ if (!dev->irq) {
+ err ("Found HC with no IRQ. Check BIOS/PCI %s setup!",
+ dev->slot_name);
+ return -ENODEV;
+ }
+
+ if (driver->flags & HCD_MEMORY) { // EHCI, OHCI
+ region = 0;
+ resource = pci_resource_start (dev, 0);
+ len = pci_resource_len (dev, 0);
+ if (!request_mem_region (resource, len, driver->description)) {
+ dbg ("controller already in use");
+ return -EBUSY;
+ }
+ base = ioremap_nocache (resource, len);
+ if (base == NULL) {
+ dbg ("error mapping memory");
+ retval = -EFAULT;
+clean_1:
+ release_mem_region (resource, len);
+ err ("init %s fail, %d", dev->slot_name, retval);
+ return retval;
+ }
+
+ } else { // UHCI
+ resource = len = 0;
+ for (region = 0; region < PCI_ROM_RESOURCE; region++) {
+ if (!(pci_resource_flags (dev, region) & IORESOURCE_IO))
+ continue;
+
+ resource = pci_resource_start (dev, region);
+ len = pci_resource_len (dev, region);
+ if (request_region (resource, len,
+ driver->description))
+ break;
+ }
+ if (region == PCI_ROM_RESOURCE) {
+ dbg ("no i/o regions available");
+ return -EBUSY;
+ }
+ base = (void *) resource;
+ }
+
+ // driver->start(), later on, will transfer device from
+ // control by SMM/BIOS to control by Linux (if needed)
+
+ pci_set_master (dev);
+ hcd = driver->hcd_alloc ();
+ if (hcd == NULL){
+ dbg ("hcd alloc fail");
+ retval = -ENOMEM;
+clean_2:
+ if (driver->flags & HCD_MEMORY) {
+ iounmap (base);
+ goto clean_1;
+ } else {
+ release_region (resource, len);
+ err ("init %s fail, %d", dev->slot_name, retval);
+ return retval;
+ }
+ }
+ pci_set_drvdata(dev, hcd);
+ hcd->driver = driver;
+ hcd->description = driver->description;
+ hcd->pdev = dev;
+ printk (KERN_INFO "%s %s: %s\n",
+ hcd->description, dev->slot_name, dev->name);
+
+#ifndef __sparc__
+ sprintf (buf, "%d", dev->irq);
+#else
+ bufp = __irq_itoa(dev->irq);
+#endif
+ if (request_irq (dev->irq, hcd_irq, SA_SHIRQ, hcd->description, hcd)
+ != 0) {
+ err ("request interrupt %s failed", bufp);
+ retval = -EBUSY;
+clean_3:
+ driver->hcd_free (hcd);
+ goto clean_2;
+ }
+ hcd->irq = dev->irq;
+
+ hcd->regs = base;
+ hcd->region = region;
+ printk (KERN_INFO "%s %s: irq %s, %s %p\n",
+ hcd->description, dev->slot_name, bufp,
+ (driver->flags & HCD_MEMORY) ? "pci mem" : "io base",
+ base);
+
+// FIXME simpler: make "bus" be that data, not pointer to it.
+// (fixed in 2.5)
+ bus = usb_alloc_bus (&hcd_operations);
+ if (bus == NULL) {
+ dbg ("usb_alloc_bus fail");
+ retval = -ENOMEM;
+ free_irq (dev->irq, hcd);
+ goto clean_3;
+ }
+ hcd->bus = bus;
+ bus->bus_name = dev->slot_name;
+ hcd->product_desc = dev->name;
+ bus->hcpriv = (void *) hcd;
+
+ INIT_LIST_HEAD (&hcd->dev_list);
+ INIT_LIST_HEAD (&hcd->hcd_list);
+
+ down (&hcd_list_lock);
+ list_add (&hcd->hcd_list, &hcd_list);
+ up (&hcd_list_lock);
+
+ usb_register_bus (bus);
+
+ if ((retval = driver->start (hcd)) < 0)
+ usb_hcd_pci_remove (dev);
+
+ return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_probe);
+
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_pci_probe(), first invoking
+ * the HCD's stop() method. It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ * Store this function in the HCD's struct pci_driver as remove().
+ */
+void usb_hcd_pci_remove (struct pci_dev *dev)
+{
+ struct usb_hcd *hcd;
+ struct usb_device *hub;
+
+ hcd = pci_get_drvdata(dev);
+ if (!hcd)
+ return;
+ printk (KERN_INFO "%s %s: remove state %x\n",
+ hcd->description, dev->slot_name, hcd->state);
+
+ if (in_interrupt ()) BUG ();
+
+ hub = hcd->bus->root_hub;
+ hcd->state = USB_STATE_QUIESCING;
+
+ dbg ("%s: roothub graceful disconnect", hcd->bus->bus_name);
+ usb_disconnect (&hub);
+ // usb_disconnect (&hcd->bus->root_hub);
+
+ hcd->driver->stop (hcd);
+ hcd->state = USB_STATE_HALT;
+
+ free_irq (hcd->irq, hcd);
+ if (hcd->driver->flags & HCD_MEMORY) {
+ iounmap (hcd->regs);
+ release_mem_region (pci_resource_start (dev, 0),
+ pci_resource_len (dev, 0));
+ } else {
+ release_region (pci_resource_start (dev, hcd->region),
+ pci_resource_len (dev, hcd->region));
+ }
+
+ down (&hcd_list_lock);
+ list_del (&hcd->hcd_list);
+ up (&hcd_list_lock);
+
+ usb_deregister_bus (hcd->bus);
+ usb_free_bus (hcd->bus);
+ hcd->bus = NULL;
+
+ hcd->driver->hcd_free (hcd);
+}
+EXPORT_SYMBOL (usb_hcd_pci_remove);
+
+
+#ifdef CONFIG_PM
+
+/*
+ * Some "sleep" power levels imply updating struct usb_driver
+ * to include a callback asking hcds to do their bit by checking
+ * if all the drivers can suspend. Gets involved with remote wakeup.
+ *
+ * If there are pending urbs, then HCs will need to access memory,
+ * causing extra power drain. New sleep()/wakeup() PM calls might
+ * be needed, beyond PCI suspend()/resume(). The root hub timer
+ * still be accessing memory though ...
+ *
+ * FIXME: USB should have some power budgeting support working with
+ * all kinds of hubs.
+ *
+ * FIXME: This assumes only D0->D3 suspend and D3->D0 resume.
+ * D1 and D2 states should do something, yes?
+ *
+ * FIXME: Should provide generic enable_wake(), calling pci_enable_wake()
+ * for all supported states, so that USB remote wakeup can work for any
+ * devices that support it (and are connected via powered hubs).
+ *
+ * FIXME: resume doesn't seem to work right any more...
+ */
+
+
+// 2.4 kernels have issued concurrent resumes (w/APM)
+// we defend against that error; PCI doesn't yet.
+
+/**
+ * usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
+ * @dev: USB Host Controller being suspended
+ *
+ * Store this function in the HCD's struct pci_driver as suspend().
+ */
+int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
+{
+ struct usb_hcd *hcd;
+ int retval;
+
+ hcd = pci_get_drvdata(dev);
+ printk (KERN_INFO "%s %s: suspend to state %d\n",
+ hcd->description, dev->slot_name, state);
+
+ pci_save_state (dev, hcd->pci_state);
+
+ // FIXME for all connected devices, leaf-to-root:
+ // driver->suspend()
+ // proposed "new 2.5 driver model" will automate that
+
+ /* driver may want to disable DMA etc */
+ retval = hcd->driver->suspend (hcd, state);
+ hcd->state = USB_STATE_SUSPENDED;
+
+ pci_set_power_state (dev, state);
+ return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_suspend);
+
+/**
+ * usb_hcd_pci_resume - power management resume of a PCI-based HCD
+ * @dev: USB Host Controller being resumed
+ *
+ * Store this function in the HCD's struct pci_driver as resume().
+ */
+int usb_hcd_pci_resume (struct pci_dev *dev)
+{
+ struct usb_hcd *hcd;
+ int retval;
+
+ hcd = pci_get_drvdata(dev);
+ printk (KERN_INFO "%s %s: resume\n",
+ hcd->description, dev->slot_name);
+
+ /* guard against multiple resumes (APM bug?) */
+ atomic_inc (&hcd->resume_count);
+ if (atomic_read (&hcd->resume_count) != 1) {
+ err ("concurrent PCI resumes for %s", hcd->bus->bus_name);
+ retval = 0;
+ goto done;
+ }
+
+ retval = -EBUSY;
+ if (hcd->state != USB_STATE_SUSPENDED) {
+ dbg ("can't resume, not suspended!");
+ goto done;
+ }
+ hcd->state = USB_STATE_RESUMING;
+
+ pci_set_power_state (dev, 0);
+ pci_restore_state (dev, hcd->pci_state);
+
+ retval = hcd->driver->resume (hcd);
+ if (!HCD_IS_RUNNING (hcd->state)) {
+ dbg ("resume %s failure, retval %d",
+ hcd->bus->bus_name, retval);
+ hc_died (hcd);
+// FIXME: recover, reset etc.
+ } else {
+ // FIXME for all connected devices, root-to-leaf:
+ // driver->resume ();
+ // proposed "new 2.5 driver model" will automate that
+ }
+
+done:
+ atomic_dec (&hcd->resume_count);
+ return retval;
+}
+EXPORT_SYMBOL (usb_hcd_pci_resume);
+
+#endif /* CONFIG_PM */
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Generic HC operations.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* called from khubd, or root hub init threads for hcd-private init */
+static int hcd_alloc_dev (struct usb_device *udev)
+{
+ struct hcd_dev *dev;
+ struct usb_hcd *hcd;
+ unsigned long flags;
+
+ if (!udev || udev->hcpriv)
+ return -EINVAL;
+ if (!udev->bus || !udev->bus->hcpriv)
+ return -ENODEV;
+ hcd = udev->bus->hcpriv;
+ if (hcd->state == USB_STATE_QUIESCING)
+ return -ENOLINK;
+
+ dev = (struct hcd_dev *) kmalloc (sizeof *dev, GFP_KERNEL);
+ if (dev == NULL)
+ return -ENOMEM;
+ memset (dev, 0, sizeof *dev);
+
+ INIT_LIST_HEAD (&dev->dev_list);
+ INIT_LIST_HEAD (&dev->urb_list);
+
+ spin_lock_irqsave (&hcd_data_lock, flags);
+ list_add (&dev->dev_list, &hcd->dev_list);
+ // refcount is implicit
+ udev->hcpriv = dev;
+ spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void hcd_panic (void *_hcd)
+{
+ struct usb_hcd *hcd = _hcd;
+ hcd->driver->stop (hcd);
+}
+
+static void hc_died (struct usb_hcd *hcd)
+{
+ struct list_head *devlist, *urblist;
+ struct hcd_dev *dev;
+ struct urb *urb;
+ unsigned long flags;
+
+ /* flag every pending urb as done */
+ spin_lock_irqsave (&hcd_data_lock, flags);
+ list_for_each (devlist, &hcd->dev_list) {
+ dev = list_entry (devlist, struct hcd_dev, dev_list);
+ list_for_each (urblist, &dev->urb_list) {
+ urb = list_entry (urblist, struct urb, urb_list);
+ dbg ("shutdown %s urb %p pipe %x, current status %d",
+ hcd->bus->bus_name,
+ urb, urb->pipe, urb->status);
+ if (urb->status == -EINPROGRESS)
+ urb->status = -ESHUTDOWN;
+ }
+ }
+ urb = (struct urb *) hcd->rh_timer.data;
+ if (urb)
+ urb->status = -ESHUTDOWN;
+ spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+ if (urb)
+ rh_status_dequeue (hcd, urb);
+
+ /* hcd->stop() needs a task context */
+ INIT_TQUEUE (&hcd->work, hcd_panic, hcd);
+ (void) schedule_task (&hcd->work);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void urb_unlink (struct urb *urb)
+{
+ unsigned long flags;
+ struct usb_device *dev;
+
+ /* Release any periodic transfer bandwidth */
+ if (urb->bandwidth)
+ usb_release_bandwidth (urb->dev, urb,
+ usb_pipeisoc (urb->pipe));
+
+ /* clear all state linking urb to this dev (and hcd) */
+
+ spin_lock_irqsave (&hcd_data_lock, flags);
+ list_del_init (&urb->urb_list);
+ dev = urb->dev;
+ urb->dev = NULL;
+ usb_dec_dev_use (dev);
+ spin_unlock_irqrestore (&hcd_data_lock, flags);
+}
+
+
+/* may be called in any context with a valid urb->dev usecount */
+/* caller surrenders "ownership" of urb */
+
+static int hcd_submit_urb (struct urb *urb)
+{
+ int status;
+ struct usb_hcd *hcd;
+ struct hcd_dev *dev;
+ unsigned long flags;
+ int pipe, temp, max;
+ int mem_flags;
+
+ if (!urb || urb->hcpriv || !urb->complete)
+ return -EINVAL;
+
+ urb->status = -EINPROGRESS;
+ urb->actual_length = 0;
+ urb->bandwidth = 0;
+ INIT_LIST_HEAD (&urb->urb_list);
+
+ if (!urb->dev || !urb->dev->bus || urb->dev->devnum <= 0)
+ return -ENODEV;
+ hcd = urb->dev->bus->hcpriv;
+ dev = urb->dev->hcpriv;
+ if (!hcd || !dev)
+ return -ENODEV;
+
+ /* can't submit new urbs when quiescing, halted, ... */
+ if (hcd->state == USB_STATE_QUIESCING || !HCD_IS_RUNNING (hcd->state))
+ return -ESHUTDOWN;
+ pipe = urb->pipe;
+ temp = usb_pipetype (urb->pipe);
+ if (usb_endpoint_halted (urb->dev, usb_pipeendpoint (pipe),
+ usb_pipeout (pipe)))
+ return -EPIPE;
+
+ /* NOTE: 2.5 passes this value explicitly in submit() */
+ mem_flags = GFP_ATOMIC;
+
+ /* FIXME there should be a sharable lock protecting us against
+ * config/altsetting changes and disconnects, kicking in here.
+ */
+
+ /* Sanity check, so HCDs can rely on clean data */
+ max = usb_maxpacket (urb->dev, pipe, usb_pipeout (pipe));
+ if (max <= 0) {
+ err ("bogus endpoint (bad maxpacket)");
+ return -EINVAL;
+ }
+
+ /* "high bandwidth" mode, 1-3 packets/uframe? */
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+ int mult;
+ switch (temp) {
+ case PIPE_ISOCHRONOUS:
+ case PIPE_INTERRUPT:
+ mult = 1 + ((max >> 11) & 0x03);
+ max &= 0x03ff;
+ max *= mult;
+ }
+ }
+
+ /* periodic transfers limit size per frame/uframe */
+ switch (temp) {
+ case PIPE_ISOCHRONOUS: {
+ int n, len;
+
+ if (urb->number_of_packets <= 0)
+ return -EINVAL;
+ for (n = 0; n < urb->number_of_packets; n++) {
+ len = urb->iso_frame_desc [n].length;
+ if (len < 0 || len > max)
+ return -EINVAL;
+ }
+
+ }
+ break;
+ case PIPE_INTERRUPT:
+ if (urb->transfer_buffer_length > max)
+ return -EINVAL;
+ }
+
+ /* the I/O buffer must usually be mapped/unmapped */
+ if (urb->transfer_buffer_length < 0)
+ return -EINVAL;
+
+ if (urb->next) {
+ warn ("use explicit queuing not urb->next");
+ return -EINVAL;
+ }
+
+#ifdef DEBUG
+ /* stuff that drivers shouldn't do, but which shouldn't
+ * cause problems in HCDs if they get it wrong.
+ */
+ {
+ unsigned int orig_flags = urb->transfer_flags;
+ unsigned int allowed;
+
+ /* enforce simple/standard policy */
+ allowed = USB_ASYNC_UNLINK; // affects later unlinks
+ allowed |= USB_NO_FSBR; // only affects UHCI
+ switch (temp) {
+ case PIPE_CONTROL:
+ allowed |= USB_DISABLE_SPD;
+ break;
+ case PIPE_BULK:
+ allowed |= USB_DISABLE_SPD | USB_QUEUE_BULK
+ | USB_ZERO_PACKET | URB_NO_INTERRUPT;
+ break;
+ case PIPE_INTERRUPT:
+ allowed |= USB_DISABLE_SPD;
+ break;
+ case PIPE_ISOCHRONOUS:
+ allowed |= USB_ISO_ASAP;
+ break;
+ }
+ urb->transfer_flags &= allowed;
+
+ /* fail if submitter gave bogus flags */
+ if (urb->transfer_flags != orig_flags) {
+ err ("BOGUS urb flags, %x --> %x",
+ orig_flags, urb->transfer_flags);
+ return -EINVAL;
+ }
+ }
+#endif
+ /*
+ * Force periodic transfer intervals to be legal values that are
+ * a power of two (so HCDs don't need to).
+ *
+ * FIXME want bus->{intr,iso}_sched_horizon values here. Each HC
+ * supports different values... this uses EHCI/UHCI defaults (and
+ * EHCI can use smaller non-default values).
+ */
+ switch (temp) {
+ case PIPE_ISOCHRONOUS:
+ case PIPE_INTERRUPT:
+ /* too small? */
+ if (urb->interval <= 0)
+ return -EINVAL;
+ /* too big? */
+ switch (urb->dev->speed) {
+ case USB_SPEED_HIGH: /* units are microframes */
+ // NOTE usb handles 2^15
+ if (urb->interval > (1024 * 8))
+ urb->interval = 1024 * 8;
+ temp = 1024 * 8;
+ break;
+ case USB_SPEED_FULL: /* units are frames/msec */
+ case USB_SPEED_LOW:
+ if (temp == PIPE_INTERRUPT) {
+ if (urb->interval > 255)
+ return -EINVAL;
+ // NOTE ohci only handles up to 32
+ temp = 128;
+ } else {
+ if (urb->interval > 1024)
+ urb->interval = 1024;
+ // NOTE usb and ohci handle up to 2^15
+ temp = 1024;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* power of two? */
+ while (temp > urb->interval)
+ temp >>= 1;
+ urb->interval = temp;
+ }
+
+
+ /*
+ * FIXME: make urb timeouts be generic, keeping the HCD cores
+ * as simple as possible.
+ */
+
+ // NOTE: a generic device/urb monitoring hook would go here.
+ // hcd_monitor_hook(MONITOR_URB_SUBMIT, urb)
+ // It would catch submission paths for all urbs.
+
+ /*
+ * Atomically queue the urb, first to our records, then to the HCD.
+ * Access to urb->status is controlled by urb->lock ... changes on
+ * i/o completion (normal or fault) or unlinking.
+ */
+
+ // FIXME: verify that quiescing hc works right (RH cleans up)
+
+ spin_lock_irqsave (&hcd_data_lock, flags);
+ if (HCD_IS_RUNNING (hcd->state) && hcd->state != USB_STATE_QUIESCING) {
+ usb_inc_dev_use (urb->dev);
+ list_add (&urb->urb_list, &dev->urb_list);
+ status = 0;
+ } else {
+ INIT_LIST_HEAD (&urb->urb_list);
+ status = -ESHUTDOWN;
+ }
+ spin_unlock_irqrestore (&hcd_data_lock, flags);
+ if (status)
+ return status;
+
+ // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag
+
+ /* For 2.4, don't map bounce buffer if it's a root hub operation. */
+ if (urb->dev == hcd->bus->root_hub) {
+ status = rh_urb_enqueue (hcd, urb);
+ } else {
+#ifdef CONFIG_PCI
+ if (usb_pipecontrol (urb->pipe))
+ urb->setup_dma = pci_map_single (
+ hcd->pdev,
+ urb->setup_packet,
+ sizeof (struct usb_ctrlrequest),
+ PCI_DMA_TODEVICE);
+ if (urb->transfer_buffer_length != 0)
+ urb->transfer_dma = pci_map_single (
+ hcd->pdev,
+ urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ usb_pipein (urb->pipe)
+ ? PCI_DMA_FROMDEVICE
+ : PCI_DMA_TODEVICE);
+#endif
+ status = hcd->driver->urb_enqueue (hcd, urb, mem_flags);
+ }
+ return status;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* called in any context */
+static int hcd_get_frame_number (struct usb_device *udev)
+{
+ struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv;
+ return hcd->driver->get_frame_number (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+struct completion_splice { // modified urb context:
+ /* did we complete? */
+ struct completion done;
+
+ /* original urb data */
+ void (*complete)(struct urb *);
+ void *context;
+};
+
+static void unlink_complete (struct urb *urb)
+{
+ struct completion_splice *splice;
+
+ splice = (struct completion_splice *) urb->context;
+
+ /* issue original completion call */
+ urb->complete = splice->complete;
+ urb->context = splice->context;
+ urb->complete (urb);
+
+ /* then let the synchronous unlink call complete */
+ complete (&splice->done);
+}
+
+/*
+ * called in any context; note ASYNC_UNLINK restrictions
+ *
+ * caller guarantees urb won't be recycled till both unlink()
+ * and the urb's completion function return
+ */
+static int hcd_unlink_urb (struct urb *urb)
+{
+ struct hcd_dev *dev;
+ struct usb_hcd *hcd = 0;
+ unsigned long flags;
+ struct completion_splice splice;
+ int retval;
+
+ if (!urb)
+ return -EINVAL;
+
+ /*
+ * we contend for urb->status with the hcd core,
+ * which changes it while returning the urb.
+ *
+ * Caller guaranteed that the urb pointer hasn't been freed, and
+ * that it was submitted. But as a rule it can't know whether or
+ * not it's already been unlinked ... so we respect the reversed
+ * lock sequence needed for the usb_hcd_giveback_urb() code paths
+ * (urb lock, then hcd_data_lock) in case some other CPU is now
+ * unlinking it.
+ */
+ spin_lock_irqsave (&urb->lock, flags);
+ spin_lock (&hcd_data_lock);
+ if (!urb->hcpriv || urb->transfer_flags & USB_TIMEOUT_KILLED) {
+ retval = -EINVAL;
+ goto done;
+ }
+
+ if (!urb->dev || !urb->dev->bus) {
+ retval = -ENODEV;
+ goto done;
+ }
+
+ /* giveback clears dev; non-null means it's linked at this level */
+ dev = urb->dev->hcpriv;
+ hcd = urb->dev->bus->hcpriv;
+ if (!dev || !hcd) {
+ retval = -ENODEV;
+ goto done;
+ }
+
+ /* Any status except -EINPROGRESS means the HCD has already started
+ * to return this URB to the driver. In that case, there's no
+ * more work for us to do.
+ *
+ * There's much magic because of "automagic resubmit" of interrupt
+ * transfers, stopped only by explicit unlinking. We won't issue
+ * an "it's unlinked" callback more than once, but device drivers
+ * can need to retry (SMP, -EAGAIN) an unlink request as well as
+ * fake out the "not yet completed" state (set -EINPROGRESS) if
+ * unlinking from complete(). Automagic eventually vanishes.
+ *
+ * FIXME use an URB_UNLINKED flag to match URB_TIMEOUT_KILLED
+ */
+ if (urb->status != -EINPROGRESS) {
+ if (usb_pipetype (urb->pipe) == PIPE_INTERRUPT)
+ retval = -EAGAIN;
+ else
+ retval = -EBUSY;
+ goto done;
+ }
+
+ /* maybe set up to block on completion notification */
+ if ((urb->transfer_flags & USB_TIMEOUT_KILLED))
+ urb->status = -ETIMEDOUT;
+ else if (!(urb->transfer_flags & USB_ASYNC_UNLINK)) {
+ if (in_interrupt ()) {
+ dbg ("non-async unlink in_interrupt");
+ retval = -EWOULDBLOCK;
+ goto done;
+ }
+ /* synchronous unlink: block till we see the completion */
+ init_completion (&splice.done);
+ splice.complete = urb->complete;
+ splice.context = urb->context;
+ urb->complete = unlink_complete;
+ urb->context = &splice;
+ urb->status = -ENOENT;
+ } else {
+ /* asynchronous unlink */
+ urb->status = -ECONNRESET;
+ }
+ spin_unlock (&hcd_data_lock);
+ spin_unlock_irqrestore (&urb->lock, flags);
+
+ if (urb == (struct urb *) hcd->rh_timer.data) {
+ rh_status_dequeue (hcd, urb);
+ retval = 0;
+ } else {
+ retval = hcd->driver->urb_dequeue (hcd, urb);
+// FIXME: if retval and we tried to splice, whoa!!
+if (retval && urb->status == -ENOENT) err ("whoa! retval %d", retval);
+ }
+
+ /* block till giveback, if needed */
+ if (!(urb->transfer_flags & (USB_ASYNC_UNLINK|USB_TIMEOUT_KILLED))
+ && HCD_IS_RUNNING (hcd->state)
+ && !retval) {
+ wait_for_completion (&splice.done);
+ } else if ((urb->transfer_flags & USB_ASYNC_UNLINK) && retval == 0) {
+ return -EINPROGRESS;
+ }
+ goto bye;
+done:
+ spin_unlock (&hcd_data_lock);
+ spin_unlock_irqrestore (&urb->lock, flags);
+bye:
+ if (retval)
+ dbg ("%s: hcd_unlink_urb fail %d",
+ hcd ? hcd->bus->bus_name : "(no bus?)",
+ retval);
+ return retval;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* called by khubd, rmmod, apmd, or other thread for hcd-private cleanup */
+
+// FIXME: likely best to have explicit per-setting (config+alt)
+// setup primitives in the usbcore-to-hcd driver API, so nothing
+// is implicit. kernel 2.5 needs a bunch of config cleanup...
+
+static int hcd_free_dev (struct usb_device *udev)
+{
+ struct hcd_dev *dev;
+ struct usb_hcd *hcd;
+ unsigned long flags;
+
+ if (!udev || !udev->hcpriv)
+ return -EINVAL;
+
+ if (!udev->bus || !udev->bus->hcpriv)
+ return -ENODEV;
+
+ // should udev->devnum == -1 ??
+
+ dev = udev->hcpriv;
+ hcd = udev->bus->hcpriv;
+
+ /* device driver problem with refcounts? */
+ if (!list_empty (&dev->urb_list)) {
+ dbg ("free busy dev, %s devnum %d (bug!)",
+ hcd->bus->bus_name, udev->devnum);
+ return -EINVAL;
+ }
+
+ hcd->driver->free_config (hcd, udev);
+
+ spin_lock_irqsave (&hcd_data_lock, flags);
+ list_del (&dev->dev_list);
+ udev->hcpriv = NULL;
+ spin_unlock_irqrestore (&hcd_data_lock, flags);
+
+ kfree (dev);
+ return 0;
+}
+
+static struct usb_operations hcd_operations = {
+ allocate: hcd_alloc_dev,
+ get_frame_number: hcd_get_frame_number,
+ submit_urb: hcd_submit_urb,
+ unlink_urb: hcd_unlink_urb,
+ deallocate: hcd_free_dev,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static void hcd_irq (int irq, void *__hcd, struct pt_regs * r)
+{
+ struct usb_hcd *hcd = __hcd;
+ int start = hcd->state;
+
+ if (unlikely (hcd->state == USB_STATE_HALT)) /* irq sharing? */
+ return;
+
+ hcd->driver->irq (hcd, r);
+ if (hcd->state != start && hcd->state == USB_STATE_HALT)
+ hc_died (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_hcd_giveback_urb - return URB from HCD to device driver
+ * @hcd: host controller returning the URB
+ * @urb: urb being returned to the USB device driver.
+ * @regs: saved hardware registers (ignored on 2.4 kernels)
+ * Context: in_interrupt()
+ *
+ * This hands the URB from HCD to its USB device driver, using its
+ * completion function. The HCD has freed all per-urb resources
+ * (and is done using urb->hcpriv). It also released all HCD locks;
+ * the device driver won't cause deadlocks if it resubmits this URB,
+ * and won't confuse things by modifying and resubmitting this one.
+ * Bandwidth and other resources will be deallocated.
+ *
+ * HCDs must not use this for periodic URBs that are still scheduled
+ * and will be reissued. They should just call their completion handlers
+ * until the urb is returned to the device driver by unlinking.
+ *
+ * NOTE that no urb->next processing is done, even for isochronous URBs.
+ * ISO streaming functionality can be achieved by having completion handlers
+ * re-queue URBs. Such explicit queuing doesn't discard error reports.
+ */
+void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
+{
+ int is_root_hub_operation;
+
+ /* Work this out here as urb_unlink clears urb->dev */
+ is_root_hub_operation = (urb->dev == hcd->bus->root_hub);
+
+ urb_unlink (urb);
+
+ // NOTE: a generic device/urb monitoring hook would go here.
+ // hcd_monitor_hook(MONITOR_URB_FINISH, urb, dev)
+ // It would catch exit/unlink paths for all urbs, but non-exit
+ // completions for periodic urbs need hooks inside the HCD.
+ // hcd_monitor_hook(MONITOR_URB_UPDATE, urb, dev)
+
+ // NOTE: 2.5 does this if !URB_NO_DMA_MAP transfer flag
+
+#ifdef CONFIG_PCI
+ /* For 2.4, don't unmap bounce buffer if it's a root hub operation. */
+ if (usb_pipecontrol (urb->pipe) && !is_root_hub_operation)
+ pci_unmap_single (hcd->pdev, urb->setup_dma,
+ sizeof (struct usb_ctrlrequest),
+ PCI_DMA_TODEVICE);
+
+ if ((urb->transfer_buffer_length != 0) && !is_root_hub_operation)
+ pci_unmap_single (hcd->pdev, urb->transfer_dma,
+ urb->transfer_buffer_length,
+ usb_pipein (urb->pipe)
+ ? PCI_DMA_FROMDEVICE
+ : PCI_DMA_TODEVICE);
+#endif
+
+ /* pass ownership to the completion handler */
+ urb->complete (urb);
+}
+EXPORT_SYMBOL (usb_hcd_giveback_urb);
diff --git a/linux-2.4.29-xen-sparse/include/asm-xen/msr.h b/linux-2.4.29-xen-sparse/include/asm-xen/msr.h
deleted file mode 100644
index 1a2c8765a8..0000000000
--- a/linux-2.4.29-xen-sparse/include/asm-xen/msr.h
+++ /dev/null
@@ -1,138 +0,0 @@
-#ifndef __ASM_MSR_H
-#define __ASM_MSR_H
-
-/*
- * Access to machine-specific registers (available on 586 and better only)
- * Note: the rd* operations modify the parameters directly (without using
- * pointer indirection), this allows gcc to optimize better
- */
-
-#define rdmsr(msr,val1,val2) \
-{ \
- dom0_op_t op; \
- op.cmd = DOM0_MSR; \
- op.u.msr.write = 0; \
- op.u.msr.msr = msr; \
- op.u.msr.cpu_mask = (1 << current->processor); \
- HYPERVISOR_dom0_op(&op); \
- val1 = op.u.msr.out1; \
- val2 = op.u.msr.out2; \
-}
-
-#define wrmsr(msr,val1,val2) \
-{ \
- dom0_op_t op; \
- op.cmd = DOM0_MSR; \
- op.u.msr.write = 1; \
- op.u.msr.cpu_mask = (1 << current->processor); \
- op.u.msr.msr = msr; \
- op.u.msr.in1 = val1; \
- op.u.msr.in2 = val2; \
- HYPERVISOR_dom0_op(&op); \
-}
-
-#define rdtsc(low,high) \
- __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
-
-#define rdtscl(low) \
- __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx")
-
-#define rdtscll(val) \
- __asm__ __volatile__("rdtsc" : "=A" (val))
-
-#define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
-
-#define rdpmc(counter,low,high) \
- __asm__ __volatile__("rdpmc" \
- : "=a" (low), "=d" (high) \
- : "c" (counter))
-
-/* symbolic names for some interesting MSRs */
-/* Intel defined MSRs. */
-#define MSR_IA32_P5_MC_ADDR 0
-#define MSR_IA32_P5_MC_TYPE 1
-#define MSR_IA32_PLATFORM_ID 0x17
-#define MSR_IA32_EBL_CR_POWERON 0x2a
-
-#define MSR_IA32_APICBASE 0x1b
-#define MSR_IA32_APICBASE_BSP (1<<8)
-#define MSR_IA32_APICBASE_ENABLE (1<<11)
-#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
-
-#define MSR_IA32_UCODE_WRITE 0x79
-#define MSR_IA32_UCODE_REV 0x8b
-
-#define MSR_IA32_BBL_CR_CTL 0x119
-
-#define MSR_IA32_MCG_CAP 0x179
-#define MSR_IA32_MCG_STATUS 0x17a
-#define MSR_IA32_MCG_CTL 0x17b
-
-#define MSR_IA32_THERM_CONTROL 0x19a
-#define MSR_IA32_THERM_INTERRUPT 0x19b
-#define MSR_IA32_THERM_STATUS 0x19c
-#define MSR_IA32_MISC_ENABLE 0x1a0
-
-#define MSR_IA32_DEBUGCTLMSR 0x1d9
-#define MSR_IA32_LASTBRANCHFROMIP 0x1db
-#define MSR_IA32_LASTBRANCHTOIP 0x1dc
-#define MSR_IA32_LASTINTFROMIP 0x1dd
-#define MSR_IA32_LASTINTTOIP 0x1de
-
-#define MSR_IA32_MC0_CTL 0x400
-#define MSR_IA32_MC0_STATUS 0x401
-#define MSR_IA32_MC0_ADDR 0x402
-#define MSR_IA32_MC0_MISC 0x403
-
-#define MSR_P6_PERFCTR0 0xc1
-#define MSR_P6_PERFCTR1 0xc2
-#define MSR_P6_EVNTSEL0 0x186
-#define MSR_P6_EVNTSEL1 0x187
-
-#define MSR_IA32_PERF_STATUS 0x198
-#define MSR_IA32_PERF_CTL 0x199
-
-/* AMD Defined MSRs */
-#define MSR_K6_EFER 0xC0000080
-#define MSR_K6_STAR 0xC0000081
-#define MSR_K6_WHCR 0xC0000082
-#define MSR_K6_UWCCR 0xC0000085
-#define MSR_K6_EPMR 0xC0000086
-#define MSR_K6_PSOR 0xC0000087
-#define MSR_K6_PFIR 0xC0000088
-
-#define MSR_K7_EVNTSEL0 0xC0010000
-#define MSR_K7_PERFCTR0 0xC0010004
-#define MSR_K7_HWCR 0xC0010015
-#define MSR_K7_CLK_CTL 0xC001001b
-#define MSR_K7_FID_VID_CTL 0xC0010041
-#define MSR_K7_VID_STATUS 0xC0010042
-
-/* Centaur-Hauls/IDT defined MSRs. */
-#define MSR_IDT_FCR1 0x107
-#define MSR_IDT_FCR2 0x108
-#define MSR_IDT_FCR3 0x109
-#define MSR_IDT_FCR4 0x10a
-
-#define MSR_IDT_MCR0 0x110
-#define MSR_IDT_MCR1 0x111
-#define MSR_IDT_MCR2 0x112
-#define MSR_IDT_MCR3 0x113
-#define MSR_IDT_MCR4 0x114
-#define MSR_IDT_MCR5 0x115
-#define MSR_IDT_MCR6 0x116
-#define MSR_IDT_MCR7 0x117
-#define MSR_IDT_MCR_CTRL 0x120
-
-/* VIA Cyrix defined MSRs*/
-#define MSR_VIA_FCR 0x1107
-#define MSR_VIA_LONGHAUL 0x110a
-#define MSR_VIA_BCR2 0x1147
-
-/* Transmeta defined MSRs */
-#define MSR_TMTA_LONGRUN_CTRL 0x80868010
-#define MSR_TMTA_LONGRUN_FLAGS 0x80868011
-#define MSR_TMTA_LRTI_READOUT 0x80868018
-#define MSR_TMTA_LRTI_VOLT_MHZ 0x8086801a
-
-#endif /* __ASM_MSR_H */
diff --git a/linux-2.4.29-xen-sparse/mkbuildtree b/linux-2.4.29-xen-sparse/mkbuildtree
index d586153418..d22c951359 100755
--- a/linux-2.4.29-xen-sparse/mkbuildtree
+++ b/linux-2.4.29-xen-sparse/mkbuildtree
@@ -163,6 +163,7 @@ ln -sf ../asm-i386/mmu.h
ln -sf ../asm-i386/mmx.h
ln -sf ../asm-i386/mpspec.h
ln -sf ../asm-i386/msgbuf.h
+ln -sf ../asm-i386/msr.h
ln -sf ../asm-i386/mtrr.h
ln -sf ../asm-i386/namei.h
ln -sf ../asm-i386/param.h
@@ -281,4 +282,12 @@ ln -sf ../../../../../${LINUX_26}/drivers/xen/blkback/vbd.c
cd ${AD}/arch/xen/drivers/blkif/frontend
ln -sf ../../../../../${LINUX_26}/drivers/xen/blkfront/blkfront.c
+cd ${AD}/arch/xen/drivers/usbif/frontend
+ln -sf ../../../../../${LINUX_26}/drivers/xen/usbfront/usbfront.c main.c
+ln -sf ../../../../../${LINUX_26}/drivers/xen/usbfront/xhci.h
+cd ${AD}/arch/xen/drivers/usbif/backend
+ln -sf ../../../../../${LINUX_26}/drivers/xen/usbback/common.h
+ln -sf ../../../../../${LINUX_26}/drivers/xen/usbback/control.c
+ln -sf ../../../../../${LINUX_26}/drivers/xen/usbback/interface.c
+ln -sf ../../../../../${LINUX_26}/drivers/xen/usbback/usbback.c main.c
diff --git a/linux-2.6.10-xen-sparse/arch/xen/Kconfig b/linux-2.6.10-xen-sparse/arch/xen/Kconfig
index 27eac46739..9beeb15593 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/Kconfig
+++ b/linux-2.6.10-xen-sparse/arch/xen/Kconfig
@@ -48,6 +48,19 @@ config XEN_BLKDEV_BACKEND
block devices to other guests via a high-performance shared-memory
interface.
+config XEN_BLKDEV_TAP_BE
+ bool "Block Tap support for backend driver (DANGEROUS)"
+ depends on XEN_BLDEV_BACKEND
+ default n
+ help
+ If you intend to use the block tap driver, the backend domain will
+ not know the domain id of the real frontend, and so will not be able
+ to map its data pages. This modifies the backend to attempt to map
+ from both the tap domain and the real frontend. This presents a
+ security risk, and so should ONLY be used for development
+ with the blktap. This option will be removed as the block drivers are
+ modified to use grant tables.
+
config XEN_NETDEV_BACKEND
bool "Network-device backend driver"
depends on XEN_PHYSDEV_ACCESS
@@ -92,6 +105,15 @@ config XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER
are unsure; or if you experience network hangs when this option is
enabled; then you must say N here.
+config XEN_BLKDEV_TAP
+ bool "Block device tap driver"
+ default n
+ help
+ This driver allows a VM to interact on block device channels
+ to other VMs. Block messages may be passed through or redirected
+ to a character device, allowing device prototyping in application
+ space. Odds are that you want to say N here.
+
config XEN_WRITABLE_PAGETABLES
bool
default y
diff --git a/linux-2.6.10-xen-sparse/arch/xen/configs/xen0_defconfig b/linux-2.6.10-xen-sparse/arch/xen/configs/xen0_defconfig
index d41daac521..664bac622c 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/configs/xen0_defconfig
+++ b/linux-2.6.10-xen-sparse/arch/xen/configs/xen0_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc3-xen0
-# Sun Dec 26 10:34:29 2004
+# Linux kernel version: 2.6.10-xen0
+# Mon Dec 27 10:14:40 2004
#
CONFIG_XEN=y
CONFIG_ARCH_XEN=y
@@ -13,10 +13,12 @@ CONFIG_NO_IDLE_HZ=y
CONFIG_XEN_PRIVILEGED_GUEST=y
CONFIG_XEN_PHYSDEV_ACCESS=y
CONFIG_XEN_BLKDEV_BACKEND=y
+# CONFIG_XEN_BLKDEV_TAP_BE is not set
CONFIG_XEN_NETDEV_BACKEND=y
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
+# CONFIG_XEN_BLKDEV_TAP is not set
CONFIG_XEN_WRITABLE_PAGETABLES=y
CONFIG_XEN_SCRUB_PAGES=y
CONFIG_HAVE_ARCH_DEV_ALLOC_SKB=y
diff --git a/linux-2.6.10-xen-sparse/arch/xen/configs/xenU_defconfig b/linux-2.6.10-xen-sparse/arch/xen/configs/xenU_defconfig
index 63450b421c..80e60bddfc 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/configs/xenU_defconfig
+++ b/linux-2.6.10-xen-sparse/arch/xen/configs/xenU_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10-rc3-xenU
-# Sun Dec 26 10:35:15 2004
+# Linux kernel version: 2.6.10-xenU
+# Mon Dec 27 10:15:03 2004
#
CONFIG_XEN=y
CONFIG_ARCH_XEN=y
@@ -17,6 +17,7 @@ CONFIG_NO_IDLE_HZ=y
CONFIG_XEN_BLKDEV_FRONTEND=y
CONFIG_XEN_NETDEV_FRONTEND=y
# CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
+# CONFIG_XEN_BLKDEV_TAP is not set
CONFIG_XEN_WRITABLE_PAGETABLES=y
CONFIG_XEN_SCRUB_PAGES=y
CONFIG_HAVE_ARCH_DEV_ALLOC_SKB=y
diff --git a/linux-2.6.10-xen-sparse/arch/xen/i386/Kconfig b/linux-2.6.10-xen-sparse/arch/xen/i386/Kconfig
index 7a3a73d869..5a6baad349 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/i386/Kconfig
+++ b/linux-2.6.10-xen-sparse/arch/xen/i386/Kconfig
@@ -331,36 +331,33 @@ config HPET_EMULATE_RTC
def_bool HPET_TIMER && RTC=y
config SMP
- bool
- default n
-#config SMP
-# bool "Symmetric multi-processing support"
-# ---help---
-# This enables support for systems with more than one CPU. If you have
-# a system with only one CPU, like most personal computers, say N. If
-# you have a system with more than one CPU, say Y.
-#
-# If you say N here, the kernel will run on single and multiprocessor
-# machines, but will use only one CPU of a multiprocessor machine. If
-# you say Y here, the kernel will run on many, but not all,
-# singleprocessor machines. On a singleprocessor machine, the kernel
-# will run faster if you say N here.
-#
-# Note that if you say Y here and choose architecture "586" or
-# "Pentium" under "Processor family", the kernel will not work on 486
-# architectures. Similarly, multiprocessor kernels for the "PPro"
-# architecture may not work on all Pentium based boards.
-#
-# People using multiprocessor machines who say Y here should also say
-# Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
-# Management" code will be disabled if you say Y here.
-#
-# See also the <file:Documentation/smp.txt>,
-# <file:Documentation/i386/IO-APIC.txt>,
-# <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
-# <http://www.tldp.org/docs.html#howto>.
-#
-# If you don't know what to do here, say N.
+ bool "Symmetric multi-processing support"
+ ---help---
+ This enables support for systems with more than one CPU. If you have
+ a system with only one CPU, like most personal computers, say N. If
+ you have a system with more than one CPU, say Y.
+
+ If you say N here, the kernel will run on single and multiprocessor
+ machines, but will use only one CPU of a multiprocessor machine. If
+ you say Y here, the kernel will run on many, but not all,
+ singleprocessor machines. On a singleprocessor machine, the kernel
+ will run faster if you say N here.
+
+ Note that if you say Y here and choose architecture "586" or
+ "Pentium" under "Processor family", the kernel will not work on 486
+ architectures. Similarly, multiprocessor kernels for the "PPro"
+ architecture may not work on all Pentium based boards.
+
+ People using multiprocessor machines who say Y here should also say
+ Y to "Enhanced Real Time Clock Support", below. The "Advanced Power
+ Management" code will be disabled if you say Y here.
+
+ See also the <file:Documentation/smp.txt>,
+ <file:Documentation/i386/IO-APIC.txt>,
+ <file:Documentation/nmi_watchdog.txt> and the SMP-HOWTO available at
+ <http://www.tldp.org/docs.html#howto>.
+
+ If you don't know what to do here, say N.
config NR_CPUS
int "Maximum number of CPUs (2-255)"
@@ -647,6 +644,11 @@ config REGPARM
-mregparm=3 is used.
+config X86_LOCAL_APIC
+ bool
+ depends on (X86_VISWS || SMP) && !X86_VOYAGER
+ default n
+
if XEN_PHYSDEV_ACCESS
menu "Bus options (PCI, PCMCIA, EISA, MCA, ISA)"
@@ -656,15 +658,10 @@ config X86_VISWS_APIC
depends on X86_VISWS
default y
-config X86_LOCAL_APIC
- bool
- depends on (X86_VISWS || SMP) && !X86_VOYAGER
- default y
-
-config X86_IO_APIC
- bool
- depends on SMP && !(X86_VISWS || X86_VOYAGER)
- default y
+#config X86_IO_APIC
+# bool
+# depends on SMP && !(X86_VISWS || X86_VOYAGER)
+# default y
config PCI
bool "PCI support" if !X86_VISWS
@@ -934,10 +931,10 @@ config X86_SMP
depends on SMP && !X86_VOYAGER
default y
-config X86_HT
- bool
- depends on SMP && !(X86_VISWS || X86_VOYAGER)
- default y
+#config X86_HT
+# bool
+# depends on SMP && !(X86_VISWS || X86_VOYAGER)
+# default y
config X86_BIOS_REBOOT
bool
diff --git a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/Makefile b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/Makefile
index 522bab987a..1542958464 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/Makefile
+++ b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/Makefile
@@ -27,10 +27,11 @@ c-obj-$(CONFIG_X86_MSR) += msr.o
c-obj-$(CONFIG_X86_CPUID) += cpuid.o
obj-$(CONFIG_MICROCODE) += microcode.o
c-obj-$(CONFIG_APM) += apm.o
-c-obj-$(CONFIG_X86_SMP) += smp.o smpboot.o
-c-obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o
+obj-$(CONFIG_X86_SMP) += smp.o smpboot.o
+#obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o
c-obj-$(CONFIG_X86_MPPARSE) += mpparse.o
-c-obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
+#obj-$(CONFIG_X86_LOCAL_APIC) += apic.o
+c-obj-$(CONFIG_X86_LOCAL_APIC) += nmi.o
c-obj-$(CONFIG_X86_IO_APIC) += io_apic.o
c-obj-$(CONFIG_X86_NUMAQ) += numaq.o
c-obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o
diff --git a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/cpu/common.c b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/cpu/common.c
index a29a7f4e97..750524cfcf 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/cpu/common.c
+++ b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/cpu/common.c
@@ -549,17 +549,6 @@ void __init cpu_init (void)
}
/*
- * Initialize the per-CPU GDT with the boot GDT,
- * and set up the GDT descriptor:
- */
- if (cpu) {
- cpu_gdt_descr[cpu].size = GDT_SIZE;
- cpu_gdt_descr[cpu].address = 0; /* XXXcl alloc page */
- BUG(); /* XXXcl SMP */
- memcpy((void *)cpu_gdt_descr[cpu].address,
- (void *)cpu_gdt_descr[0].address, GDT_SIZE);
- }
- /*
* Set up the per-thread TLS descriptor cache:
*/
memcpy(thread->tls_array, &get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN],
@@ -604,3 +593,9 @@ void __init cpu_init (void)
current->used_math = 0;
mxcsr_feature_mask_init();
}
+
+
+int get_smp_processor_id(void)
+{
+ return smp_processor_id();
+}
diff --git a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/entry.S b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/entry.S
index 321f89e3d4..db26c6a440 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/entry.S
+++ b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/entry.S
@@ -80,12 +80,44 @@ VM_MASK = 0x00020000
#define evtchn_upcall_pending /* 0 */
#define evtchn_upcall_mask 1
+#define sizeof_vcpu_shift 3
+
+#ifdef CONFIG_SMP
+#define XEN_GET_VCPU_INFO(reg)
+#define preempt_disable(reg) incl TI_preempt_count(reg)
+#define preempt_enable(reg) decl TI_preempt_count(reg)
+#define XEN_LOCK_VCPU_INFO_SMP(reg) preempt_disable(%ebp) ; \
+ movl TI_cpu(%ebp),reg ; \
+ shl $sizeof_vcpu_shift,reg ; \
+ addl HYPERVISOR_shared_info,reg
+#define XEN_UNLOCK_VCPU_INFO_SMP(reg) preempt_enable(%ebp)
+#define XEN_UNLOCK_VCPU_INFO_SMP_fixup .byte 0xff,0xff,0xff
+#define Ux00 0xff
+#define XEN_LOCKED_BLOCK_EVENTS(reg) movb $1,evtchn_upcall_mask(reg)
+#define XEN_BLOCK_EVENTS(reg) XEN_LOCK_VCPU_INFO_SMP(reg) ; \
+ XEN_LOCKED_BLOCK_EVENTS(reg) ; \
+ XEN_UNLOCK_VCPU_INFO_SMP(reg)
+#define XEN_UNBLOCK_EVENTS(reg) XEN_LOCK_VCPU_INFO_SMP(reg) ; \
+ movb $0,evtchn_upcall_mask(reg) ; \
+ XEN_UNLOCK_VCPU_INFO_SMP(reg)
+#define XEN_SAVE_UPCALL_MASK(reg,tmp,off) GET_THREAD_INFO(%ebp) ; \
+ XEN_LOCK_VCPU_INFO_SMP(reg) ; \
+ movb evtchn_upcall_mask(reg), tmp ; \
+ movb tmp, off(%esp) ; \
+ XEN_UNLOCK_VCPU_INFO_SMP(reg)
+#else
#define XEN_GET_VCPU_INFO(reg) movl HYPERVISOR_shared_info,reg
-#define XEN_BLOCK_EVENTS(reg) movb $1,evtchn_upcall_mask(reg)
+#define XEN_LOCK_VCPU_INFO_SMP(reg)
+#define XEN_UNLOCK_VCPU_INFO_SMP(reg)
+#define XEN_UNLOCK_VCPU_INFO_SMP_fixup
+#define Ux00 0x00
+#define XEN_LOCKED_BLOCK_EVENTS(reg) movb $1,evtchn_upcall_mask(reg)
+#define XEN_BLOCK_EVENTS(reg) XEN_LOCKED_BLOCK_EVENTS(reg)
#define XEN_UNBLOCK_EVENTS(reg) movb $0,evtchn_upcall_mask(reg)
#define XEN_SAVE_UPCALL_MASK(reg,tmp,off) \
movb evtchn_upcall_mask(reg), tmp; \
movb tmp, off(%esp)
+#endif
#define XEN_TEST_PENDING(reg) testb $0xFF,evtchn_upcall_pending(reg)
@@ -287,9 +319,11 @@ restore_all:
jnz resume_vm86
movb EVENT_MASK(%esp), %al
notb %al # %al == ~saved_mask
+ XEN_LOCK_VCPU_INFO_SMP(%esi)
andb evtchn_upcall_mask(%esi),%al
andb $1,%al # %al == mask & ~saved_mask
jnz restore_all_enable_events # != 0 => reenable event delivery
+ XEN_UNLOCK_VCPU_INFO_SMP(%esi)
RESTORE_ALL
resume_vm86:
@@ -476,8 +510,10 @@ restore_all_enable_events:
scrit: /**** START OF CRITICAL REGION ****/
XEN_TEST_PENDING(%esi)
jnz 14f # process more events if necessary...
+ XEN_UNLOCK_VCPU_INFO_SMP(%esi)
RESTORE_ALL
-14: XEN_BLOCK_EVENTS(%esi)
+14: XEN_LOCKED_BLOCK_EVENTS(%esi)
+ XEN_UNLOCK_VCPU_INFO_SMP(%esi)
jmp 11b
ecrit: /**** END OF CRITICAL REGION ****/
# [How we do the fixup]. We want to merge the current stack frame with the
@@ -490,24 +526,33 @@ ecrit: /**** END OF CRITICAL REGION ****/
critical_region_fixup:
addl $critical_fixup_table-scrit,%eax
movzbl (%eax),%eax # %eax contains num bytes popped
- mov %esp,%esi
+#ifdef CONFIG_SMP
+ cmpb $0xff,%al
+ jne 15f
+ add $1,%al
+ GET_THREAD_INFO(%ebp)
+ XEN_UNLOCK_VCPU_INFO_SMP(%esi)
+15:
+#endif
+ mov %esp,%esi
add %eax,%esi # %esi points at end of src region
mov %esp,%edi
add $0x34,%edi # %edi points at end of dst region
mov %eax,%ecx
shr $2,%ecx # convert words to bytes
- je 16f # skip loop if nothing to copy
-15: subl $4,%esi # pre-decrementing copy loop
+ je 17f # skip loop if nothing to copy
+16: subl $4,%esi # pre-decrementing copy loop
subl $4,%edi
movl (%esi),%eax
movl %eax,(%edi)
- loop 15b
-16: movl %edi,%esp # final %edi is top of merged stack
+ loop 16b
+17: movl %edi,%esp # final %edi is top of merged stack
jmp 11b
critical_fixup_table:
- .byte 0x00,0x00,0x00 # testb $0xff,(%esi) = XEN_TEST_PENDING
- .byte 0x00,0x00 # jnz 14f
+ .byte Ux00,Ux00,Ux00 # testb $0xff,(%esi) = XEN_TEST_PENDING
+ .byte Ux00,Ux00 # jnz 14f
+ XEN_UNLOCK_VCPU_INFO_SMP_fixup
.byte 0x00 # pop %ebx
.byte 0x04 # pop %ecx
.byte 0x08 # pop %edx
@@ -519,7 +564,8 @@ critical_fixup_table:
.byte 0x20 # pop %es
.byte 0x24,0x24,0x24 # add $4,%esp
.byte 0x28 # iret
- .byte 0x00,0x00,0x00,0x00 # movb $1,1(%esi)
+ .byte Ux00,Ux00,Ux00,Ux00 # movb $1,1(%esi)
+ XEN_UNLOCK_VCPU_INFO_SMP_fixup
.byte 0x00,0x00 # jmp 11b
# Hypervisor uses this for application faults while it executes.
diff --git a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/head.S b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/head.S
index b8ac0568da..3d2d8947a4 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/head.S
+++ b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/head.S
@@ -31,14 +31,19 @@
ENTRY(startup_32)
cld
- /* Set up the stack pointer */
- lss stack_start,%esp
-
/* Copy the necessary stuff from xen_start_info structure. */
mov $xen_start_info_union,%edi
mov $128,%ecx
rep movsl
+#ifdef CONFIG_SMP
+ENTRY(startup_32_smp)
+ cld
+#endif /* CONFIG_SMP */
+
+ /* Set up the stack pointer */
+ lss stack_start,%esp
+
checkCPUtype:
/* get vendor info */
@@ -61,11 +66,22 @@ checkCPUtype:
movb %cl,X86_MASK
movl %edx,X86_CAPABILITY
+ incb ready
+
xorl %eax,%eax # Clear FS/GS and LDT
movl %eax,%fs
movl %eax,%gs
cld # gcc2 wants the direction flag cleared at all times
+#ifdef CONFIG_SMP
+ movb ready, %cl
+ cmpb $1,%cl
+ je 1f # the first CPU calls start_kernel
+ # all other CPUs call initialize_secondary
+ call initialize_secondary
+ jmp L6
+1:
+#endif /* CONFIG_SMP */
call start_kernel
L6:
jmp L6 # main should never return here, but
@@ -88,6 +104,8 @@ ENTRY(stack_start)
.long init_thread_union+THREAD_SIZE
.long __BOOT_DS
+ready: .byte 0
+
.globl idt_descr
.globl cpu_gdt_descr
diff --git a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/irq.c b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/irq.c
new file mode 100644
index 0000000000..6cd16ccfdc
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/irq.c
@@ -0,0 +1,258 @@
+/*
+ * linux/arch/i386/kernel/irq.c
+ *
+ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
+ *
+ * This file contains the lowest level x86-specific interrupt
+ * entry, irq-stacks and irq statistics code. All the remaining
+ * irq logic is done by the generic kernel/irq/ code and
+ * by the x86-specific irq controller code. (e.g. i8259.c and
+ * io_apic.c.)
+ */
+
+#include <asm/uaccess.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+
+#ifndef CONFIG_X86_LOCAL_APIC
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves.
+ */
+void ack_bad_irq(unsigned int irq)
+{
+ printk("unexpected IRQ trap at vector %02x\n", irq);
+}
+#endif
+
+#ifdef CONFIG_4KSTACKS
+/*
+ * per-CPU IRQ handling contexts (thread information and stack)
+ */
+union irq_ctx {
+ struct thread_info tinfo;
+ u32 stack[THREAD_SIZE/sizeof(u32)];
+};
+
+static union irq_ctx *hardirq_ctx[NR_CPUS];
+static union irq_ctx *softirq_ctx[NR_CPUS];
+#endif
+
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+fastcall unsigned int do_IRQ(struct pt_regs *regs)
+{
+ /* high bits used in ret_from_ code */
+ int irq = regs->orig_eax & __IRQ_MASK(HARDIRQ_BITS);
+#ifdef CONFIG_4KSTACKS
+ union irq_ctx *curctx, *irqctx;
+ u32 *isp;
+#endif
+
+ irq_enter();
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+ /* Debugging check for stack overflow: is there less than 1KB free? */
+ {
+ long esp;
+
+ __asm__ __volatile__("andl %%esp,%0" :
+ "=r" (esp) : "0" (THREAD_SIZE - 1));
+ if (unlikely(esp < (sizeof(struct thread_info) + STACK_WARN))) {
+ printk("do_IRQ: stack overflow: %ld\n",
+ esp - sizeof(struct thread_info));
+ dump_stack();
+ }
+ }
+#endif
+
+#ifdef CONFIG_4KSTACKS
+
+ curctx = (union irq_ctx *) current_thread_info();
+ irqctx = hardirq_ctx[smp_processor_id()];
+
+ /*
+ * this is where we switch to the IRQ stack. However, if we are
+ * already using the IRQ stack (because we interrupted a hardirq
+ * handler) we can't do that and just have to keep using the
+ * current stack (which is the irq stack already after all)
+ */
+ if (curctx != irqctx) {
+ int arg1, arg2, ebx;
+
+ /* build the stack frame on the IRQ stack */
+ isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
+ irqctx->tinfo.task = curctx->tinfo.task;
+ irqctx->tinfo.previous_esp = current_stack_pointer;
+
+ asm volatile(
+ " xchgl %%ebx,%%esp \n"
+ " call __do_IRQ \n"
+ " movl %%ebx,%%esp \n"
+ : "=a" (arg1), "=d" (arg2), "=b" (ebx)
+ : "0" (irq), "1" (regs), "2" (isp)
+ : "memory", "cc", "ecx"
+ );
+ } else
+#endif
+ __do_IRQ(irq, regs);
+
+ irq_exit();
+
+ return 1;
+}
+
+#ifdef CONFIG_4KSTACKS
+
+/*
+ * These should really be __section__(".bss.page_aligned") as well, but
+ * gcc's 3.0 and earlier don't handle that correctly.
+ */
+static char softirq_stack[NR_CPUS * THREAD_SIZE]
+ __attribute__((__aligned__(THREAD_SIZE)));
+
+static char hardirq_stack[NR_CPUS * THREAD_SIZE]
+ __attribute__((__aligned__(THREAD_SIZE)));
+
+/*
+ * allocate per-cpu stacks for hardirq and for softirq processing
+ */
+void irq_ctx_init(int cpu)
+{
+ union irq_ctx *irqctx;
+
+ if (hardirq_ctx[cpu])
+ return;
+
+ irqctx = (union irq_ctx*) &hardirq_stack[cpu*THREAD_SIZE];
+ irqctx->tinfo.task = NULL;
+ irqctx->tinfo.exec_domain = NULL;
+ irqctx->tinfo.cpu = cpu;
+ irqctx->tinfo.preempt_count = HARDIRQ_OFFSET;
+ irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
+
+ hardirq_ctx[cpu] = irqctx;
+
+ irqctx = (union irq_ctx*) &softirq_stack[cpu*THREAD_SIZE];
+ irqctx->tinfo.task = NULL;
+ irqctx->tinfo.exec_domain = NULL;
+ irqctx->tinfo.cpu = cpu;
+ irqctx->tinfo.preempt_count = SOFTIRQ_OFFSET;
+ irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
+
+ softirq_ctx[cpu] = irqctx;
+
+ printk("CPU %u irqstacks, hard=%p soft=%p\n",
+ cpu,hardirq_ctx[cpu],softirq_ctx[cpu]);
+}
+
+extern asmlinkage void __do_softirq(void);
+
+asmlinkage void do_softirq(void)
+{
+ unsigned long flags;
+ struct thread_info *curctx;
+ union irq_ctx *irqctx;
+ u32 *isp;
+
+ if (in_interrupt())
+ return;
+
+ local_irq_save(flags);
+
+ if (local_softirq_pending()) {
+ curctx = current_thread_info();
+ irqctx = softirq_ctx[smp_processor_id()];
+ irqctx->tinfo.task = curctx->task;
+ irqctx->tinfo.previous_esp = current_stack_pointer;
+
+ /* build the stack frame on the softirq stack */
+ isp = (u32*) ((char*)irqctx + sizeof(*irqctx));
+
+ asm volatile(
+ " xchgl %%ebx,%%esp \n"
+ " call __do_softirq \n"
+ " movl %%ebx,%%esp \n"
+ : "=b"(isp)
+ : "0"(isp)
+ : "memory", "cc", "edx", "ecx", "eax"
+ );
+ }
+
+ local_irq_restore(flags);
+}
+
+EXPORT_SYMBOL(do_softirq);
+#endif
+
+/*
+ * Interrupt statistics:
+ */
+
+atomic_t irq_err_count;
+
+/*
+ * /proc/interrupts printing:
+ */
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+ int i = *(loff_t *) v, j;
+ struct irqaction * action;
+ unsigned long flags;
+
+ if (i == 0) {
+ seq_printf(p, " ");
+ for (j=0; j<NR_CPUS; j++)
+ if (cpu_online(j))
+ seq_printf(p, "CPU%d ",j);
+ seq_putc(p, '\n');
+ }
+
+ if (i < NR_IRQS) {
+ spin_lock_irqsave(&irq_desc[i].lock, flags);
+ action = irq_desc[i].action;
+ if (!action)
+ goto skip;
+ seq_printf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
+ seq_printf(p, "%10u ", kstat_irqs(i));
+#else
+ for (j = 0; j < NR_CPUS; j++)
+ if (cpu_online(j))
+ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+#endif
+ seq_printf(p, " %14s", irq_desc[i].handler->typename);
+ seq_printf(p, " %s", action->name);
+
+ for (action=action->next; action; action = action->next)
+ seq_printf(p, ", %s", action->name);
+
+ seq_putc(p, '\n');
+skip:
+ spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+ } else if (i == NR_IRQS) {
+ seq_printf(p, "NMI: ");
+ for (j = 0; j < NR_CPUS; j++)
+ if (cpu_online(j))
+ seq_printf(p, "%10u ", nmi_count(j));
+ seq_putc(p, '\n');
+#ifdef CONFIG_X86_LOCAL_APIC
+ seq_printf(p, "LOC: ");
+ for (j = 0; j < NR_CPUS; j++)
+ if (cpu_online(j))
+ seq_printf(p, "%10u ",
+ irq_stat[j].apic_timer_irqs);
+ seq_putc(p, '\n');
+#endif
+ seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+#if defined(CONFIG_X86_IO_APIC)
+ seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
+#endif
+ }
+ return 0;
+}
diff --git a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/process.c b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/process.c
index 5eaf9e384c..72789d4853 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/process.c
+++ b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/process.c
@@ -93,10 +93,11 @@ EXPORT_SYMBOL(enable_hlt);
extern int set_timeout_timer(void);
void xen_idle(void)
{
- int cpu = smp_processor_id();
+ int cpu;
local_irq_disable();
+ cpu = smp_processor_id();
if (rcu_pending(cpu))
rcu_check_callbacks(cpu, 0);
diff --git a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/setup.c b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/setup.c
index 852c556778..4ba19cf755 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/setup.c
+++ b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/setup.c
@@ -39,6 +39,7 @@
#include <linux/efi.h>
#include <linux/init.h>
#include <linux/edd.h>
+#include <linux/percpu.h>
#include <video/edid.h>
#include <asm/e820.h>
#include <asm/mpspec.h>
@@ -347,8 +348,8 @@ EXPORT_SYMBOL(HYPERVISOR_shared_info);
unsigned long *phys_to_machine_mapping, *pfn_to_mfn_frame_list;
EXPORT_SYMBOL(phys_to_machine_mapping);
-multicall_entry_t multicall_list[8];
-int nr_multicall_ents = 0;
+DEFINE_PER_CPU(multicall_entry_t, multicall_list[8]);
+DEFINE_PER_CPU(int, nr_multicall_ents);
/* Raw start-of-day parameters from the hypervisor. */
union xen_start_info_union xen_start_info_union;
diff --git a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/smp.c b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/smp.c
new file mode 100644
index 0000000000..9fabbfe043
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/smp.c
@@ -0,0 +1,599 @@
+/*
+ * Intel SMP support routines.
+ *
+ * (c) 1995 Alan Cox, Building #3 <alan@redhat.com>
+ * (c) 1998-99, 2000 Ingo Molnar <mingo@redhat.com>
+ *
+ * This code is released under the GNU General Public License version 2 or
+ * later.
+ */
+
+#include <linux/init.h>
+
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel_stat.h>
+#include <linux/mc146818rtc.h>
+#include <linux/cache.h>
+#include <linux/interrupt.h>
+
+#include <asm/mtrr.h>
+#include <asm/tlbflush.h>
+#if 0
+#include <mach_apic.h>
+#endif
+#include <asm-xen/evtchn.h>
+
+#define xxprint(msg) HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg), msg)
+
+/*
+ * Some notes on x86 processor bugs affecting SMP operation:
+ *
+ * Pentium, Pentium Pro, II, III (and all CPUs) have bugs.
+ * The Linux implications for SMP are handled as follows:
+ *
+ * Pentium III / [Xeon]
+ * None of the E1AP-E3AP errata are visible to the user.
+ *
+ * E1AP. see PII A1AP
+ * E2AP. see PII A2AP
+ * E3AP. see PII A3AP
+ *
+ * Pentium II / [Xeon]
+ * None of the A1AP-A3AP errata are visible to the user.
+ *
+ * A1AP. see PPro 1AP
+ * A2AP. see PPro 2AP
+ * A3AP. see PPro 7AP
+ *
+ * Pentium Pro
+ * None of 1AP-9AP errata are visible to the normal user,
+ * except occasional delivery of 'spurious interrupt' as trap #15.
+ * This is very rare and a non-problem.
+ *
+ * 1AP. Linux maps APIC as non-cacheable
+ * 2AP. worked around in hardware
+ * 3AP. fixed in C0 and above steppings microcode update.
+ * Linux does not use excessive STARTUP_IPIs.
+ * 4AP. worked around in hardware
+ * 5AP. symmetric IO mode (normal Linux operation) not affected.
+ * 'noapic' mode has vector 0xf filled out properly.
+ * 6AP. 'noapic' mode might be affected - fixed in later steppings
+ * 7AP. We do not assume writes to the LVT deassering IRQs
+ * 8AP. We do not enable low power mode (deep sleep) during MP bootup
+ * 9AP. We do not use mixed mode
+ *
+ * Pentium
+ * There is a marginal case where REP MOVS on 100MHz SMP
+ * machines with B stepping processors can fail. XXX should provide
+ * an L1cache=Writethrough or L1cache=off option.
+ *
+ * B stepping CPUs may hang. There are hardware work arounds
+ * for this. We warn about it in case your board doesn't have the work
+ * arounds. Basically thats so I can tell anyone with a B stepping
+ * CPU and SMP problems "tough".
+ *
+ * Specific items [From Pentium Processor Specification Update]
+ *
+ * 1AP. Linux doesn't use remote read
+ * 2AP. Linux doesn't trust APIC errors
+ * 3AP. We work around this
+ * 4AP. Linux never generated 3 interrupts of the same priority
+ * to cause a lost local interrupt.
+ * 5AP. Remote read is never used
+ * 6AP. not affected - worked around in hardware
+ * 7AP. not affected - worked around in hardware
+ * 8AP. worked around in hardware - we get explicit CS errors if not
+ * 9AP. only 'noapic' mode affected. Might generate spurious
+ * interrupts, we log only the first one and count the
+ * rest silently.
+ * 10AP. not affected - worked around in hardware
+ * 11AP. Linux reads the APIC between writes to avoid this, as per
+ * the documentation. Make sure you preserve this as it affects
+ * the C stepping chips too.
+ * 12AP. not affected - worked around in hardware
+ * 13AP. not affected - worked around in hardware
+ * 14AP. we always deassert INIT during bootup
+ * 15AP. not affected - worked around in hardware
+ * 16AP. not affected - worked around in hardware
+ * 17AP. not affected - worked around in hardware
+ * 18AP. not affected - worked around in hardware
+ * 19AP. not affected - worked around in BIOS
+ *
+ * If this sounds worrying believe me these bugs are either ___RARE___,
+ * or are signal timing bugs worked around in hardware and there's
+ * about nothing of note with C stepping upwards.
+ */
+
+DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) ____cacheline_aligned = { &init_mm, 0, };
+
+/*
+ * the following functions deal with sending IPIs between CPUs.
+ *
+ * We use 'broadcast', CPU->CPU IPIs and self-IPIs too.
+ */
+
+static inline int __prepare_ICR (unsigned int shortcut, int vector)
+{
+ return APIC_DM_FIXED | shortcut | vector | APIC_DEST_LOGICAL;
+}
+
+static inline int __prepare_ICR2 (unsigned int mask)
+{
+ return SET_APIC_DEST_FIELD(mask);
+}
+
+DECLARE_PER_CPU(int, ipi_to_evtchn[NR_IPIS]);
+
+static inline void __send_IPI_one(unsigned int cpu, int vector)
+{
+ unsigned int evtchn;
+
+ evtchn = per_cpu(ipi_to_evtchn, cpu)[vector];
+ // printk("send_IPI_mask_bitmask cpu %d vector %d evtchn %d\n", cpu, vector, evtchn);
+ if (evtchn) {
+#if 0
+ shared_info_t *s = HYPERVISOR_shared_info;
+ while (synch_test_bit(evtchn, &s->evtchn_pending[0]) ||
+ synch_test_bit(evtchn, &s->evtchn_mask[0]))
+ ;
+#endif
+ notify_via_evtchn(evtchn);
+ } else
+ printk("send_IPI to unbound port %d/%d",
+ cpu, vector);
+}
+
+void __send_IPI_shortcut(unsigned int shortcut, int vector)
+{
+ int cpu;
+
+ switch (shortcut) {
+ case APIC_DEST_SELF:
+ __send_IPI_one(smp_processor_id(), vector);
+ break;
+ case APIC_DEST_ALLBUT:
+ for (cpu = 0; cpu < NR_CPUS; ++cpu) {
+ if (cpu == smp_processor_id())
+ continue;
+ if (cpu_isset(cpu, cpu_online_map)) {
+ __send_IPI_one(cpu, vector);
+ }
+ }
+ break;
+ default:
+ printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut,
+ vector);
+ break;
+ }
+}
+
+void fastcall send_IPI_self(int vector)
+{
+ __send_IPI_shortcut(APIC_DEST_SELF, vector);
+}
+
+/*
+ * This is only used on smaller machines.
+ */
+void send_IPI_mask_bitmask(cpumask_t mask, int vector)
+{
+ unsigned long flags;
+ unsigned int cpu;
+
+ local_irq_save(flags);
+
+ for (cpu = 0; cpu < NR_CPUS; ++cpu) {
+ if (cpu_isset(cpu, mask)) {
+ __send_IPI_one(cpu, vector);
+ }
+ }
+
+ local_irq_restore(flags);
+}
+
+inline void send_IPI_mask_sequence(cpumask_t mask, int vector)
+{
+
+ send_IPI_mask_bitmask(mask, vector);
+}
+
+#include <mach_ipi.h> /* must come after the send_IPI functions above for inlining */
+
+/*
+ * Smarter SMP flushing macros.
+ * c/o Linus Torvalds.
+ *
+ * These mean you can really definitely utterly forget about
+ * writing to user space from interrupts. (Its not allowed anyway).
+ *
+ * Optimizations Manfred Spraul <manfred@colorfullife.com>
+ */
+
+static cpumask_t flush_cpumask;
+static struct mm_struct * flush_mm;
+static unsigned long flush_va;
+static spinlock_t tlbstate_lock = SPIN_LOCK_UNLOCKED;
+#define FLUSH_ALL 0xffffffff
+
+/*
+ * We cannot call mmdrop() because we are in interrupt context,
+ * instead update mm->cpu_vm_mask.
+ *
+ * We need to reload %cr3 since the page tables may be going
+ * away from under us..
+ */
+static inline void leave_mm (unsigned long cpu)
+{
+ if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK)
+ BUG();
+ cpu_clear(cpu, per_cpu(cpu_tlbstate, cpu).active_mm->cpu_vm_mask);
+ load_cr3(swapper_pg_dir);
+}
+
+/*
+ *
+ * The flush IPI assumes that a thread switch happens in this order:
+ * [cpu0: the cpu that switches]
+ * 1) switch_mm() either 1a) or 1b)
+ * 1a) thread switch to a different mm
+ * 1a1) cpu_clear(cpu, old_mm->cpu_vm_mask);
+ * Stop ipi delivery for the old mm. This is not synchronized with
+ * the other cpus, but smp_invalidate_interrupt ignore flush ipis
+ * for the wrong mm, and in the worst case we perform a superflous
+ * tlb flush.
+ * 1a2) set cpu_tlbstate to TLBSTATE_OK
+ * Now the smp_invalidate_interrupt won't call leave_mm if cpu0
+ * was in lazy tlb mode.
+ * 1a3) update cpu_tlbstate[].active_mm
+ * Now cpu0 accepts tlb flushes for the new mm.
+ * 1a4) cpu_set(cpu, new_mm->cpu_vm_mask);
+ * Now the other cpus will send tlb flush ipis.
+ * 1a4) change cr3.
+ * 1b) thread switch without mm change
+ * cpu_tlbstate[].active_mm is correct, cpu0 already handles
+ * flush ipis.
+ * 1b1) set cpu_tlbstate to TLBSTATE_OK
+ * 1b2) test_and_set the cpu bit in cpu_vm_mask.
+ * Atomically set the bit [other cpus will start sending flush ipis],
+ * and test the bit.
+ * 1b3) if the bit was 0: leave_mm was called, flush the tlb.
+ * 2) switch %%esp, ie current
+ *
+ * The interrupt must handle 2 special cases:
+ * - cr3 is changed before %%esp, ie. it cannot use current->{active_,}mm.
+ * - the cpu performs speculative tlb reads, i.e. even if the cpu only
+ * runs in kernel space, the cpu could load tlb entries for user space
+ * pages.
+ *
+ * The good news is that cpu_tlbstate is local to each cpu, no
+ * write/read ordering problems.
+ */
+
+/*
+ * TLB flush IPI:
+ *
+ * 1) Flush the tlb entries if the cpu uses the mm that's being flushed.
+ * 2) Leave the mm if we are in the lazy tlb mode.
+ */
+
+irqreturn_t smp_invalidate_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ unsigned long cpu;
+
+ cpu = get_cpu();
+
+ if (!cpu_isset(cpu, flush_cpumask))
+ goto out;
+ /*
+ * This was a BUG() but until someone can quote me the
+ * line from the intel manual that guarantees an IPI to
+ * multiple CPUs is retried _only_ on the erroring CPUs
+ * its staying as a return
+ *
+ * BUG();
+ */
+
+ if (flush_mm == per_cpu(cpu_tlbstate, cpu).active_mm) {
+ if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_OK) {
+ if (flush_va == FLUSH_ALL)
+ local_flush_tlb();
+ else
+ __flush_tlb_one(flush_va);
+ } else
+ leave_mm(cpu);
+ }
+ smp_mb__before_clear_bit();
+ cpu_clear(cpu, flush_cpumask);
+ smp_mb__after_clear_bit();
+out:
+ put_cpu_no_resched();
+
+ return IRQ_HANDLED;
+}
+
+static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
+ unsigned long va)
+{
+ cpumask_t tmp;
+ /*
+ * A couple of (to be removed) sanity checks:
+ *
+ * - we do not send IPIs to not-yet booted CPUs.
+ * - current CPU must not be in mask
+ * - mask must exist :)
+ */
+ BUG_ON(cpus_empty(cpumask));
+
+ cpus_and(tmp, cpumask, cpu_online_map);
+ BUG_ON(!cpus_equal(cpumask, tmp));
+ BUG_ON(cpu_isset(smp_processor_id(), cpumask));
+ BUG_ON(!mm);
+
+ /*
+ * i'm not happy about this global shared spinlock in the
+ * MM hot path, but we'll see how contended it is.
+ * Temporarily this turns IRQs off, so that lockups are
+ * detected by the NMI watchdog.
+ */
+ spin_lock(&tlbstate_lock);
+
+ flush_mm = mm;
+ flush_va = va;
+#if NR_CPUS <= BITS_PER_LONG
+ atomic_set_mask(cpumask, &flush_cpumask);
+#else
+ {
+ int k;
+ unsigned long *flush_mask = (unsigned long *)&flush_cpumask;
+ unsigned long *cpu_mask = (unsigned long *)&cpumask;
+ for (k = 0; k < BITS_TO_LONGS(NR_CPUS); ++k)
+ atomic_set_mask(cpu_mask[k], &flush_mask[k]);
+ }
+#endif
+ /*
+ * We have to send the IPI only to
+ * CPUs affected.
+ */
+ send_IPI_mask(cpumask, INVALIDATE_TLB_VECTOR);
+
+ while (!cpus_empty(flush_cpumask))
+ /* nothing. lockup detection does not belong here */
+ mb();
+
+ flush_mm = NULL;
+ flush_va = 0;
+ spin_unlock(&tlbstate_lock);
+}
+
+void flush_tlb_current_task(void)
+{
+ struct mm_struct *mm = current->mm;
+ cpumask_t cpu_mask;
+
+ preempt_disable();
+ cpu_mask = mm->cpu_vm_mask;
+ cpu_clear(smp_processor_id(), cpu_mask);
+
+ local_flush_tlb();
+ if (!cpus_empty(cpu_mask))
+ flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+ preempt_enable();
+}
+
+void flush_tlb_mm (struct mm_struct * mm)
+{
+ cpumask_t cpu_mask;
+
+ preempt_disable();
+ cpu_mask = mm->cpu_vm_mask;
+ cpu_clear(smp_processor_id(), cpu_mask);
+
+ if (current->active_mm == mm) {
+ if (current->mm)
+ local_flush_tlb();
+ else
+ leave_mm(smp_processor_id());
+ }
+ if (!cpus_empty(cpu_mask))
+ flush_tlb_others(cpu_mask, mm, FLUSH_ALL);
+
+ preempt_enable();
+}
+
+void flush_tlb_page(struct vm_area_struct * vma, unsigned long va)
+{
+ struct mm_struct *mm = vma->vm_mm;
+ cpumask_t cpu_mask;
+
+ preempt_disable();
+ cpu_mask = mm->cpu_vm_mask;
+ cpu_clear(smp_processor_id(), cpu_mask);
+
+ if (current->active_mm == mm) {
+ if(current->mm)
+ __flush_tlb_one(va);
+ else
+ leave_mm(smp_processor_id());
+ }
+
+ if (!cpus_empty(cpu_mask))
+ flush_tlb_others(cpu_mask, mm, va);
+
+ preempt_enable();
+}
+
+static void do_flush_tlb_all(void* info)
+{
+ unsigned long cpu = smp_processor_id();
+
+ __flush_tlb_all();
+ if (per_cpu(cpu_tlbstate, cpu).state == TLBSTATE_LAZY)
+ leave_mm(cpu);
+}
+
+void flush_tlb_all(void)
+{
+ on_each_cpu(do_flush_tlb_all, NULL, 1, 1);
+}
+
+/*
+ * this function sends a 'reschedule' IPI to another CPU.
+ * it goes straight through and wastes no time serializing
+ * anything. Worst case is that we lose a reschedule ...
+ */
+void smp_send_reschedule(int cpu)
+{
+ send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
+}
+
+/*
+ * Structure and data for smp_call_function(). This is designed to minimise
+ * static memory requirements. It also looks cleaner.
+ */
+static spinlock_t call_lock = SPIN_LOCK_UNLOCKED;
+
+struct call_data_struct {
+ void (*func) (void *info);
+ void *info;
+ atomic_t started;
+ atomic_t finished;
+ int wait;
+};
+
+static struct call_data_struct * call_data;
+
+/*
+ * this function sends a 'generic call function' IPI to all other CPUs
+ * in the system.
+ */
+
+int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
+ int wait)
+/*
+ * [SUMMARY] Run a function on all other CPUs.
+ * <func> The function to run. This must be fast and non-blocking.
+ * <info> An arbitrary pointer to pass to the function.
+ * <nonatomic> currently unused.
+ * <wait> If true, wait (atomically) until function has completed on other CPUs.
+ * [RETURNS] 0 on success, else a negative status code. Does not return until
+ * remote CPUs are nearly ready to execute <<func>> or are or have executed.
+ *
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler or from a bottom half handler.
+ */
+{
+ struct call_data_struct data;
+ int cpus = num_online_cpus()-1;
+
+ if (!cpus)
+ return 0;
+
+ /* Can deadlock when called with interrupts disabled */
+ WARN_ON(irqs_disabled());
+
+ data.func = func;
+ data.info = info;
+ atomic_set(&data.started, 0);
+ data.wait = wait;
+ if (wait)
+ atomic_set(&data.finished, 0);
+
+ spin_lock(&call_lock);
+ call_data = &data;
+ mb();
+
+ /* Send a message to all other CPUs and wait for them to respond */
+ send_IPI_allbutself(CALL_FUNCTION_VECTOR);
+
+ /* Wait for response */
+ while (atomic_read(&data.started) != cpus)
+ barrier();
+
+ if (wait)
+ while (atomic_read(&data.finished) != cpus)
+ barrier();
+ spin_unlock(&call_lock);
+
+ return 0;
+}
+
+static void stop_this_cpu (void * dummy)
+{
+ /*
+ * Remove this CPU:
+ */
+ cpu_clear(smp_processor_id(), cpu_online_map);
+ local_irq_disable();
+#if 1
+ xxprint("stop_this_cpu disable_local_APIC\n");
+#else
+ disable_local_APIC();
+#endif
+ if (cpu_data[smp_processor_id()].hlt_works_ok)
+ for(;;) __asm__("hlt");
+ for (;;);
+}
+
+/*
+ * this function calls the 'stop' function on all other CPUs in the system.
+ */
+
+void smp_send_stop(void)
+{
+ smp_call_function(stop_this_cpu, NULL, 1, 0);
+
+ local_irq_disable();
+#if 1
+ xxprint("smp_send_stop disable_local_APIC\n");
+#else
+ disable_local_APIC();
+#endif
+ local_irq_enable();
+}
+
+/*
+ * Reschedule call back. Nothing to do,
+ * all the work is done automatically when
+ * we return from the interrupt.
+ */
+irqreturn_t smp_reschedule_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+
+ return IRQ_HANDLED;
+}
+
+#include <linux/kallsyms.h>
+irqreturn_t smp_call_function_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ void (*func) (void *info) = call_data->func;
+ void *info = call_data->info;
+ int wait = call_data->wait;
+
+ /*
+ * Notify initiating CPU that I've grabbed the data and am
+ * about to execute the function
+ */
+ mb();
+ atomic_inc(&call_data->started);
+ /*
+ * At this point the info structure may be out of scope unless wait==1
+ */
+ irq_enter();
+ (*func)(info);
+ irq_exit();
+
+ if (wait) {
+ mb();
+ atomic_inc(&call_data->finished);
+ }
+
+ return IRQ_HANDLED;
+}
+
diff --git a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/smpboot.c b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/smpboot.c
new file mode 100644
index 0000000000..a9bb0e201b
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/smpboot.c
@@ -0,0 +1,1364 @@
+/*
+ * x86 SMP booting functions
+ *
+ * (c) 1995 Alan Cox, Building #3 <alan@redhat.com>
+ * (c) 1998, 1999, 2000 Ingo Molnar <mingo@redhat.com>
+ *
+ * Much of the core SMP work is based on previous work by Thomas Radke, to
+ * whom a great many thanks are extended.
+ *
+ * Thanks to Intel for making available several different Pentium,
+ * Pentium Pro and Pentium-II/Xeon MP machines.
+ * Original development of Linux SMP code supported by Caldera.
+ *
+ * This code is released under the GNU General Public License version 2 or
+ * later.
+ *
+ * Fixes
+ * Felix Koop : NR_CPUS used properly
+ * Jose Renau : Handle single CPU case.
+ * Alan Cox : By repeated request 8) - Total BogoMIPS report.
+ * Greg Wright : Fix for kernel stacks panic.
+ * Erich Boleyn : MP v1.4 and additional changes.
+ * Matthias Sattler : Changes for 2.1 kernel map.
+ * Michel Lespinasse : Changes for 2.1 kernel map.
+ * Michael Chastain : Change trampoline.S to gnu as.
+ * Alan Cox : Dumb bug: 'B' step PPro's are fine
+ * Ingo Molnar : Added APIC timers, based on code
+ * from Jose Renau
+ * Ingo Molnar : various cleanups and rewrites
+ * Tigran Aivazian : fixed "0.00 in /proc/uptime on SMP" bug.
+ * Maciej W. Rozycki : Bits for genuine 82489DX APICs
+ * Martin J. Bligh : Added support for multi-quad systems
+ * Dave Jones : Report invalid combinations of Athlon CPUs.
+* Rusty Russell : Hacked into shape for new "hotplug" boot process. */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/smp_lock.h>
+#include <linux/irq.h>
+#include <linux/bootmem.h>
+
+#include <linux/delay.h>
+#include <linux/mc146818rtc.h>
+#include <asm/tlbflush.h>
+#include <asm/desc.h>
+#include <asm/arch_hooks.h>
+
+#if 1
+#define Dprintk(args...)
+#else
+#include <mach_apic.h>
+#endif
+#include <mach_wakecpu.h>
+#include <smpboot_hooks.h>
+
+/* Set if we find a B stepping CPU */
+static int __initdata smp_b_stepping;
+
+/* Number of siblings per CPU package */
+int smp_num_siblings = 1;
+int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
+
+/* bitmap of online cpus */
+cpumask_t cpu_online_map;
+
+static cpumask_t cpu_callin_map;
+cpumask_t cpu_callout_map;
+static cpumask_t smp_commenced_mask;
+
+/* Per CPU bogomips and other parameters */
+struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
+
+u8 x86_cpu_to_apicid[NR_CPUS] =
+ { [0 ... NR_CPUS-1] = 0xff };
+EXPORT_SYMBOL(x86_cpu_to_apicid);
+
+/* Set when the idlers are all forked */
+int smp_threads_ready;
+
+#if 0
+/*
+ * Trampoline 80x86 program as an array.
+ */
+
+extern unsigned char trampoline_data [];
+extern unsigned char trampoline_end [];
+static unsigned char *trampoline_base;
+static int trampoline_exec;
+
+/*
+ * Currently trivial. Write the real->protected mode
+ * bootstrap into the page concerned. The caller
+ * has made sure it's suitably aligned.
+ */
+
+static unsigned long __init setup_trampoline(void)
+{
+ memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data);
+ return virt_to_phys(trampoline_base);
+}
+#endif
+
+/*
+ * We are called very early to get the low memory for the
+ * SMP bootup trampoline page.
+ */
+void __init smp_alloc_memory(void)
+{
+#if 1
+ int cpu;
+
+ for (cpu = 1; cpu < NR_CPUS; cpu++) {
+ cpu_gdt_descr[cpu].address = (unsigned long)
+ alloc_bootmem_low_pages(PAGE_SIZE);
+ /* XXX free unused pages later */
+ }
+#else
+ trampoline_base = (void *) alloc_bootmem_low_pages(PAGE_SIZE);
+ /*
+ * Has to be in very low memory so we can execute
+ * real-mode AP code.
+ */
+ if (__pa(trampoline_base) >= 0x9F000)
+ BUG();
+ /*
+ * Make the SMP trampoline executable:
+ */
+ trampoline_exec = set_kernel_exec((unsigned long)trampoline_base, 1);
+#endif
+}
+
+/*
+ * The bootstrap kernel entry code has set these up. Save them for
+ * a given CPU
+ */
+
+static void __init smp_store_cpu_info(int id)
+{
+ struct cpuinfo_x86 *c = cpu_data + id;
+
+ *c = boot_cpu_data;
+ if (id!=0)
+ identify_cpu(c);
+ /*
+ * Mask B, Pentium, but not Pentium MMX
+ */
+ if (c->x86_vendor == X86_VENDOR_INTEL &&
+ c->x86 == 5 &&
+ c->x86_mask >= 1 && c->x86_mask <= 4 &&
+ c->x86_model <= 3)
+ /*
+ * Remember we have B step Pentia with bugs
+ */
+ smp_b_stepping = 1;
+
+ /*
+ * Certain Athlons might work (for various values of 'work') in SMP
+ * but they are not certified as MP capable.
+ */
+ if ((c->x86_vendor == X86_VENDOR_AMD) && (c->x86 == 6)) {
+
+ /* Athlon 660/661 is valid. */
+ if ((c->x86_model==6) && ((c->x86_mask==0) || (c->x86_mask==1)))
+ goto valid_k7;
+
+ /* Duron 670 is valid */
+ if ((c->x86_model==7) && (c->x86_mask==0))
+ goto valid_k7;
+
+ /*
+ * Athlon 662, Duron 671, and Athlon >model 7 have capability bit.
+ * It's worth noting that the A5 stepping (662) of some Athlon XP's
+ * have the MP bit set.
+ * See http://www.heise.de/newsticker/data/jow-18.10.01-000 for more.
+ */
+ if (((c->x86_model==6) && (c->x86_mask>=2)) ||
+ ((c->x86_model==7) && (c->x86_mask>=1)) ||
+ (c->x86_model> 7))
+ if (cpu_has_mp)
+ goto valid_k7;
+
+ /* If we get here, it's not a certified SMP capable AMD system. */
+ tainted |= TAINT_UNSAFE_SMP;
+ }
+
+valid_k7:
+ ;
+}
+
+#if 0
+/*
+ * TSC synchronization.
+ *
+ * We first check whether all CPUs have their TSC's synchronized,
+ * then we print a warning if not, and always resync.
+ */
+
+static atomic_t tsc_start_flag = ATOMIC_INIT(0);
+static atomic_t tsc_count_start = ATOMIC_INIT(0);
+static atomic_t tsc_count_stop = ATOMIC_INIT(0);
+static unsigned long long tsc_values[NR_CPUS];
+
+#define NR_LOOPS 5
+
+static void __init synchronize_tsc_bp (void)
+{
+ int i;
+ unsigned long long t0;
+ unsigned long long sum, avg;
+ long long delta;
+ unsigned long one_usec;
+ int buggy = 0;
+
+ printk(KERN_INFO "checking TSC synchronization across %u CPUs: ", num_booting_cpus());
+
+ /* convert from kcyc/sec to cyc/usec */
+ one_usec = cpu_khz / 1000;
+
+ atomic_set(&tsc_start_flag, 1);
+ wmb();
+
+ /*
+ * We loop a few times to get a primed instruction cache,
+ * then the last pass is more or less synchronized and
+ * the BP and APs set their cycle counters to zero all at
+ * once. This reduces the chance of having random offsets
+ * between the processors, and guarantees that the maximum
+ * delay between the cycle counters is never bigger than
+ * the latency of information-passing (cachelines) between
+ * two CPUs.
+ */
+ for (i = 0; i < NR_LOOPS; i++) {
+ /*
+ * all APs synchronize but they loop on '== num_cpus'
+ */
+ while (atomic_read(&tsc_count_start) != num_booting_cpus()-1)
+ mb();
+ atomic_set(&tsc_count_stop, 0);
+ wmb();
+ /*
+ * this lets the APs save their current TSC:
+ */
+ atomic_inc(&tsc_count_start);
+
+ rdtscll(tsc_values[smp_processor_id()]);
+ /*
+ * We clear the TSC in the last loop:
+ */
+ if (i == NR_LOOPS-1)
+ write_tsc(0, 0);
+
+ /*
+ * Wait for all APs to leave the synchronization point:
+ */
+ while (atomic_read(&tsc_count_stop) != num_booting_cpus()-1)
+ mb();
+ atomic_set(&tsc_count_start, 0);
+ wmb();
+ atomic_inc(&tsc_count_stop);
+ }
+
+ sum = 0;
+ for (i = 0; i < NR_CPUS; i++) {
+ if (cpu_isset(i, cpu_callout_map)) {
+ t0 = tsc_values[i];
+ sum += t0;
+ }
+ }
+ avg = sum;
+ do_div(avg, num_booting_cpus());
+
+ sum = 0;
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!cpu_isset(i, cpu_callout_map))
+ continue;
+ delta = tsc_values[i] - avg;
+ if (delta < 0)
+ delta = -delta;
+ /*
+ * We report bigger than 2 microseconds clock differences.
+ */
+ if (delta > 2*one_usec) {
+ long realdelta;
+ if (!buggy) {
+ buggy = 1;
+ printk("\n");
+ }
+ realdelta = delta;
+ do_div(realdelta, one_usec);
+ if (tsc_values[i] < avg)
+ realdelta = -realdelta;
+
+ printk(KERN_INFO "CPU#%d had %ld usecs TSC skew, fixed it up.\n", i, realdelta);
+ }
+
+ sum += delta;
+ }
+ if (!buggy)
+ printk("passed.\n");
+}
+
+static void __init synchronize_tsc_ap (void)
+{
+ int i;
+
+ /*
+ * Not every cpu is online at the time
+ * this gets called, so we first wait for the BP to
+ * finish SMP initialization:
+ */
+ while (!atomic_read(&tsc_start_flag)) mb();
+
+ for (i = 0; i < NR_LOOPS; i++) {
+ atomic_inc(&tsc_count_start);
+ while (atomic_read(&tsc_count_start) != num_booting_cpus())
+ mb();
+
+ rdtscll(tsc_values[smp_processor_id()]);
+ if (i == NR_LOOPS-1)
+ write_tsc(0, 0);
+
+ atomic_inc(&tsc_count_stop);
+ while (atomic_read(&tsc_count_stop) != num_booting_cpus()) mb();
+ }
+}
+#undef NR_LOOPS
+#endif
+
+extern void calibrate_delay(void);
+
+static atomic_t init_deasserted;
+
+void __init smp_callin(void)
+{
+ int cpuid, phys_id;
+ unsigned long timeout;
+
+#if 0
+ /*
+ * If waken up by an INIT in an 82489DX configuration
+ * we may get here before an INIT-deassert IPI reaches
+ * our local APIC. We have to wait for the IPI or we'll
+ * lock up on an APIC access.
+ */
+ wait_for_init_deassert(&init_deasserted);
+#endif
+
+ /*
+ * (This works even if the APIC is not enabled.)
+ */
+ phys_id = smp_processor_id();
+ cpuid = smp_processor_id();
+ if (cpu_isset(cpuid, cpu_callin_map)) {
+ printk("huh, phys CPU#%d, CPU#%d already present??\n",
+ phys_id, cpuid);
+ BUG();
+ }
+ Dprintk("CPU#%d (phys ID: %d) waiting for CALLOUT\n", cpuid, phys_id);
+
+ /*
+ * STARTUP IPIs are fragile beasts as they might sometimes
+ * trigger some glue motherboard logic. Complete APIC bus
+ * silence for 1 second, this overestimates the time the
+ * boot CPU is spending to send the up to 2 STARTUP IPIs
+ * by a factor of two. This should be enough.
+ */
+
+ /*
+ * Waiting 2s total for startup (udelay is not yet working)
+ */
+ timeout = jiffies + 2*HZ;
+ while (time_before(jiffies, timeout)) {
+ /*
+ * Has the boot CPU finished it's STARTUP sequence?
+ */
+ if (cpu_isset(cpuid, cpu_callout_map))
+ break;
+ rep_nop();
+ }
+
+ if (!time_before(jiffies, timeout)) {
+ printk("BUG: CPU%d started up but did not get a callout!\n",
+ cpuid);
+ BUG();
+ }
+
+#if 0
+ /*
+ * the boot CPU has finished the init stage and is spinning
+ * on callin_map until we finish. We are free to set up this
+ * CPU, first the APIC. (this is probably redundant on most
+ * boards)
+ */
+
+ Dprintk("CALLIN, before setup_local_APIC().\n");
+ smp_callin_clear_local_apic();
+ setup_local_APIC();
+#endif
+ map_cpu_to_logical_apicid();
+
+ local_irq_enable();
+
+ /*
+ * Get our bogomips.
+ */
+ calibrate_delay();
+ Dprintk("Stack at about %p\n",&cpuid);
+
+ /*
+ * Save our processor parameters
+ */
+ smp_store_cpu_info(cpuid);
+
+#if 0
+ disable_APIC_timer();
+#endif
+ local_irq_disable();
+ /*
+ * Allow the master to continue.
+ */
+ cpu_set(cpuid, cpu_callin_map);
+
+#if 0
+ /*
+ * Synchronize the TSC with the BP
+ */
+ if (cpu_has_tsc && cpu_khz)
+ synchronize_tsc_ap();
+#endif
+}
+
+int cpucount;
+
+extern int cpu_idle(void);
+
+
+static irqreturn_t local_debug_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction local_irq_debug = {
+ local_debug_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "ldebug",
+ NULL, NULL
+};
+
+void local_setup_debug(void)
+{
+ (void)setup_irq(bind_virq_to_irq(VIRQ_DEBUG), &local_irq_debug);
+}
+
+
+extern void local_setup_timer(void);
+
+/*
+ * Activate a secondary processor.
+ */
+int __init start_secondary(void *unused)
+{
+ /*
+ * Dont put anything before smp_callin(), SMP
+ * booting is too fragile that we want to limit the
+ * things done here to the most necessary things.
+ */
+ cpu_init();
+ smp_callin();
+ while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
+ rep_nop();
+ local_setup_timer();
+ local_setup_debug(); /* XXX */
+ smp_intr_init();
+ local_irq_enable();
+ /*
+ * low-memory mappings have been cleared, flush them from
+ * the local TLBs too.
+ */
+ local_flush_tlb();
+ cpu_set(smp_processor_id(), cpu_online_map);
+ wmb();
+ if (0) {
+ char *msg2 = "delay2\n";
+ int timeout;
+ for (timeout = 0; timeout < 50000; timeout++) {
+ udelay(1000);
+ if (timeout == 2000) {
+ (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg2), msg2);
+ timeout = 0;
+ }
+ }
+ }
+ return cpu_idle();
+}
+
+/*
+ * Everything has been set up for the secondary
+ * CPUs - they just need to reload everything
+ * from the task structure
+ * This function must not return.
+ */
+void __init initialize_secondary(void)
+{
+ /*
+ * We don't actually need to load the full TSS,
+ * basically just the stack pointer and the eip.
+ */
+
+ asm volatile(
+ "movl %0,%%esp\n\t"
+ "jmp *%1"
+ :
+ :"r" (current->thread.esp),"r" (current->thread.eip));
+}
+
+extern struct {
+ void * esp;
+ unsigned short ss;
+} stack_start;
+
+#ifdef CONFIG_NUMA
+
+/* which logical CPUs are on which nodes */
+cpumask_t node_2_cpu_mask[MAX_NUMNODES] =
+ { [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE };
+/* which node each logical CPU is on */
+int cpu_2_node[NR_CPUS] = { [0 ... NR_CPUS-1] = 0 };
+EXPORT_SYMBOL(cpu_2_node);
+
+/* set up a mapping between cpu and node. */
+static inline void map_cpu_to_node(int cpu, int node)
+{
+ printk("Mapping cpu %d to node %d\n", cpu, node);
+ cpu_set(cpu, node_2_cpu_mask[node]);
+ cpu_2_node[cpu] = node;
+}
+
+/* undo a mapping between cpu and node. */
+static inline void unmap_cpu_to_node(int cpu)
+{
+ int node;
+
+ printk("Unmapping cpu %d from all nodes\n", cpu);
+ for (node = 0; node < MAX_NUMNODES; node ++)
+ cpu_clear(cpu, node_2_cpu_mask[node]);
+ cpu_2_node[cpu] = 0;
+}
+#else /* !CONFIG_NUMA */
+
+#define map_cpu_to_node(cpu, node) ({})
+#define unmap_cpu_to_node(cpu) ({})
+
+#endif /* CONFIG_NUMA */
+
+u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
+
+void map_cpu_to_logical_apicid(void)
+{
+ int cpu = smp_processor_id();
+ int apicid = smp_processor_id();
+
+ cpu_2_logical_apicid[cpu] = apicid;
+ map_cpu_to_node(cpu, apicid_to_node(apicid));
+}
+
+void unmap_cpu_to_logical_apicid(int cpu)
+{
+ cpu_2_logical_apicid[cpu] = BAD_APICID;
+ unmap_cpu_to_node(cpu);
+}
+
+#if APIC_DEBUG
+static inline void __inquire_remote_apic(int apicid)
+{
+ int i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
+ char *names[] = { "ID", "VERSION", "SPIV" };
+ int timeout, status;
+
+ printk("Inquiring remote APIC #%d...\n", apicid);
+
+ for (i = 0; i < sizeof(regs) / sizeof(*regs); i++) {
+ printk("... APIC #%d %s: ", apicid, names[i]);
+
+ /*
+ * Wait for idle.
+ */
+ apic_wait_icr_idle();
+
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(apicid));
+ apic_write_around(APIC_ICR, APIC_DM_REMRD | regs[i]);
+
+ timeout = 0;
+ do {
+ udelay(100);
+ status = apic_read(APIC_ICR) & APIC_ICR_RR_MASK;
+ } while (status == APIC_ICR_RR_INPROG && timeout++ < 1000);
+
+ switch (status) {
+ case APIC_ICR_RR_VALID:
+ status = apic_read(APIC_RRR);
+ printk("%08x\n", status);
+ break;
+ default:
+ printk("failed\n");
+ }
+ }
+}
+#endif
+
+#if 0
+#ifdef WAKE_SECONDARY_VIA_NMI
+/*
+ * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal
+ * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
+ * won't ... remember to clear down the APIC, etc later.
+ */
+static int __init
+wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
+{
+ unsigned long send_status = 0, accept_status = 0;
+ int timeout, maxlvt;
+
+ /* Target chip */
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(logical_apicid));
+
+ /* Boot on the stack */
+ /* Kick the second */
+ apic_write_around(APIC_ICR, APIC_DM_NMI | APIC_DEST_LOGICAL);
+
+ Dprintk("Waiting for send to finish...\n");
+ timeout = 0;
+ do {
+ Dprintk("+");
+ udelay(100);
+ send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+ } while (send_status && (timeout++ < 1000));
+
+ /*
+ * Give the other CPU some time to accept the IPI.
+ */
+ udelay(200);
+ /*
+ * Due to the Pentium erratum 3AP.
+ */
+ maxlvt = get_maxlvt();
+ if (maxlvt > 3) {
+ apic_read_around(APIC_SPIV);
+ apic_write(APIC_ESR, 0);
+ }
+ accept_status = (apic_read(APIC_ESR) & 0xEF);
+ Dprintk("NMI sent.\n");
+
+ if (send_status)
+ printk("APIC never delivered???\n");
+ if (accept_status)
+ printk("APIC delivery error (%lx).\n", accept_status);
+
+ return (send_status | accept_status);
+}
+#endif /* WAKE_SECONDARY_VIA_NMI */
+
+#ifdef WAKE_SECONDARY_VIA_INIT
+static int __init
+wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
+{
+ unsigned long send_status = 0, accept_status = 0;
+ int maxlvt, timeout, num_starts, j;
+
+ /*
+ * Be paranoid about clearing APIC errors.
+ */
+ if (APIC_INTEGRATED(apic_version[phys_apicid])) {
+ apic_read_around(APIC_SPIV);
+ apic_write(APIC_ESR, 0);
+ apic_read(APIC_ESR);
+ }
+
+ Dprintk("Asserting INIT.\n");
+
+ /*
+ * Turn INIT on target chip
+ */
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
+
+ /*
+ * Send IPI
+ */
+ apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_INT_ASSERT
+ | APIC_DM_INIT);
+
+ Dprintk("Waiting for send to finish...\n");
+ timeout = 0;
+ do {
+ Dprintk("+");
+ udelay(100);
+ send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+ } while (send_status && (timeout++ < 1000));
+
+ mdelay(10);
+
+ Dprintk("Deasserting INIT.\n");
+
+ /* Target chip */
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
+
+ /* Send IPI */
+ apic_write_around(APIC_ICR, APIC_INT_LEVELTRIG | APIC_DM_INIT);
+
+ Dprintk("Waiting for send to finish...\n");
+ timeout = 0;
+ do {
+ Dprintk("+");
+ udelay(100);
+ send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+ } while (send_status && (timeout++ < 1000));
+
+ atomic_set(&init_deasserted, 1);
+
+ /*
+ * Should we send STARTUP IPIs ?
+ *
+ * Determine this based on the APIC version.
+ * If we don't have an integrated APIC, don't send the STARTUP IPIs.
+ */
+ if (APIC_INTEGRATED(apic_version[phys_apicid]))
+ num_starts = 2;
+ else
+ num_starts = 0;
+
+ /*
+ * Run STARTUP IPI loop.
+ */
+ Dprintk("#startup loops: %d.\n", num_starts);
+
+ maxlvt = get_maxlvt();
+
+ for (j = 1; j <= num_starts; j++) {
+ Dprintk("Sending STARTUP #%d.\n",j);
+ apic_read_around(APIC_SPIV);
+ apic_write(APIC_ESR, 0);
+ apic_read(APIC_ESR);
+ Dprintk("After apic_write.\n");
+
+ /*
+ * STARTUP IPI
+ */
+
+ /* Target chip */
+ apic_write_around(APIC_ICR2, SET_APIC_DEST_FIELD(phys_apicid));
+
+ /* Boot on the stack */
+ /* Kick the second */
+ apic_write_around(APIC_ICR, APIC_DM_STARTUP
+ | (start_eip >> 12));
+
+ /*
+ * Give the other CPU some time to accept the IPI.
+ */
+ udelay(300);
+
+ Dprintk("Startup point 1.\n");
+
+ Dprintk("Waiting for send to finish...\n");
+ timeout = 0;
+ do {
+ Dprintk("+");
+ udelay(100);
+ send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+ } while (send_status && (timeout++ < 1000));
+
+ /*
+ * Give the other CPU some time to accept the IPI.
+ */
+ udelay(200);
+ /*
+ * Due to the Pentium erratum 3AP.
+ */
+ if (maxlvt > 3) {
+ apic_read_around(APIC_SPIV);
+ apic_write(APIC_ESR, 0);
+ }
+ accept_status = (apic_read(APIC_ESR) & 0xEF);
+ if (send_status || accept_status)
+ break;
+ }
+ Dprintk("After Startup.\n");
+
+ if (send_status)
+ printk("APIC never delivered???\n");
+ if (accept_status)
+ printk("APIC delivery error (%lx).\n", accept_status);
+
+ return (send_status | accept_status);
+}
+#endif /* WAKE_SECONDARY_VIA_INIT */
+#endif
+
+extern cpumask_t cpu_initialized;
+
+static int __init do_boot_cpu(int apicid)
+/*
+ * NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
+ * (ie clustered apic addressing mode), this is a LOGICAL apic ID.
+ * Returns zero if CPU booted OK, else error code from wakeup_secondary_cpu.
+ */
+{
+ struct task_struct *idle;
+ unsigned long boot_error;
+ int timeout, cpu;
+ unsigned long start_eip;
+#if 0
+ unsigned short nmi_high = 0, nmi_low = 0;
+#endif
+ full_execution_context_t ctxt;
+ extern void startup_32_smp(void);
+ extern void hypervisor_callback(void);
+ extern void failsafe_callback(void);
+ extern int smp_trap_init(trap_info_t *);
+ int i;
+
+ cpu = ++cpucount;
+ /*
+ * We can't use kernel_thread since we must avoid to
+ * reschedule the child.
+ */
+ idle = fork_idle(cpu);
+ if (IS_ERR(idle))
+ panic("failed fork for CPU %d", cpu);
+ idle->thread.eip = (unsigned long) start_secondary;
+ /* start_eip had better be page-aligned! */
+ start_eip = (unsigned long)startup_32_smp;
+
+ /* So we see what's up */
+ printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip);
+ /* Stack for startup_32 can be just as for start_secondary onwards */
+ stack_start.esp = (void *) idle->thread.esp;
+
+ irq_ctx_init(cpu);
+
+ /*
+ * This grunge runs the startup process for
+ * the targeted processor.
+ */
+
+ atomic_set(&init_deasserted, 0);
+
+#if 1
+ if (cpu_gdt_descr[0].size > PAGE_SIZE)
+ BUG();
+ cpu_gdt_descr[cpu].size = cpu_gdt_descr[0].size;
+ memcpy((void *)cpu_gdt_descr[cpu].address,
+ (void *)cpu_gdt_descr[0].address, cpu_gdt_descr[0].size);
+ memset((char *)cpu_gdt_descr[cpu].address +
+ FIRST_RESERVED_GDT_ENTRY * 8, 0,
+ NR_RESERVED_GDT_ENTRIES * 8);
+
+ memset(&ctxt, 0, sizeof(ctxt));
+
+ ctxt.cpu_ctxt.ds = __USER_DS;
+ ctxt.cpu_ctxt.es = __USER_DS;
+ ctxt.cpu_ctxt.fs = 0;
+ ctxt.cpu_ctxt.gs = 0;
+ ctxt.cpu_ctxt.ss = __KERNEL_DS;
+ ctxt.cpu_ctxt.cs = __KERNEL_CS;
+ ctxt.cpu_ctxt.eip = start_eip;
+ ctxt.cpu_ctxt.esp = idle->thread.esp;
+ ctxt.cpu_ctxt.eflags = (1<<9) | (1<<2) | (idle->thread.io_pl<<12);
+
+ /* FPU is set up to default initial state. */
+ memset(ctxt.fpu_ctxt, 0, sizeof(ctxt.fpu_ctxt));
+
+ /* Virtual IDT is empty at start-of-day. */
+ for ( i = 0; i < 256; i++ )
+ {
+ ctxt.trap_ctxt[i].vector = i;
+ ctxt.trap_ctxt[i].cs = FLAT_GUESTOS_CS;
+ }
+ ctxt.fast_trap_idx = smp_trap_init(ctxt.trap_ctxt);
+
+ /* No LDT. */
+ ctxt.ldt_ents = 0;
+
+ {
+ unsigned long va;
+ int f;
+
+ for (va = cpu_gdt_descr[cpu].address, f = 0;
+ va < cpu_gdt_descr[cpu].address + cpu_gdt_descr[cpu].size;
+ va += PAGE_SIZE, f++) {
+ ctxt.gdt_frames[f] = virt_to_machine(va) >> PAGE_SHIFT;
+ make_page_readonly((void *)va);
+ }
+ ctxt.gdt_ents = cpu_gdt_descr[cpu].size / 8;
+ flush_page_update_queue();
+ }
+
+ /* Ring 1 stack is the initial stack. */
+ ctxt.guestos_ss = __KERNEL_DS;
+ ctxt.guestos_esp = idle->thread.esp;
+
+ /* Callback handlers. */
+ ctxt.event_callback_cs = __KERNEL_CS;
+ ctxt.event_callback_eip = (unsigned long)hypervisor_callback;
+ ctxt.failsafe_callback_cs = __KERNEL_CS;
+ ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
+
+ ctxt.pt_base = (unsigned long)virt_to_machine(swapper_pg_dir);
+
+ boot_error = HYPERVISOR_boot_vcpu(cpu, &ctxt);
+
+ if (!boot_error) {
+ /*
+ * allow APs to start initializing.
+ */
+ Dprintk("Before Callout %d.\n", cpu);
+ cpu_set(cpu, cpu_callout_map);
+ Dprintk("After Callout %d.\n", cpu);
+
+ /*
+ * Wait 5s total for a response
+ */
+ for (timeout = 0; timeout < 50000; timeout++) {
+ if (cpu_isset(cpu, cpu_callin_map))
+ break; /* It has booted */
+ udelay(100);
+ }
+
+ if (cpu_isset(cpu, cpu_callin_map)) {
+ /* number CPUs logically, starting from 1 (BSP is 0) */
+ Dprintk("OK.\n");
+ printk("CPU%d: ", cpu);
+ print_cpu_info(&cpu_data[cpu]);
+ Dprintk("CPU has booted.\n");
+ } else {
+ boot_error= 1;
+ }
+ }
+ x86_cpu_to_apicid[cpu] = apicid;
+ if (boot_error) {
+ /* Try to put things back the way they were before ... */
+ unmap_cpu_to_logical_apicid(cpu);
+ cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */
+ cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */
+ cpucount--;
+ }
+
+#else
+ Dprintk("Setting warm reset code and vector.\n");
+
+ store_NMI_vector(&nmi_high, &nmi_low);
+
+ smpboot_setup_warm_reset_vector(start_eip);
+
+ /*
+ * Starting actual IPI sequence...
+ */
+ boot_error = wakeup_secondary_cpu(apicid, start_eip);
+
+ if (!boot_error) {
+ /*
+ * allow APs to start initializing.
+ */
+ Dprintk("Before Callout %d.\n", cpu);
+ cpu_set(cpu, cpu_callout_map);
+ Dprintk("After Callout %d.\n", cpu);
+
+ /*
+ * Wait 5s total for a response
+ */
+ for (timeout = 0; timeout < 50000; timeout++) {
+ if (cpu_isset(cpu, cpu_callin_map))
+ break; /* It has booted */
+ udelay(100);
+ }
+
+ if (cpu_isset(cpu, cpu_callin_map)) {
+ /* number CPUs logically, starting from 1 (BSP is 0) */
+ Dprintk("OK.\n");
+ printk("CPU%d: ", cpu);
+ print_cpu_info(&cpu_data[cpu]);
+ Dprintk("CPU has booted.\n");
+ } else {
+ boot_error= 1;
+ if (*((volatile unsigned char *)trampoline_base)
+ == 0xA5)
+ /* trampoline started but...? */
+ printk("Stuck ??\n");
+ else
+ /* trampoline code not run */
+ printk("Not responding.\n");
+ inquire_remote_apic(apicid);
+ }
+ }
+ x86_cpu_to_apicid[cpu] = apicid;
+ if (boot_error) {
+ /* Try to put things back the way they were before ... */
+ unmap_cpu_to_logical_apicid(cpu);
+ cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */
+ cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */
+ cpucount--;
+ }
+
+ /* mark "stuck" area as not stuck */
+ *((volatile unsigned long *)trampoline_base) = 0;
+#endif
+
+ return boot_error;
+}
+
+cycles_t cacheflush_time;
+unsigned long cache_decay_ticks;
+
+static void smp_tune_scheduling (void)
+{
+ unsigned long cachesize; /* kB */
+ unsigned long bandwidth = 350; /* MB/s */
+ /*
+ * Rough estimation for SMP scheduling, this is the number of
+ * cycles it takes for a fully memory-limited process to flush
+ * the SMP-local cache.
+ *
+ * (For a P5 this pretty much means we will choose another idle
+ * CPU almost always at wakeup time (this is due to the small
+ * L1 cache), on PIIs it's around 50-100 usecs, depending on
+ * the cache size)
+ */
+
+ if (!cpu_khz) {
+ /*
+ * this basically disables processor-affinity
+ * scheduling on SMP without a TSC.
+ */
+ cacheflush_time = 0;
+ return;
+ } else {
+ cachesize = boot_cpu_data.x86_cache_size;
+ if (cachesize == -1) {
+ cachesize = 16; /* Pentiums, 2x8kB cache */
+ bandwidth = 100;
+ }
+
+ cacheflush_time = (cpu_khz>>10) * (cachesize<<10) / bandwidth;
+ }
+
+ cache_decay_ticks = (long)cacheflush_time/cpu_khz + 1;
+
+ printk("per-CPU timeslice cutoff: %ld.%02ld usecs.\n",
+ (long)cacheflush_time/(cpu_khz/1000),
+ ((long)cacheflush_time*100/(cpu_khz/1000)) % 100);
+ printk("task migration cache decay timeout: %ld msecs.\n",
+ cache_decay_ticks);
+}
+
+/*
+ * Cycle through the processors sending APIC IPIs to boot each.
+ */
+
+#if 0
+static int boot_cpu_logical_apicid;
+#endif
+/* Where the IO area was mapped on multiquad, always 0 otherwise */
+void *xquad_portio;
+
+cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
+
+static void __init smp_boot_cpus(unsigned int max_cpus)
+{
+ int cpu, kicked;
+ unsigned long bogosum = 0;
+#if 0
+ int apicid, bit;
+#endif
+
+ /*
+ * Setup boot CPU information
+ */
+ smp_store_cpu_info(0); /* Final full version of the data */
+ printk("CPU%d: ", 0);
+ print_cpu_info(&cpu_data[0]);
+
+#if 0
+ boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
+ boot_cpu_logical_apicid = logical_smp_processor_id();
+ x86_cpu_to_apicid[0] = boot_cpu_physical_apicid;
+#else
+ // boot_cpu_physical_apicid = 0;
+ // boot_cpu_logical_apicid = 0;
+ x86_cpu_to_apicid[0] = 0;
+#endif
+
+ current_thread_info()->cpu = 0;
+ smp_tune_scheduling();
+ cpus_clear(cpu_sibling_map[0]);
+ cpu_set(0, cpu_sibling_map[0]);
+
+ /*
+ * If we couldn't find an SMP configuration at boot time,
+ * get out of here now!
+ */
+ if (!smp_found_config /* && !acpi_lapic) */) {
+ printk(KERN_NOTICE "SMP motherboard not detected.\n");
+ smpboot_clear_io_apic_irqs();
+#if 0
+ phys_cpu_present_map = physid_mask_of_physid(0);
+ if (APIC_init_uniprocessor())
+ printk(KERN_NOTICE "Local APIC not detected."
+ " Using dummy APIC emulation.\n");
+#endif
+ map_cpu_to_logical_apicid();
+ return;
+ }
+
+#if 0
+ /*
+ * Should not be necessary because the MP table should list the boot
+ * CPU too, but we do it for the sake of robustness anyway.
+ * Makes no sense to do this check in clustered apic mode, so skip it
+ */
+ if (!check_phys_apicid_present(boot_cpu_physical_apicid)) {
+ printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
+ boot_cpu_physical_apicid);
+ physid_set(hard_smp_processor_id(), phys_cpu_present_map);
+ }
+
+ /*
+ * If we couldn't find a local APIC, then get out of here now!
+ */
+ if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) && !cpu_has_apic) {
+ printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
+ boot_cpu_physical_apicid);
+ printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
+ smpboot_clear_io_apic_irqs();
+ phys_cpu_present_map = physid_mask_of_physid(0);
+ return;
+ }
+
+ verify_local_APIC();
+#endif
+
+ /*
+ * If SMP should be disabled, then really disable it!
+ */
+ if (!max_cpus) {
+ HYPERVISOR_shared_info->n_vcpu = 1;
+ printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
+ smpboot_clear_io_apic_irqs();
+#if 0
+ phys_cpu_present_map = physid_mask_of_physid(0);
+#endif
+ return;
+ }
+
+ smp_intr_init();
+
+#if 0
+ connect_bsp_APIC();
+ setup_local_APIC();
+#endif
+ map_cpu_to_logical_apicid();
+#if 0
+
+
+ setup_portio_remap();
+
+ /*
+ * Scan the CPU present map and fire up the other CPUs via do_boot_cpu
+ *
+ * In clustered apic mode, phys_cpu_present_map is a constructed thus:
+ * bits 0-3 are quad0, 4-7 are quad1, etc. A perverse twist on the
+ * clustered apic ID.
+ */
+ Dprintk("CPU present map: %lx\n", physids_coerce(phys_cpu_present_map));
+#endif
+ Dprintk("CPU present map: %lx\n",
+ (1UL << HYPERVISOR_shared_info->n_vcpu) - 1);
+
+ kicked = 1;
+ for (cpu = 1; kicked < NR_CPUS &&
+ cpu < HYPERVISOR_shared_info->n_vcpu; cpu++) {
+ if (max_cpus <= cpucount+1)
+ continue;
+
+ if (do_boot_cpu(cpu))
+ printk("CPU #%d not responding - cannot use it.\n",
+ cpu);
+ else
+ ++kicked;
+ }
+
+#if 0
+ /*
+ * Cleanup possible dangling ends...
+ */
+ smpboot_restore_warm_reset_vector();
+#endif
+
+ /*
+ * Allow the user to impress friends.
+ */
+ Dprintk("Before bogomips.\n");
+ for (cpu = 0; cpu < NR_CPUS; cpu++)
+ if (cpu_isset(cpu, cpu_callout_map))
+ bogosum += cpu_data[cpu].loops_per_jiffy;
+ printk(KERN_INFO
+ "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+ cpucount+1,
+ bogosum/(500000/HZ),
+ (bogosum/(5000/HZ))%100);
+
+ Dprintk("Before bogocount - setting activated=1.\n");
+
+ if (smp_b_stepping)
+ printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
+
+ /*
+ * Don't taint if we are running SMP kernel on a single non-MP
+ * approved Athlon
+ */
+ if (tainted & TAINT_UNSAFE_SMP) {
+ if (cpucount)
+ printk (KERN_INFO "WARNING: This combination of AMD processors is not suitable for SMP.\n");
+ else
+ tainted &= ~TAINT_UNSAFE_SMP;
+ }
+
+ Dprintk("Boot done.\n");
+
+ /*
+ * construct cpu_sibling_map[], so that we can tell sibling CPUs
+ * efficiently.
+ */
+ for (cpu = 0; cpu < NR_CPUS; cpu++)
+ cpus_clear(cpu_sibling_map[cpu]);
+
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ int siblings = 0;
+ int i;
+ if (!cpu_isset(cpu, cpu_callout_map))
+ continue;
+
+ if (smp_num_siblings > 1) {
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!cpu_isset(i, cpu_callout_map))
+ continue;
+ if (phys_proc_id[cpu] == phys_proc_id[i]) {
+ siblings++;
+ cpu_set(i, cpu_sibling_map[cpu]);
+ }
+ }
+ } else {
+ siblings++;
+ cpu_set(cpu, cpu_sibling_map[cpu]);
+ }
+
+ if (siblings != smp_num_siblings)
+ printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings);
+ }
+
+#if 0
+ if (nmi_watchdog == NMI_LOCAL_APIC)
+ check_nmi_watchdog();
+
+ smpboot_setup_io_apic();
+
+ setup_boot_APIC_clock();
+
+ /*
+ * Synchronize the TSC with the AP
+ */
+ if (cpu_has_tsc && cpucount && cpu_khz)
+ synchronize_tsc_bp();
+#endif
+}
+
+/* These are wrappers to interface to the new boot process. Someone
+ who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+ smp_boot_cpus(max_cpus);
+}
+
+void __devinit smp_prepare_boot_cpu(void)
+{
+ cpu_set(smp_processor_id(), cpu_online_map);
+ cpu_set(smp_processor_id(), cpu_callout_map);
+}
+
+int __devinit __cpu_up(unsigned int cpu)
+{
+ /* This only works at boot for x86. See "rewrite" above. */
+ if (cpu_isset(cpu, smp_commenced_mask)) {
+ local_irq_enable();
+ return -ENOSYS;
+ }
+
+ /* In case one didn't come up */
+ if (!cpu_isset(cpu, cpu_callin_map)) {
+ local_irq_enable();
+ return -EIO;
+ }
+
+ local_irq_enable();
+ /* Unleash the CPU! */
+ cpu_set(cpu, smp_commenced_mask);
+ while (!cpu_isset(cpu, cpu_online_map))
+ mb();
+ return 0;
+}
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
+#if 1
+#else
+#ifdef CONFIG_X86_IO_APIC
+ setup_ioapic_dest();
+#endif
+ zap_low_mappings();
+ /*
+ * Disable executability of the SMP trampoline:
+ */
+ set_kernel_exec((unsigned long)trampoline_base, trampoline_exec);
+#endif
+}
+
+extern irqreturn_t smp_reschedule_interrupt(int, void *, struct pt_regs *);
+
+static struct irqaction reschedule_irq = {
+ smp_reschedule_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "reschedule",
+ NULL, NULL
+};
+
+extern irqreturn_t smp_invalidate_interrupt(int, void *, struct pt_regs *);
+
+static struct irqaction invalidate_irq = {
+ smp_invalidate_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "invalidate",
+ NULL, NULL
+};
+
+extern irqreturn_t smp_call_function_interrupt(int, void *, struct pt_regs *);
+
+static struct irqaction call_function_irq = {
+ smp_call_function_interrupt, SA_INTERRUPT, CPU_MASK_NONE,
+ "call_function", NULL, NULL
+};
+
+void __init smp_intr_init(void)
+{
+
+ (void)setup_irq(
+ bind_ipi_on_cpu_to_irq(smp_processor_id(), RESCHEDULE_VECTOR),
+ &reschedule_irq);
+ (void)setup_irq(
+ bind_ipi_on_cpu_to_irq(smp_processor_id(), INVALIDATE_TLB_VECTOR),
+ &invalidate_irq);
+ (void)setup_irq(
+ bind_ipi_on_cpu_to_irq(smp_processor_id(), CALL_FUNCTION_VECTOR),
+ &call_function_irq);
+}
diff --git a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/time.c b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/time.c
index 47eabac205..e878473d66 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/time.c
+++ b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/time.c
@@ -46,6 +46,7 @@
#include <linux/bcd.h>
#include <linux/efi.h>
#include <linux/sysctl.h>
+#include <linux/percpu.h>
#include <asm/io.h>
#include <asm/smp.h>
@@ -93,7 +94,6 @@ u32 shadow_tsc_stamp;
u64 shadow_system_time;
static u32 shadow_time_version;
static struct timeval shadow_tv;
-extern u64 processed_system_time;
/*
* We use this to ensure that gettimeofday() is monotonically increasing. We
@@ -111,6 +111,7 @@ static long last_update_from_xen; /* UTC seconds when last read Xen clock. */
/* Keep track of last time we did processing/updating of jiffies and xtime. */
u64 processed_system_time; /* System time (ns) at last processing. */
+DEFINE_PER_CPU(u64, processed_system_time);
#define NS_PER_TICK (1000000000ULL/HZ)
@@ -403,11 +404,9 @@ static inline void do_timer_interrupt(int irq, void *dev_id,
delta -= NS_PER_TICK;
processed_system_time += NS_PER_TICK;
do_timer(regs);
-#ifndef CONFIG_SMP
update_process_times(user_mode(regs));
-#endif
if (regs)
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING, regs);
}
/*
@@ -671,15 +670,27 @@ int set_timeout_timer(void)
{
u64 alarm = 0;
int ret = 0;
+#ifdef CONFIG_SMP
+ unsigned long seq;
+#endif
/*
* This is safe against long blocking (since calculations are
* not based on TSC deltas). It is also safe against warped
* system time since suspend-resume is cooperative and we
- * would first get locked out. It is safe against normal
- * updates of jiffies since interrupts are off.
+ * would first get locked out.
*/
+#ifdef CONFIG_SMP
+ do {
+ seq = read_seqbegin(&xtime_lock);
+ if (smp_processor_id())
+ alarm = __jiffies_to_st(jiffies + 1);
+ else
+ alarm = __jiffies_to_st(jiffies + 1);
+ } while (read_seqretry(&xtime_lock, seq));
+#else
alarm = __jiffies_to_st(next_timer_interrupt());
+#endif
/* Failure is pretty bad, but we'd best soldier on. */
if ( HYPERVISOR_set_timer_op(alarm) != 0 )
@@ -712,6 +723,73 @@ void time_resume(void)
last_update_from_xen = 0;
}
+#ifdef CONFIG_SMP
+#define xxprint(msg) HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg), msg)
+
+static irqreturn_t local_timer_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ s64 delta;
+ int cpu = smp_processor_id();
+
+ do {
+ __get_time_values_from_xen();
+
+ delta = (s64)(shadow_system_time +
+ ((s64)cur_timer->get_offset() *
+ (s64)NSEC_PER_USEC) -
+ per_cpu(processed_system_time, cpu));
+ }
+ while (!TIME_VALUES_UP_TO_DATE);
+
+ if (unlikely(delta < 0)) {
+ printk("Timer ISR/%d: Time went backwards: %lld %lld %lld %lld\n",
+ cpu, delta, shadow_system_time,
+ ((s64)cur_timer->get_offset() * (s64)NSEC_PER_USEC),
+ processed_system_time);
+ return IRQ_HANDLED;
+ }
+
+ /* Process elapsed jiffies since last call. */
+ while (delta >= NS_PER_TICK) {
+ delta -= NS_PER_TICK;
+ per_cpu(processed_system_time, cpu) += NS_PER_TICK;
+ if (regs)
+ update_process_times(user_mode(regs));
+#if 0
+ if (regs)
+ profile_tick(CPU_PROFILING, regs);
+#endif
+ }
+
+ if (smp_processor_id() == 0) {
+ xxprint("bug bug\n");
+ BUG();
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction local_irq_timer = {
+ local_timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "ltimer",
+ NULL, NULL
+};
+
+void local_setup_timer(void)
+{
+ int seq, time_irq;
+ int cpu = smp_processor_id();
+
+ do {
+ seq = read_seqbegin(&xtime_lock);
+ per_cpu(processed_system_time, cpu) = shadow_system_time;
+ } while (read_seqretry(&xtime_lock, seq));
+
+ time_irq = bind_virq_to_irq(VIRQ_TIMER);
+ (void)setup_irq(time_irq, &local_irq_timer);
+}
+#endif
+
/*
* /proc/sys/xen: This really belongs in another file. It can stay here for
* now however.
diff --git a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/traps.c b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/traps.c
index 1936d96c37..829ba1f5c2 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/traps.c
+++ b/linux-2.6.10-xen-sparse/arch/xen/i386/kernel/traps.c
@@ -987,3 +987,15 @@ void __init trap_init(void)
*/
cpu_init();
}
+
+int smp_trap_init(trap_info_t *trap_ctxt)
+{
+ trap_info_t *t = trap_table;
+
+ for (t = trap_table; t->address; t++) {
+ trap_ctxt[t->vector].flags = t->flags;
+ trap_ctxt[t->vector].cs = t->cs;
+ trap_ctxt[t->vector].address = t->address;
+ }
+ return SYSCALL_VECTOR;
+}
diff --git a/linux-2.6.10-xen-sparse/arch/xen/i386/mm/fault.c b/linux-2.6.10-xen-sparse/arch/xen/i386/mm/fault.c
index b869fad317..59ee3cb4f6 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/i386/mm/fault.c
+++ b/linux-2.6.10-xen-sparse/arch/xen/i386/mm/fault.c
@@ -21,6 +21,7 @@
#include <linux/vt_kern.h> /* For unblank_screen() */
#include <linux/highmem.h>
#include <linux/module.h>
+#include <linux/percpu.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -29,7 +30,7 @@
extern void die(const char *,struct pt_regs *,long);
-pgd_t *cur_pgd; /* XXXsmp */
+DEFINE_PER_CPU(pgd_t *, cur_pgd);
/*
* Unlock any spinlocks which will prevent us from getting the
@@ -453,7 +454,8 @@ no_context:
printk(" at virtual address %08lx\n",address);
printk(KERN_ALERT " printing eip:\n");
printk("%08lx\n", regs->eip);
- page = ((unsigned long *) cur_pgd)[address >> 22];
+ page = ((unsigned long *) per_cpu(cur_pgd, smp_processor_id()))
+ [address >> 22];
printk(KERN_ALERT "*pde = ma %08lx pa %08lx\n", page,
machine_to_phys(page));
/*
@@ -528,7 +530,7 @@ vmalloc_fault:
pmd_t *pmd, *pmd_k;
pte_t *pte_k;
- pgd = index + cur_pgd;
+ pgd = index + per_cpu(cur_pgd, smp_processor_id());
pgd_k = init_mm.pgd + index;
if (!pgd_present(*pgd_k))
diff --git a/linux-2.6.10-xen-sparse/arch/xen/i386/mm/hypervisor.c b/linux-2.6.10-xen-sparse/arch/xen/i386/mm/hypervisor.c
index 81d0b8450c..9068960f05 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/i386/mm/hypervisor.c
+++ b/linux-2.6.10-xen-sparse/arch/xen/i386/mm/hypervisor.c
@@ -36,6 +36,9 @@
#include <asm-xen/hypervisor.h>
#include <asm-xen/multicall.h>
#include <asm-xen/balloon.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#include <linux/percpu.h>
+#endif
/*
* This suffices to protect us if we ever move to SMP domains.
@@ -50,12 +53,15 @@ static spinlock_t update_lock = SPIN_LOCK_UNLOCKED;
#define QUEUE_SIZE 2048
#define pte_offset_kernel pte_offset
#else
+#ifdef CONFIG_SMP
+#define QUEUE_SIZE 1
+#else
#define QUEUE_SIZE 128
#endif
+#endif
-static mmu_update_t update_queue[QUEUE_SIZE];
-unsigned int mmu_update_queue_idx = 0;
-#define idx mmu_update_queue_idx
+DEFINE_PER_CPU(mmu_update_t, update_queue[QUEUE_SIZE]);
+DEFINE_PER_CPU(unsigned int, mmu_update_queue_idx);
/*
* MULTICALL_flush_page_update_queue:
@@ -63,15 +69,18 @@ unsigned int mmu_update_queue_idx = 0;
*/
void MULTICALL_flush_page_update_queue(void)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
unsigned int _idx;
spin_lock_irqsave(&update_lock, flags);
+ idx = per_cpu(mmu_update_queue_idx, cpu);
if ( (_idx = idx) != 0 )
{
- idx = 0;
+ per_cpu(mmu_update_queue_idx, cpu) = 0;
wmb(); /* Make sure index is cleared first to avoid double updates. */
queue_multicall3(__HYPERVISOR_mmu_update,
- (unsigned long)update_queue,
+ (unsigned long)&per_cpu(update_queue[0], cpu),
(unsigned long)_idx,
(unsigned long)NULL);
}
@@ -80,10 +89,11 @@ void MULTICALL_flush_page_update_queue(void)
static inline void __flush_page_update_queue(void)
{
- unsigned int _idx = idx;
- idx = 0;
+ int cpu = smp_processor_id();
+ unsigned int _idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(mmu_update_queue_idx, cpu) = 0;
wmb(); /* Make sure index is cleared first to avoid double updates. */
- if ( unlikely(HYPERVISOR_mmu_update(update_queue, _idx, NULL) < 0) )
+ if ( unlikely(HYPERVISOR_mmu_update(&per_cpu(update_queue[0], cpu), _idx, NULL) < 0) )
{
printk(KERN_ALERT "Failed to execute MMU updates.\n");
BUG();
@@ -92,136 +102,172 @@ static inline void __flush_page_update_queue(void)
void _flush_page_update_queue(void)
{
+ int cpu = smp_processor_id();
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- if ( idx != 0 ) __flush_page_update_queue();
+ if ( per_cpu(mmu_update_queue_idx, cpu) != 0 ) __flush_page_update_queue();
spin_unlock_irqrestore(&update_lock, flags);
}
static inline void increment_index(void)
{
- idx++;
- if ( unlikely(idx == QUEUE_SIZE) ) __flush_page_update_queue();
+ int cpu = smp_processor_id();
+ per_cpu(mmu_update_queue_idx, cpu)++;
+ if ( unlikely(per_cpu(mmu_update_queue_idx, cpu) == QUEUE_SIZE) ) __flush_page_update_queue();
}
static inline void increment_index_and_flush(void)
{
- idx++;
+ int cpu = smp_processor_id();
+ per_cpu(mmu_update_queue_idx, cpu)++;
__flush_page_update_queue();
}
void queue_l1_entry_update(pte_t *ptr, unsigned long val)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = virt_to_machine(ptr);
- update_queue[idx].val = val;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = virt_to_machine(ptr);
+ per_cpu(update_queue[idx], cpu).val = val;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_l2_entry_update(pmd_t *ptr, unsigned long val)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = virt_to_machine(ptr);
- update_queue[idx].val = val;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = virt_to_machine(ptr);
+ per_cpu(update_queue[idx], cpu).val = val;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pt_switch(unsigned long ptr)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
- update_queue[idx].val = MMUEXT_NEW_BASEPTR;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
+ per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_NEW_BASEPTR;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_tlb_flush(void)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = MMU_EXTENDED_COMMAND;
- update_queue[idx].val = MMUEXT_TLB_FLUSH;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = MMU_EXTENDED_COMMAND;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_TLB_FLUSH;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_invlpg(unsigned long ptr)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = MMU_EXTENDED_COMMAND;
- update_queue[idx].ptr |= ptr & PAGE_MASK;
- update_queue[idx].val = MMUEXT_INVLPG;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = MMU_EXTENDED_COMMAND;
+ per_cpu(update_queue[idx], cpu).ptr |= ptr & PAGE_MASK;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_INVLPG;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pgd_pin(unsigned long ptr)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
- update_queue[idx].val = MMUEXT_PIN_L2_TABLE;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
+ per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_PIN_L2_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pgd_unpin(unsigned long ptr)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
- update_queue[idx].val = MMUEXT_UNPIN_TABLE;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
+ per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_UNPIN_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pte_pin(unsigned long ptr)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
- update_queue[idx].val = MMUEXT_PIN_L1_TABLE;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
+ per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_PIN_L1_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_pte_unpin(unsigned long ptr)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
- update_queue[idx].val = MMUEXT_UNPIN_TABLE;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
+ per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_UNPIN_TABLE;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_set_ldt(unsigned long ptr, unsigned long len)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = MMU_EXTENDED_COMMAND | ptr;
- update_queue[idx].val = MMUEXT_SET_LDT | (len << MMUEXT_CMD_SHIFT);
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = MMU_EXTENDED_COMMAND | ptr;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_SET_LDT | (len << MMUEXT_CMD_SHIFT);
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
void queue_machphys_update(unsigned long mfn, unsigned long pfn)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
- update_queue[idx].val = pfn;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
+ per_cpu(update_queue[idx], cpu).val = pfn;
increment_index();
spin_unlock_irqrestore(&update_lock, flags);
}
@@ -229,116 +275,149 @@ void queue_machphys_update(unsigned long mfn, unsigned long pfn)
/* queue and flush versions of the above */
void xen_l1_entry_update(pte_t *ptr, unsigned long val)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = virt_to_machine(ptr);
- update_queue[idx].val = val;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = virt_to_machine(ptr);
+ per_cpu(update_queue[idx], cpu).val = val;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_l2_entry_update(pmd_t *ptr, unsigned long val)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = virt_to_machine(ptr);
- update_queue[idx].val = val;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = virt_to_machine(ptr);
+ per_cpu(update_queue[idx], cpu).val = val;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_pt_switch(unsigned long ptr)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
- update_queue[idx].val = MMUEXT_NEW_BASEPTR;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
+ per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_NEW_BASEPTR;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_tlb_flush(void)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = MMU_EXTENDED_COMMAND;
- update_queue[idx].val = MMUEXT_TLB_FLUSH;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = MMU_EXTENDED_COMMAND;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_TLB_FLUSH;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_invlpg(unsigned long ptr)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = MMU_EXTENDED_COMMAND;
- update_queue[idx].ptr |= ptr & PAGE_MASK;
- update_queue[idx].val = MMUEXT_INVLPG;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = MMU_EXTENDED_COMMAND;
+ per_cpu(update_queue[idx], cpu).ptr |= ptr & PAGE_MASK;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_INVLPG;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_pgd_pin(unsigned long ptr)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
- update_queue[idx].val = MMUEXT_PIN_L2_TABLE;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
+ per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_PIN_L2_TABLE;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_pgd_unpin(unsigned long ptr)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
- update_queue[idx].val = MMUEXT_UNPIN_TABLE;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
+ per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_UNPIN_TABLE;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_pte_pin(unsigned long ptr)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
- update_queue[idx].val = MMUEXT_PIN_L1_TABLE;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
+ per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_PIN_L1_TABLE;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_pte_unpin(unsigned long ptr)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = phys_to_machine(ptr);
- update_queue[idx].ptr |= MMU_EXTENDED_COMMAND;
- update_queue[idx].val = MMUEXT_UNPIN_TABLE;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = phys_to_machine(ptr);
+ per_cpu(update_queue[idx], cpu).ptr |= MMU_EXTENDED_COMMAND;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_UNPIN_TABLE;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_set_ldt(unsigned long ptr, unsigned long len)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = MMU_EXTENDED_COMMAND | ptr;
- update_queue[idx].val = MMUEXT_SET_LDT | (len << MMUEXT_CMD_SHIFT);
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = MMU_EXTENDED_COMMAND | ptr;
+ per_cpu(update_queue[idx], cpu).val = MMUEXT_SET_LDT | (len << MMUEXT_CMD_SHIFT);
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
void xen_machphys_update(unsigned long mfn, unsigned long pfn)
{
+ int cpu = smp_processor_id();
+ int idx;
unsigned long flags;
spin_lock_irqsave(&update_lock, flags);
- update_queue[idx].ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
- update_queue[idx].val = pfn;
+ idx = per_cpu(mmu_update_queue_idx, cpu);
+ per_cpu(update_queue[idx], cpu).ptr = (mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
+ per_cpu(update_queue[idx], cpu).val = pfn;
increment_index_and_flush();
spin_unlock_irqrestore(&update_lock, flags);
}
diff --git a/linux-2.6.10-xen-sparse/arch/xen/kernel/Makefile b/linux-2.6.10-xen-sparse/arch/xen/kernel/Makefile
index 4b74f30cb6..cce0865073 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/kernel/Makefile
+++ b/linux-2.6.10-xen-sparse/arch/xen/kernel/Makefile
@@ -11,4 +11,5 @@ $(obj)/vmlinux.lds.S:
extra-y += vmlinux.lds
-obj-y := ctrl_if.o evtchn.o fixup.o reboot.o xen_proc.o gnttab.o skbuff.o devmem.o
+obj-y := ctrl_if.o evtchn.o fixup.o reboot.o xen_proc.o \
+ gnttab.o skbuff.o devmem.o smp.o
diff --git a/linux-2.6.10-xen-sparse/arch/xen/kernel/ctrl_if.c b/linux-2.6.10-xen-sparse/arch/xen/kernel/ctrl_if.c
index 16852cb02a..3d305718a6 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/kernel/ctrl_if.c
+++ b/linux-2.6.10-xen-sparse/arch/xen/kernel/ctrl_if.c
@@ -47,6 +47,19 @@
#endif
/*
+ * Extra ring macros to sync a consumer index up to the public producer index.
+ * Generally UNSAFE, but we use it for recovery and shutdown in some cases.
+ */
+#define RING_DROP_PENDING_REQUESTS(_p, _r) \
+ do { \
+ (_r)->req_cons = (_r)->sring->req_prod; \
+ } while (0)
+#define RING_DROP_PENDING_RESPONSES(_p, _r) \
+ do { \
+ (_r)->rsp_cons = (_r)->sring->rsp_prod; \
+ } while (0)
+
+/*
* Only used by initial domain which must create its own control-interface
* event channel. This value is picked up by the user-space domain controller
* via an ioctl.
@@ -59,8 +72,8 @@ static spinlock_t ctrl_if_lock;
static struct irqaction ctrl_if_irq_action;
-static CONTROL_RING_IDX ctrl_if_tx_resp_cons;
-static CONTROL_RING_IDX ctrl_if_rx_req_cons;
+static ctrl_front_ring_t ctrl_if_tx_ring;
+static ctrl_back_ring_t ctrl_if_rx_ring;
/* Incoming message requests. */
/* Primary message type -> message handler. */
@@ -97,8 +110,6 @@ static void __ctrl_if_rx_tasklet(unsigned long data);
static DECLARE_TASKLET(ctrl_if_rx_tasklet, __ctrl_if_rx_tasklet, 0);
#define get_ctrl_if() ((control_if_t *)((char *)HYPERVISOR_shared_info + 2048))
-#define TX_FULL(_c) \
- (((_c)->tx_req_prod - ctrl_if_tx_resp_cons) == CONTROL_RING_SIZE)
static void ctrl_if_notify_controller(void)
{
@@ -113,21 +124,20 @@ static void ctrl_if_rxmsg_default_handler(ctrl_msg_t *msg, unsigned long id)
static void __ctrl_if_tx_tasklet(unsigned long data)
{
- control_if_t *ctrl_if = get_ctrl_if();
- ctrl_msg_t *msg;
- int was_full = TX_FULL(ctrl_if);
- CONTROL_RING_IDX rp;
+ ctrl_msg_t *msg;
+ int was_full = RING_FULL(CTRL_RING, &ctrl_if_tx_ring);
+ RING_IDX i, rp;
- rp = ctrl_if->tx_resp_prod;
+ i = ctrl_if_tx_ring.rsp_cons;
+ rp = ctrl_if_tx_ring.sring->rsp_prod;
rmb(); /* Ensure we see all requests up to 'rp'. */
- while ( ctrl_if_tx_resp_cons != rp )
+ for ( ; i != rp; i++ )
{
- msg = &ctrl_if->tx_ring[MASK_CONTROL_IDX(ctrl_if_tx_resp_cons)];
-
- DPRINTK("Rx-Rsp %u/%u :: %d/%d\n",
- ctrl_if_tx_resp_cons,
- ctrl_if->tx_resp_prod,
+ msg = RING_GET_RESPONSE(CTRL_RING, &ctrl_if_tx_ring, i);
+
+ DPRINTK("Rx-Rsp %u/%u :: %d/%d\n", i-1,
+ ctrl_if_tx_ring.sring->rsp_prod,
msg->type, msg->subtype);
/* Execute the callback handler, if one was specified. */
@@ -138,16 +148,16 @@ static void __ctrl_if_tx_tasklet(unsigned long data)
smp_mb(); /* Execute, /then/ free. */
ctrl_if_txmsg_id_mapping[msg->id].fn = NULL;
}
-
- /*
- * Step over the message in the ring /after/ finishing reading it. As
- * soon as the index is updated then the message may get blown away.
- */
- smp_mb();
- ctrl_if_tx_resp_cons++;
}
- if ( was_full && !TX_FULL(ctrl_if) )
+ /*
+ * Step over messages in the ring /after/ finishing reading them. As soon
+ * as the index is updated then the message may get blown away.
+ */
+ smp_mb();
+ ctrl_if_tx_ring.rsp_cons = i;
+
+ if ( was_full && !RING_FULL(CTRL_RING, &ctrl_if_tx_ring) )
{
wake_up(&ctrl_if_tx_wait);
run_task_queue(&ctrl_if_tx_tq);
@@ -172,24 +182,27 @@ static void __ctrl_if_rxmsg_deferred(void *unused)
static void __ctrl_if_rx_tasklet(unsigned long data)
{
- control_if_t *ctrl_if = get_ctrl_if();
ctrl_msg_t msg, *pmsg;
- CONTROL_RING_IDX rp, dp;
+ CONTROL_RING_IDX dp;
+ RING_IDX rp, i;
+ i = ctrl_if_rx_ring.req_cons;
+ rp = ctrl_if_rx_ring.sring->req_prod;
dp = ctrl_if_rxmsg_deferred_prod;
- rp = ctrl_if->rx_req_prod;
rmb(); /* Ensure we see all requests up to 'rp'. */
-
- while ( ctrl_if_rx_req_cons != rp )
+
+ for ( ; i != rp; i++)
{
- pmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if_rx_req_cons++)];
+ pmsg = RING_GET_REQUEST(CTRL_RING, &ctrl_if_rx_ring, i);
memcpy(&msg, pmsg, offsetof(ctrl_msg_t, msg));
- DPRINTK("Rx-Req %u/%u :: %d/%d\n",
- ctrl_if_rx_req_cons-1,
- ctrl_if->rx_req_prod,
+ DPRINTK("Rx-Req %u/%u :: %d/%d\n", i-1,
+ ctrl_if_rx_ring.sring->req_prod,
msg.type, msg.subtype);
+ if ( msg.length > sizeof(msg.msg) )
+ msg.length = sizeof(msg.msg);
+
if ( msg.length != 0 )
memcpy(msg.msg, pmsg->msg, msg.length);
@@ -201,6 +214,8 @@ static void __ctrl_if_rx_tasklet(unsigned long data)
(*ctrl_if_rxmsg_handler[msg.type])(&msg, 0);
}
+ ctrl_if_rx_ring.req_cons = i;
+
if ( dp != ctrl_if_rxmsg_deferred_prod )
{
wmb();
@@ -212,12 +227,10 @@ static void __ctrl_if_rx_tasklet(unsigned long data)
static irqreturn_t ctrl_if_interrupt(int irq, void *dev_id,
struct pt_regs *regs)
{
- control_if_t *ctrl_if = get_ctrl_if();
-
- if ( ctrl_if_tx_resp_cons != ctrl_if->tx_resp_prod )
+ if ( RING_HAS_UNCONSUMED_RESPONSES(CTRL_RING, &ctrl_if_tx_ring) )
tasklet_schedule(&ctrl_if_tx_tasklet);
- if ( ctrl_if_rx_req_cons != ctrl_if->rx_req_prod )
+ if ( RING_HAS_UNCONSUMED_REQUESTS(CTRL_RING, &ctrl_if_rx_ring) )
tasklet_schedule(&ctrl_if_rx_tasklet);
return IRQ_HANDLED;
@@ -229,13 +242,13 @@ ctrl_if_send_message_noblock(
ctrl_msg_handler_t hnd,
unsigned long id)
{
- control_if_t *ctrl_if = get_ctrl_if();
unsigned long flags;
+ ctrl_msg_t *dmsg;
int i;
spin_lock_irqsave(&ctrl_if_lock, flags);
- if ( TX_FULL(ctrl_if) )
+ if ( RING_FULL(CTRL_RING, &ctrl_if_tx_ring) )
{
spin_unlock_irqrestore(&ctrl_if_lock, flags);
return -EAGAIN;
@@ -252,14 +265,15 @@ ctrl_if_send_message_noblock(
}
DPRINTK("Tx-Req %u/%u :: %d/%d\n",
- ctrl_if->tx_req_prod,
- ctrl_if_tx_resp_cons,
+ ctrl_if_tx_ring.req_prod_pvt,
+ ctrl_if_tx_ring.rsp_cons,
msg->type, msg->subtype);
- memcpy(&ctrl_if->tx_ring[MASK_CONTROL_IDX(ctrl_if->tx_req_prod)],
- msg, sizeof(*msg));
- wmb(); /* Write the message before letting the controller peek at it. */
- ctrl_if->tx_req_prod++;
+ dmsg = RING_GET_REQUEST(CTRL_RING, &ctrl_if_tx_ring,
+ ctrl_if_tx_ring.req_prod_pvt);
+ memcpy(dmsg, msg, sizeof(*msg));
+ ctrl_if_tx_ring.req_prod_pvt++;
+ RING_PUSH_REQUESTS(CTRL_RING, &ctrl_if_tx_ring);
spin_unlock_irqrestore(&ctrl_if_lock, flags);
@@ -358,10 +372,8 @@ int
ctrl_if_enqueue_space_callback(
struct tq_struct *task)
{
- control_if_t *ctrl_if = get_ctrl_if();
-
/* Fast path. */
- if ( !TX_FULL(ctrl_if) )
+ if ( !RING_FULL(CTRL_RING, &ctrl_if_tx_ring) )
return 0;
(void)queue_task(task, &ctrl_if_tx_tq);
@@ -372,14 +384,13 @@ ctrl_if_enqueue_space_callback(
* certainly return 'not full'.
*/
smp_mb();
- return TX_FULL(ctrl_if);
+ return RING_FULL(CTRL_RING, &ctrl_if_tx_ring);
}
void
ctrl_if_send_response(
ctrl_msg_t *msg)
{
- control_if_t *ctrl_if = get_ctrl_if();
unsigned long flags;
ctrl_msg_t *dmsg;
@@ -390,15 +401,16 @@ ctrl_if_send_response(
spin_lock_irqsave(&ctrl_if_lock, flags);
DPRINTK("Tx-Rsp %u :: %d/%d\n",
- ctrl_if->rx_resp_prod,
+ ctrl_if_rx_ring.rsp_prod_pvt,
msg->type, msg->subtype);
- dmsg = &ctrl_if->rx_ring[MASK_CONTROL_IDX(ctrl_if->rx_resp_prod)];
+ dmsg = RING_GET_RESPONSE(CTRL_RING, &ctrl_if_rx_ring,
+ ctrl_if_rx_ring.rsp_prod_pvt);
if ( dmsg != msg )
memcpy(dmsg, msg, sizeof(*msg));
- wmb(); /* Write the message before letting the controller peek at it. */
- ctrl_if->rx_resp_prod++;
+ ctrl_if_rx_ring.rsp_prod_pvt++;
+ RING_PUSH_RESPONSES(CTRL_RING, &ctrl_if_rx_ring);
spin_unlock_irqrestore(&ctrl_if_lock, flags);
@@ -469,8 +481,6 @@ void ctrl_if_suspend(void)
void ctrl_if_resume(void)
{
- control_if_t *ctrl_if = get_ctrl_if();
-
if ( xen_start_info.flags & SIF_INITDOMAIN )
{
/*
@@ -491,8 +501,8 @@ void ctrl_if_resume(void)
}
/* Sync up with shared indexes. */
- ctrl_if_tx_resp_cons = ctrl_if->tx_resp_prod;
- ctrl_if_rx_req_cons = ctrl_if->rx_resp_prod;
+ RING_DROP_PENDING_RESPONSES(CTRL_RING, &ctrl_if_tx_ring);
+ RING_DROP_PENDING_REQUESTS(CTRL_RING, &ctrl_if_rx_ring);
ctrl_if_evtchn = xen_start_info.domain_controller_evtchn;
ctrl_if_irq = bind_evtchn_to_irq(ctrl_if_evtchn);
@@ -505,11 +515,15 @@ void ctrl_if_resume(void)
void __init ctrl_if_init(void)
{
- int i;
+ control_if_t *ctrl_if = get_ctrl_if();
+ int i;
for ( i = 0; i < 256; i++ )
ctrl_if_rxmsg_handler[i] = ctrl_if_rxmsg_default_handler;
+ FRONT_RING_ATTACH(CTRL_RING, &ctrl_if_tx_ring, &ctrl_if->tx_ring);
+ BACK_RING_ATTACH(CTRL_RING, &ctrl_if_rx_ring, &ctrl_if->rx_ring);
+
spin_lock_init(&ctrl_if_lock);
ctrl_if_resume();
@@ -532,12 +546,13 @@ __initcall(ctrl_if_late_setup);
int ctrl_if_transmitter_empty(void)
{
- return (get_ctrl_if()->tx_req_prod == ctrl_if_tx_resp_cons);
+ return (ctrl_if_tx_ring.sring->req_prod == ctrl_if_tx_ring.rsp_cons);
+
}
void ctrl_if_discard_responses(void)
{
- ctrl_if_tx_resp_cons = get_ctrl_if()->tx_resp_prod;
+ RING_DROP_PENDING_RESPONSES(CTRL_RING, &ctrl_if_tx_ring);
}
EXPORT_SYMBOL(ctrl_if_send_message_noblock);
diff --git a/linux-2.6.10-xen-sparse/arch/xen/kernel/evtchn.c b/linux-2.6.10-xen-sparse/arch/xen/kernel/evtchn.c
index e5aa5a1b18..9e3b8d06b7 100644
--- a/linux-2.6.10-xen-sparse/arch/xen/kernel/evtchn.c
+++ b/linux-2.6.10-xen-sparse/arch/xen/kernel/evtchn.c
@@ -42,6 +42,7 @@
#include <asm-xen/xen-public/physdev.h>
#include <asm-xen/ctrl_if.h>
#include <asm-xen/hypervisor.h>
+#include <asm-xen/evtchn.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
EXPORT_SYMBOL(force_evtchn_callback);
@@ -59,7 +60,13 @@ static int evtchn_to_irq[NR_EVENT_CHANNELS];
static int irq_to_evtchn[NR_IRQS];
/* IRQ <-> VIRQ mapping. */
-static int virq_to_irq[NR_VIRQS];
+DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]);
+
+/* evtchn <-> IPI mapping. */
+#ifndef NR_IPIS // XXX SMH: temp fix for 2.4
+#define NR_IPIS 1
+#endif
+DEFINE_PER_CPU(int, ipi_to_evtchn[NR_IPIS]);
/* Reference counts for bindings to IRQs. */
static int irq_bindcount[NR_IRQS];
@@ -99,22 +106,26 @@ asmlinkage void evtchn_do_upcall(struct pt_regs *regs)
int irq;
unsigned long flags;
shared_info_t *s = HYPERVISOR_shared_info;
+ vcpu_info_t *vcpu_info = &s->vcpu_data[smp_processor_id()];
local_irq_save(flags);
- while ( s->vcpu_data[0].evtchn_upcall_pending )
+ while ( vcpu_info->evtchn_upcall_pending )
{
- s->vcpu_data[0].evtchn_upcall_pending = 0;
+ vcpu_info->evtchn_upcall_pending = 0;
/* NB. No need for a barrier here -- XCHG is a barrier on x86. */
- l1 = xchg(&s->evtchn_pending_sel, 0);
+ l1 = xchg(&vcpu_info->evtchn_pending_sel, 0);
while ( (l1i = ffs(l1)) != 0 )
{
l1i--;
l1 &= ~(1 << l1i);
- l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
- while ( (l2i = ffs(l2)) != 0 )
+ for ( ;; )
{
+ l2 = s->evtchn_pending[l1i] & ~s->evtchn_mask[l1i];
+ l2i = ffs(l2);
+ if ( l2i == 0 )
+ break;
l2i--;
l2 &= ~(1 << l2i);
@@ -148,10 +159,11 @@ int bind_virq_to_irq(int virq)
{
evtchn_op_t op;
int evtchn, irq;
+ int cpu = smp_processor_id();
spin_lock(&irq_mapping_update_lock);
- if ( (irq = virq_to_irq[virq]) == -1 )
+ if ( (irq = per_cpu(virq_to_irq, cpu)[virq]) == -1 )
{
op.cmd = EVTCHNOP_bind_virq;
op.u.bind_virq.virq = virq;
@@ -163,7 +175,7 @@ int bind_virq_to_irq(int virq)
evtchn_to_irq[evtchn] = irq;
irq_to_evtchn[irq] = evtchn;
- virq_to_irq[virq] = irq;
+ per_cpu(virq_to_irq, cpu)[virq] = irq;
}
irq_bindcount[irq]++;
@@ -176,7 +188,8 @@ int bind_virq_to_irq(int virq)
void unbind_virq_from_irq(int virq)
{
evtchn_op_t op;
- int irq = virq_to_irq[virq];
+ int cpu = smp_processor_id();
+ int irq = per_cpu(virq_to_irq, cpu)[virq];
int evtchn = irq_to_evtchn[irq];
spin_lock(&irq_mapping_update_lock);
@@ -191,7 +204,61 @@ void unbind_virq_from_irq(int virq)
evtchn_to_irq[evtchn] = -1;
irq_to_evtchn[irq] = -1;
- virq_to_irq[virq] = -1;
+ per_cpu(virq_to_irq, cpu)[virq] = -1;
+ }
+
+ spin_unlock(&irq_mapping_update_lock);
+}
+
+int bind_ipi_on_cpu_to_irq(int cpu, int ipi)
+{
+ evtchn_op_t op;
+ int evtchn, irq;
+
+ spin_lock(&irq_mapping_update_lock);
+
+ if ( (evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi]) == 0 )
+ {
+ op.cmd = EVTCHNOP_bind_ipi;
+ op.u.bind_ipi.ipi_edom = cpu;
+ if ( HYPERVISOR_event_channel_op(&op) != 0 )
+ panic("Failed to bind virtual IPI %d on cpu %d\n", ipi, cpu);
+ evtchn = op.u.bind_ipi.port;
+
+ irq = find_unbound_irq();
+ evtchn_to_irq[evtchn] = irq;
+ irq_to_evtchn[irq] = evtchn;
+
+ per_cpu(ipi_to_evtchn, cpu)[ipi] = evtchn;
+ } else
+ irq = evtchn_to_irq[evtchn];
+
+ irq_bindcount[irq]++;
+
+ spin_unlock(&irq_mapping_update_lock);
+
+ return irq;
+}
+
+void unbind_ipi_on_cpu_from_irq(int cpu, int ipi)
+{
+ evtchn_op_t op;
+ int evtchn = per_cpu(ipi_to_evtchn, cpu)[ipi];
+ int irq = irq_to_evtchn[evtchn];
+
+ spin_lock(&irq_mapping_update_lock);
+
+ if ( --irq_bindcount[irq] == 0 )
+ {
+ op.cmd = EVTCHNOP_close;
+ op.u.close.dom = DOMID_SELF;
+ op.u.close.port = evtchn;
+ if ( HYPERVISOR_event_channel_op(&op) != 0 )
+ panic("Failed to unbind virtual IPI %d on cpu %d\n", ipi, cpu);
+
+ evtchn_to_irq[evtchn] = -1;
+ irq_to_evtchn[irq] = -1;
+ per_cpu(ipi_to_evtchn, cpu)[ipi] = 0;
}
spin_unlock(&irq_mapping_update_lock);
@@ -421,30 +488,15 @@ static struct hw_interrupt_type pirq_type = {
NULL
};
-static irqreturn_t misdirect_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
-{
- /* nothing */
- return IRQ_HANDLED;
-}
-
-static struct irqaction misdirect_action = {
- misdirect_interrupt,
- SA_INTERRUPT,
- CPU_MASK_NONE,
- "misdirect",
- NULL,
- NULL
-};
-
void irq_suspend(void)
{
int pirq, virq, irq, evtchn;
+ int cpu = smp_processor_id(); /* XXX */
/* Unbind VIRQs from event channels. */
for ( virq = 0; virq < NR_VIRQS; virq++ )
{
- if ( (irq = virq_to_irq[virq]) == -1 )
+ if ( (irq = per_cpu(virq_to_irq, cpu)[virq]) == -1 )
continue;
evtchn = irq_to_evtchn[irq];
@@ -464,13 +516,14 @@ void irq_resume(void)
{
evtchn_op_t op;
int virq, irq, evtchn;
+ int cpu = smp_processor_id(); /* XXX */
for ( evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++ )
mask_evtchn(evtchn); /* New event-channel space is not 'live' yet. */
for ( virq = 0; virq < NR_VIRQS; virq++ )
{
- if ( (irq = virq_to_irq[virq]) == -1 )
+ if ( (irq = per_cpu(virq_to_irq, cpu)[virq]) == -1 )
continue;
/* Get a new binding from Xen. */
@@ -492,14 +545,17 @@ void irq_resume(void)
void __init init_IRQ(void)
{
int i;
+ int cpu;
irq_ctx_init(0);
spin_lock_init(&irq_mapping_update_lock);
- /* No VIRQ -> IRQ mappings. */
- for ( i = 0; i < NR_VIRQS; i++ )
- virq_to_irq[i] = -1;
+ for ( cpu = 0; cpu < NR_CPUS; cpu++ ) {
+ /* No VIRQ -> IRQ mappings. */
+ for ( i = 0; i < NR_VIRQS; i++ )
+ per_cpu(virq_to_irq, cpu)[i] = -1;
+ }
/* No event-channel -> IRQ mappings. */
for ( i = 0; i < NR_EVENT_CHANNELS; i++ )
@@ -534,8 +590,6 @@ void __init init_IRQ(void)
irq_desc[pirq_to_irq(i)].handler = &pirq_type;
}
- (void)setup_irq(bind_virq_to_irq(VIRQ_MISDIRECT), &misdirect_action);
-
/* This needs to be done early, but after the IRQ subsystem is alive. */
ctrl_if_init();
}
diff --git a/linux-2.6.10-xen-sparse/arch/xen/kernel/smp.c b/linux-2.6.10-xen-sparse/arch/xen/kernel/smp.c
new file mode 100644
index 0000000000..51addc6c76
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/arch/xen/kernel/smp.c
@@ -0,0 +1,19 @@
+/* Copyright (C) 2004, Christian Limpach */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/threads.h>
+
+unsigned int __initdata maxcpus = NR_CPUS;
+
+
+/*
+ * the frequency of the profiling timer can be changed
+ * by writing a multiplier value into /proc/profile.
+ */
+int setup_profiling_timer(unsigned int multiplier)
+{
+ printk("setup_profiling_timer\n");
+
+ return 0;
+}
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/Makefile b/linux-2.6.10-xen-sparse/drivers/xen/Makefile
index 0bfb5a50c3..7bb4798309 100644
--- a/linux-2.6.10-xen-sparse/drivers/xen/Makefile
+++ b/linux-2.6.10-xen-sparse/drivers/xen/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_XEN_BLKDEV_BACKEND) += blkback/
obj-$(CONFIG_XEN_NETDEV_BACKEND) += netback/
obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += blkfront/
obj-$(CONFIG_XEN_NETDEV_FRONTEND) += netfront/
+obj-$(CONFIG_XEN_BLKDEV_TAP) += blktap/
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blkback/blkback.c b/linux-2.6.10-xen-sparse/drivers/xen/blkback/blkback.c
index 6d201022d2..6167f6061b 100644
--- a/linux-2.6.10-xen-sparse/drivers/xen/blkback/blkback.c
+++ b/linux-2.6.10-xen-sparse/drivers/xen/blkback/blkback.c
@@ -11,6 +11,7 @@
*/
#include "common.h"
+#include <asm-xen/evtchn.h>
/*
* These are rather arbitrary. They are fairly large because adjacent requests
@@ -68,6 +69,18 @@ static PEND_RING_IDX pending_prod, pending_cons;
static kmem_cache_t *buffer_head_cachep;
#endif
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
+/*
+ * If the tap driver is used, we may get pages belonging to either the tap
+ * or (more likely) the real frontend. The backend must specify which domain
+ * a given page belongs to in update_va_mapping though. For the moment,
+ * the tap rewrites the ID field of the request to contain the request index
+ * and the id of the real front end domain.
+ */
+#define BLKTAP_COOKIE 0xbeadfeed
+static inline domid_t ID_TO_DOM(unsigned long id) { return (id >> 16); }
+#endif
+
static int do_block_io_op(blkif_t *blkif, int max_to_do);
static void dispatch_probe(blkif_t *blkif, blkif_request_t *req);
static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req);
@@ -265,17 +278,16 @@ irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
static int do_block_io_op(blkif_t *blkif, int max_to_do)
{
- blkif_ring_t *blk_ring = blkif->blk_ring_base;
+ blkif_back_ring_t *blk_ring = &blkif->blk_ring;
blkif_request_t *req;
- BLKIF_RING_IDX i, rp;
+ RING_IDX i, rp;
int more_to_do = 0;
- rp = blk_ring->req_prod;
+ rp = blk_ring->sring->req_prod;
rmb(); /* Ensure we see queued requests up to 'rp'. */
- /* Take items off the comms ring, taking care not to overflow. */
- for ( i = blkif->blk_req_cons;
- (i != rp) && ((i-blkif->blk_resp_prod) != BLKIF_RING_SIZE);
+ for ( i = blk_ring->req_cons;
+ (i != rp) && !RING_REQUEST_CONS_OVERFLOW(BLKIF_RING, blk_ring, i);
i++ )
{
if ( (max_to_do-- == 0) || (NR_PENDING_REQS == MAX_PENDING_REQS) )
@@ -284,7 +296,7 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do)
break;
}
- req = &blk_ring->ring[MASK_BLKIF_IDX(i)].req;
+ req = RING_GET_REQUEST(BLKIF_RING, blk_ring, i);
switch ( req->operation )
{
case BLKIF_OP_READ:
@@ -298,14 +310,13 @@ static int do_block_io_op(blkif_t *blkif, int max_to_do)
default:
DPRINTK("error: unknown block io operation [%d]\n",
- blk_ring->ring[i].req.operation);
- make_response(blkif, blk_ring->ring[i].req.id,
- blk_ring->ring[i].req.operation, BLKIF_RSP_ERROR);
+ req->operation);
+ make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
break;
}
}
- blkif->blk_req_cons = i;
+ blk_ring->req_cons = i;
return more_to_do;
}
@@ -323,12 +334,29 @@ static void dispatch_probe(blkif_t *blkif, blkif_request_t *req)
(blkif_last_sect(req->frame_and_sects[0]) != 7) )
goto out;
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
+ /* Grab the real frontend out of the probe message. */
+ if (req->frame_and_sects[1] == BLKTAP_COOKIE)
+ blkif->is_blktap = 1;
+#endif
+
+
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
if ( HYPERVISOR_update_va_mapping_otherdomain(
MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
(pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
- 0, blkif->domid) )
+ 0, (blkif->is_blktap ? ID_TO_DOM(req->id) : blkif->domid) ) )
+
goto out;
-
+#else
+ if ( HYPERVISOR_update_va_mapping_otherdomain(
+ MMAP_VADDR(pending_idx, 0) >> PAGE_SHIFT,
+ (pte_t) { (req->frame_and_sects[0] & PAGE_MASK) | __PAGE_KERNEL },
+ 0, blkif->domid) )
+
+ goto out;
+#endif
+
rsp = vbd_probe(blkif, (vdisk_t *)MMAP_VADDR(pending_idx, 0),
PAGE_SIZE / sizeof(vdisk_t));
@@ -411,8 +439,11 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
mcl[i].args[0] = MMAP_VADDR(pending_idx, i) >> PAGE_SHIFT;
mcl[i].args[1] = (phys_seg[i].buffer & PAGE_MASK) | remap_prot;
mcl[i].args[2] = 0;
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
+ mcl[i].args[3] = (blkif->is_blktap) ? ID_TO_DOM(req->id) : blkif->domid;
+#else
mcl[i].args[3] = blkif->domid;
-
+#endif
phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] =
FOREIGN_FRAME(phys_seg[i].buffer >> PAGE_SHIFT);
}
@@ -526,16 +557,17 @@ static void make_response(blkif_t *blkif, unsigned long id,
{
blkif_response_t *resp;
unsigned long flags;
+ blkif_back_ring_t *blk_ring = &blkif->blk_ring;
/* Place on the response ring for the relevant domain. */
spin_lock_irqsave(&blkif->blk_ring_lock, flags);
- resp = &blkif->blk_ring_base->
- ring[MASK_BLKIF_IDX(blkif->blk_resp_prod)].resp;
+ resp = RING_GET_RESPONSE(BLKIF_RING, blk_ring, blk_ring->rsp_prod_pvt);
resp->id = id;
resp->operation = op;
resp->status = st;
wmb(); /* Ensure other side can see the response fields. */
- blkif->blk_ring_base->resp_prod = ++blkif->blk_resp_prod;
+ blk_ring->rsp_prod_pvt++;
+ RING_PUSH_RESPONSES(BLKIF_RING, blk_ring);
spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
/* Kick the relevant domain. */
@@ -579,7 +611,10 @@ static int __init blkif_init(void)
#endif
blkif_ctrlif_init();
-
+
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
+ printk(KERN_ALERT "NOTE: Blkif backend is running with tap support on!\n");
+#endif
return 0;
}
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blkback/common.h b/linux-2.6.10-xen-sparse/drivers/xen/blkback/common.h
index 4a12ca8fe9..1df08d43cd 100644
--- a/linux-2.6.10-xen-sparse/drivers/xen/blkback/common.h
+++ b/linux-2.6.10-xen-sparse/drivers/xen/blkback/common.h
@@ -15,6 +15,7 @@
#include <asm-xen/ctrl_if.h>
#include <asm-xen/hypervisor.h>
#include <asm-xen/xen-public/io/blkif.h>
+#include <asm-xen/xen-public/io/ring.h>
#if 0
#define ASSERT(_p) \
@@ -36,19 +37,17 @@ struct block_device;
typedef struct blkif_st {
/* Unique identifier for this interface. */
- domid_t domid;
- unsigned int handle;
+ domid_t domid;
+ unsigned int handle;
/* Physical parameters of the comms window. */
- unsigned long shmem_frame;
- unsigned int evtchn;
- int irq;
+ unsigned long shmem_frame;
+ unsigned int evtchn;
+ int irq;
/* Comms information. */
- blkif_ring_t *blk_ring_base; /* ioremap()'ed ptr to shmem_frame. */
- BLKIF_RING_IDX blk_req_cons; /* Request consumer. */
- BLKIF_RING_IDX blk_resp_prod; /* Private version of resp. producer. */
+ blkif_back_ring_t blk_ring;
/* VBDs attached to this interface. */
- rb_root_t vbd_rb; /* Mapping from 16-bit vdevices to VBDs. */
- spinlock_t vbd_lock; /* Protects VBD mapping. */
+ rb_root_t vbd_rb; /* Mapping from 16-bit vdevices to VBDs.*/
+ spinlock_t vbd_lock; /* Protects VBD mapping. */
/* Private fields. */
enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
/*
@@ -56,6 +55,10 @@ typedef struct blkif_st {
* We therefore need to store the id from the original request.
*/
u8 disconnect_rspid;
+#ifdef CONFIG_XEN_BLKDEV_TAP_BE
+ /* Is this a blktap frontend */
+ unsigned int is_blktap;
+#endif
struct blkif_st *hash_next;
struct list_head blkdev_list;
spinlock_t blk_ring_lock;
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blkback/interface.c b/linux-2.6.10-xen-sparse/drivers/xen/blkback/interface.c
index 4196014597..087e02d620 100644
--- a/linux-2.6.10-xen-sparse/drivers/xen/blkback/interface.c
+++ b/linux-2.6.10-xen-sparse/drivers/xen/blkback/interface.c
@@ -39,7 +39,7 @@ static void __blkif_disconnect_complete(void *arg)
* must still be notified to the remote driver.
*/
unbind_evtchn_from_irq(blkif->evtchn);
- vfree(blkif->blk_ring_base);
+ vfree(blkif->blk_ring.sring);
/* Construct the deferred response message. */
cmsg.type = CMSG_BLKIF_BE;
@@ -149,14 +149,15 @@ void blkif_destroy(blkif_be_destroy_t *destroy)
void blkif_connect(blkif_be_connect_t *connect)
{
- domid_t domid = connect->domid;
- unsigned int handle = connect->blkif_handle;
- unsigned int evtchn = connect->evtchn;
- unsigned long shmem_frame = connect->shmem_frame;
+ domid_t domid = connect->domid;
+ unsigned int handle = connect->blkif_handle;
+ unsigned int evtchn = connect->evtchn;
+ unsigned long shmem_frame = connect->shmem_frame;
struct vm_struct *vma;
- pgprot_t prot;
- int error;
- blkif_t *blkif;
+ pgprot_t prot;
+ int error;
+ blkif_t *blkif;
+ blkif_sring_t *sring;
blkif = blkif_find_by_handle(domid, handle);
if ( unlikely(blkif == NULL) )
@@ -195,11 +196,13 @@ void blkif_connect(blkif_be_connect_t *connect)
vfree(vma->addr);
return;
}
-
+ sring = (blkif_sring_t *)vma->addr;
+ SHARED_RING_INIT(BLKIF_RING, sring);
+ BACK_RING_INIT(BLKIF_RING, &blkif->blk_ring, sring);
+
blkif->evtchn = evtchn;
blkif->irq = bind_evtchn_to_irq(evtchn);
blkif->shmem_frame = shmem_frame;
- blkif->blk_ring_base = (blkif_ring_t *)vma->addr;
blkif->status = CONNECTED;
blkif_get(blkif);
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blkfront/blkfront.c b/linux-2.6.10-xen-sparse/drivers/xen/blkfront/blkfront.c
index e28db67411..65c7011e76 100644
--- a/linux-2.6.10-xen-sparse/drivers/xen/blkfront/blkfront.c
+++ b/linux-2.6.10-xen-sparse/drivers/xen/blkfront/blkfront.c
@@ -6,6 +6,7 @@
* Copyright (c) 2003-2004, Keir Fraser & Steve Hand
* Modifications by Mark A. Williamson are (c) Intel Research Cambridge
* Copyright (c) 2004, Christian Limpach
+ * Copyright (c) 2004, Andrew Warfield
*
* This file may be distributed separately from the Linux kernel, or
* incorporated into other software packages, subject to the following license:
@@ -44,6 +45,7 @@
#include <linux/interrupt.h>
#include <scsi/scsi.h>
#include <asm-xen/ctrl_if.h>
+#include <asm-xen/evtchn.h>
typedef unsigned char byte; /* from linux/ide.h */
@@ -70,20 +72,14 @@ static unsigned int blkif_irq = 0;
static int blkif_control_rsp_valid;
static blkif_response_t blkif_control_rsp;
-static blkif_ring_t *blk_ring = NULL;
-static BLKIF_RING_IDX resp_cons; /* Response consumer for comms ring. */
-static BLKIF_RING_IDX req_prod; /* Private request producer. */
+static blkif_front_ring_t blk_ring;
unsigned long rec_ring_free;
-blkif_request_t rec_ring[BLKIF_RING_SIZE];
+blkif_request_t rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)];
static int recovery = 0; /* "Recovery in progress" flag. Protected
* by the blkif_io_lock */
-/* We plug the I/O ring if the driver is suspended or if the ring is full. */
-#define BLKIF_RING_FULL (((req_prod - resp_cons) == BLKIF_RING_SIZE) || \
- (blkif_state != BLKIF_STATE_CONNECTED))
-
static void kick_pending_request_queues(void);
int __init xlblk_init(void);
@@ -94,7 +90,7 @@ static inline int GET_ID_FROM_FREELIST( void )
{
unsigned long free = rec_ring_free;
- if ( free > BLKIF_RING_SIZE )
+ if ( free > RING_SIZE(BLKIF_RING, &blk_ring) )
BUG();
rec_ring_free = rec_ring[free].id;
@@ -155,8 +151,7 @@ static inline void translate_req_to_mfn(blkif_request_t *xreq,
static inline void flush_requests(void)
{
DISABLE_SCATTERGATHER();
- wmb(); /* Ensure that the frontend can see the requests. */
- blk_ring->req_prod = req_prod;
+ RING_PUSH_REQUESTS(BLKIF_RING, &blk_ring);
notify_via_evtchn(blkif_evtchn);
}
@@ -336,7 +331,7 @@ static int blkif_queue_request(struct request *req)
return 1;
/* Fill out a communications ring structure. */
- ring_req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req;
+ ring_req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt);
id = GET_ID_FROM_FREELIST();
rec_ring[id].id = (unsigned long) req;
@@ -361,8 +356,8 @@ static int blkif_queue_request(struct request *req)
}
}
- req_prod++;
-
+ blk_ring.req_prod_pvt++;
+
/* Keep a private copy so we can reissue requests when recovering. */
translate_req_to_pfn(&rec_ring[id], ring_req);
@@ -389,7 +384,7 @@ void do_blkif_request(request_queue_t *rq)
continue;
}
- if ( BLKIF_RING_FULL )
+ if ( RING_FULL(BLKIF_RING, &blk_ring) )
{
blk_stop_queue(rq);
break;
@@ -415,9 +410,9 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
{
struct request *req;
blkif_response_t *bret;
- BLKIF_RING_IDX i, rp;
+ RING_IDX i, rp;
unsigned long flags;
-
+
spin_lock_irqsave(&blkif_io_lock, flags);
if ( unlikely(blkif_state == BLKIF_STATE_CLOSED) ||
@@ -426,18 +421,17 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
spin_unlock_irqrestore(&blkif_io_lock, flags);
return IRQ_HANDLED;
}
-
- rp = blk_ring->resp_prod;
+
+ rp = blk_ring.sring->rsp_prod;
rmb(); /* Ensure we see queued responses up to 'rp'. */
- for ( i = resp_cons; i != rp; i++ )
+ for ( i = blk_ring.rsp_cons; i != rp; i++ )
{
unsigned long id;
- bret = &blk_ring->ring[MASK_BLKIF_IDX(i)].resp;
+ bret = RING_GET_RESPONSE(BLKIF_RING, &blk_ring, i);
id = bret->id;
req = (struct request *)rec_ring[id].id;
-
blkif_completion( &rec_ring[id] );
ADD_ID_TO_FREELIST(id); /* overwrites req */
@@ -466,9 +460,9 @@ static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
BUG();
}
}
-
- resp_cons = i;
+ blk_ring.rsp_cons = i;
+
kick_pending_request_queues();
spin_unlock_irqrestore(&blkif_io_lock, flags);
@@ -517,15 +511,15 @@ static void vbd_update(void)
#endif /* ENABLE_VBD_UPDATE */
/*============================================================================*/
-
static void kick_pending_request_queues(void)
{
/* We kick pending request queues if the ring is reasonably empty. */
if ( (nr_pending != 0) &&
- ((req_prod - resp_cons) < (BLKIF_RING_SIZE >> 1)) )
+ (RING_PENDING_REQUESTS(BLKIF_RING, &blk_ring) <
+ (RING_SIZE(BLKIF_RING, &blk_ring) >> 1)) )
{
/* Attempt to drain the queue, but bail if the ring becomes full. */
- while ( (nr_pending != 0) && !BLKIF_RING_FULL )
+ while ( (nr_pending != 0) && !RING_FULL(BLKIF_RING, &blk_ring) )
do_blkif_request(pending_queues[--nr_pending]);
}
}
@@ -819,8 +813,8 @@ static int blkif_queue_request(unsigned long id,
(sg_dev == device) &&
(sg_next_sect == sector_number) )
{
-
- req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod-1)].req;
+ req = RING_GET_REQUEST(BLKIF_RING, &blk_ring,
+ blk_ring.req_prod_pvt - 1);
bh = (struct buffer_head *)id;
bh->b_reqnext = (struct buffer_head *)rec_ring[req->id].id;
@@ -840,7 +834,7 @@ static int blkif_queue_request(unsigned long id,
return 0;
}
- else if ( BLKIF_RING_FULL )
+ else if ( RING_FULL(BLKIF_RING, &blk_ring) )
{
return 1;
}
@@ -857,7 +851,7 @@ static int blkif_queue_request(unsigned long id,
}
/* Fill out a communications ring structure. */
- req = &blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req;
+ req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt);
xid = GET_ID_FROM_FREELIST();
rec_ring[xid].id = id;
@@ -869,11 +863,11 @@ static int blkif_queue_request(unsigned long id,
req->nr_segments = 1;
req->frame_and_sects[0] = buffer_ma | (fsect<<3) | lsect;
- req_prod++;
-
/* Keep a private copy so we can reissue requests when recovering. */
translate_req_to_pfn(&rec_ring[xid], req );
+ blk_ring.req_prod_pvt++;
+
return 0;
}
@@ -962,7 +956,7 @@ void do_blkif_request(request_queue_t *rq)
static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
{
- BLKIF_RING_IDX i, rp;
+ RING_IDX i, rp;
unsigned long flags;
struct buffer_head *bh, *next_bh;
@@ -974,14 +968,15 @@ static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
return;
}
- rp = blk_ring->resp_prod;
+ rp = blk_ring.sring->rsp_prod;
rmb(); /* Ensure we see queued responses up to 'rp'. */
- for ( i = resp_cons; i != rp; i++ )
+ for ( i = blk_ring.rsp_cons; i != rp; i++ )
{
unsigned long id;
- blkif_response_t *bret = &blk_ring->ring[MASK_BLKIF_IDX(i)].resp;
-
+ blkif_response_t *bret;
+
+ bret = RING_GET_RESPONSE(BLKIF_RING, &blk_ring, i);
id = bret->id;
bh = (struct buffer_head *)rec_ring[id].id;
@@ -1011,10 +1006,10 @@ static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
default:
BUG();
}
+
}
+ blk_ring.rsp_cons = i;
- resp_cons = i;
-
kick_pending_request_queues();
spin_unlock_irqrestore(&io_request_lock, flags);
@@ -1028,31 +1023,33 @@ static void blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
void blkif_control_send(blkif_request_t *req, blkif_response_t *rsp)
{
unsigned long flags, id;
+ blkif_request_t *req_d;
retry:
- while ( (req_prod - resp_cons) == BLKIF_RING_SIZE )
+ while ( RING_FULL(BLKIF_RING, &blk_ring) )
{
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(1);
}
spin_lock_irqsave(&blkif_io_lock, flags);
- if ( (req_prod - resp_cons) == BLKIF_RING_SIZE )
+ if ( RING_FULL(BLKIF_RING, &blk_ring) )
{
spin_unlock_irqrestore(&blkif_io_lock, flags);
goto retry;
}
DISABLE_SCATTERGATHER();
- blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req = *req;
+ req_d = RING_GET_REQUEST(BLKIF_RING, &blk_ring, blk_ring.req_prod_pvt);
+ *req_d = *req;
id = GET_ID_FROM_FREELIST();
- blk_ring->ring[MASK_BLKIF_IDX(req_prod)].req.id = id;
+ req_d->id = id;
rec_ring[id].id = (unsigned long) req;
translate_req_to_pfn( &rec_ring[id], req );
- req_prod++;
+ blk_ring.req_prod_pvt++;
flush_requests();
spin_unlock_irqrestore(&blkif_io_lock, flags);
@@ -1094,7 +1091,7 @@ static void blkif_send_interface_connect(void)
blkif_fe_interface_connect_t *msg = (void*)cmsg.msg;
msg->handle = 0;
- msg->shmem_frame = (virt_to_machine(blk_ring) >> PAGE_SHIFT);
+ msg->shmem_frame = (virt_to_machine(blk_ring.sring) >> PAGE_SHIFT);
ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
}
@@ -1108,10 +1105,10 @@ static void blkif_free(void)
spin_unlock_irq(&blkif_io_lock);
/* Free resources associated with old device channel. */
- if ( blk_ring != NULL )
+ if ( blk_ring.sring != NULL )
{
- free_page((unsigned long)blk_ring);
- blk_ring = NULL;
+ free_page((unsigned long)blk_ring.sring);
+ blk_ring.sring = NULL;
}
free_irq(blkif_irq, NULL);
blkif_irq = 0;
@@ -1127,10 +1124,14 @@ static void blkif_close(void)
/* Move from CLOSED to DISCONNECTED state. */
static void blkif_disconnect(void)
{
- if ( blk_ring != NULL )
- free_page((unsigned long)blk_ring);
- blk_ring = (blkif_ring_t *)__get_free_page(GFP_KERNEL);
- blk_ring->req_prod = blk_ring->resp_prod = resp_cons = req_prod = 0;
+ blkif_sring_t *sring;
+
+ if ( blk_ring.sring != NULL )
+ free_page((unsigned long)blk_ring.sring);
+
+ sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL);
+ SHARED_RING_INIT(BLKIF_RING, sring);
+ FRONT_RING_INIT(BLKIF_RING, &blk_ring, sring);
blkif_state = BLKIF_STATE_DISCONNECTED;
blkif_send_interface_connect();
}
@@ -1144,34 +1145,37 @@ static void blkif_reset(void)
static void blkif_recover(void)
{
int i;
+ blkif_request_t *req;
/* Hmm, requests might be re-ordered when we re-issue them.
* This will need to be fixed once we have barriers */
/* Stage 1 : Find active and move to safety. */
- for ( i = 0; i < BLKIF_RING_SIZE; i++ )
+ for ( i = 0; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ )
{
if ( rec_ring[i].id >= PAGE_OFFSET )
{
- translate_req_to_mfn(
- &blk_ring->ring[req_prod].req, &rec_ring[i]);
- req_prod++;
+ req = RING_GET_REQUEST(BLKIF_RING, &blk_ring,
+ blk_ring.req_prod_pvt);
+ translate_req_to_mfn(req, &rec_ring[i]);
+ blk_ring.req_prod_pvt++;
}
}
/* Stage 2 : Set up shadow list. */
- for ( i = 0; i < req_prod; i++ )
+ for ( i = 0; i < blk_ring.req_prod_pvt; i++ )
{
- rec_ring[i].id = blk_ring->ring[i].req.id;
- blk_ring->ring[i].req.id = i;
- translate_req_to_pfn(&rec_ring[i], &blk_ring->ring[i].req);
+ req = RING_GET_REQUEST(BLKIF_RING, &blk_ring, i);
+ rec_ring[i].id = req->id;
+ req->id = i;
+ translate_req_to_pfn(&rec_ring[i], req);
}
/* Stage 3 : Set up free list. */
- for ( ; i < BLKIF_RING_SIZE; i++ )
+ for ( ; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ )
rec_ring[i].id = i+1;
- rec_ring_free = req_prod;
- rec_ring[BLKIF_RING_SIZE-1].id = 0x0fffffff;
+ rec_ring_free = blk_ring.req_prod_pvt;
+ rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)-1].id = 0x0fffffff;
/* blk_ring->req_prod will be set when we flush_requests().*/
wmb();
@@ -1233,7 +1237,8 @@ static void blkif_status(blkif_fe_interface_status_t *status)
{
if ( status->handle != blkif_handle )
{
- WPRINTK(" Invalid blkif: handle=%u", status->handle);
+ WPRINTK(" Invalid blkif: handle=%u\n", status->handle);
+ unexpected(status);
return;
}
@@ -1363,9 +1368,9 @@ int __init xlblk_init(void)
printk(KERN_INFO "xen_blk: Initialising virtual block device driver\n");
rec_ring_free = 0;
- for ( i = 0; i < BLKIF_RING_SIZE; i++ )
+ for ( i = 0; i < RING_SIZE(BLKIF_RING, &blk_ring); i++ )
rec_ring[i].id = i+1;
- rec_ring[BLKIF_RING_SIZE-1].id = 0x0fffffff;
+ rec_ring[RING_SIZE(BLKIF_RING, &blk_ring)-1].id = 0x0fffffff;
(void)ctrl_if_register_receiver(CMSG_BLKIF_FE, blkif_ctrlif_rx,
CALLBACK_IN_BLOCKING_CONTEXT);
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blkfront/block.h b/linux-2.6.10-xen-sparse/drivers/xen/blkfront/block.h
index 1edebd5e05..b2a38c1d66 100644
--- a/linux-2.6.10-xen-sparse/drivers/xen/blkfront/block.h
+++ b/linux-2.6.10-xen-sparse/drivers/xen/blkfront/block.h
@@ -46,6 +46,7 @@
#include <linux/devfs_fs_kernel.h>
#include <asm-xen/xen-public/xen.h>
#include <asm-xen/xen-public/io/blkif.h>
+#include <asm-xen/xen-public/io/ring.h>
#include <asm/io.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blktap/Makefile b/linux-2.6.10-xen-sparse/drivers/xen/blktap/Makefile
new file mode 100644
index 0000000000..80b7ca0627
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/drivers/xen/blktap/Makefile
@@ -0,0 +1,3 @@
+
+obj-y := blktap_userdev.o blktap_datapath.o blktap_controlmsg.o blktap.o
+
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap.c b/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap.c
new file mode 100644
index 0000000000..e4fbf390bc
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap.c
@@ -0,0 +1,86 @@
+/******************************************************************************
+ * blktap.c
+ *
+ * XenLinux virtual block-device tap.
+ *
+ * Copyright (c) 2004, Andrew Warfield
+ *
+ * Based on the original split block driver:
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
+ * Copyright (c) 2004, Christian Limpach
+ *
+ * Note that unlike the split block driver code, this driver has been developed
+ * strictly for Linux 2.6
+ */
+
+#include "blktap.h"
+
+int __init xlblk_init(void)
+{
+ ctrl_msg_t cmsg;
+ blkif_fe_driver_status_t fe_st;
+ blkif_be_driver_status_t be_st;
+
+ printk(KERN_INFO "Initialising Xen block tap device\n");
+
+ DPRINTK(" tap - Backend connection init:\n");
+
+
+ (void)ctrl_if_register_receiver(CMSG_BLKIF_FE, blkif_ctrlif_rx,
+ CALLBACK_IN_BLOCKING_CONTEXT);
+
+ /* Send a driver-UP notification to the domain controller. */
+ cmsg.type = CMSG_BLKIF_FE;
+ cmsg.subtype = CMSG_BLKIF_FE_DRIVER_STATUS;
+ cmsg.length = sizeof(blkif_fe_driver_status_t);
+ fe_st.status = BLKIF_DRIVER_STATUS_UP;
+ memcpy(cmsg.msg, &fe_st, sizeof(fe_st));
+ ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+
+ DPRINTK(" tap - Frontend connection init:\n");
+
+ active_reqs_init();
+ blkif_interface_init();
+ blkdev_schedule_init();
+
+ (void)ctrl_if_register_receiver(CMSG_BLKIF_BE, blkif_ctrlif_rx,
+ CALLBACK_IN_BLOCKING_CONTEXT);
+
+ /* Send a driver-UP notification to the domain controller. */
+ cmsg.type = CMSG_BLKIF_BE;
+ cmsg.subtype = CMSG_BLKIF_BE_DRIVER_STATUS;
+ cmsg.length = sizeof(blkif_be_driver_status_t);
+ be_st.status = BLKIF_DRIVER_STATUS_UP;
+ memcpy(cmsg.msg, &be_st, sizeof(be_st));
+ ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+
+ DPRINTK(" tap - Userland channel init:\n");
+
+ blktap_init();
+
+ DPRINTK("Blkif tap device initialized.\n");
+
+ return 0;
+}
+
+void blkdev_suspend(void)
+{
+}
+
+void blkdev_resume(void)
+{
+ ctrl_msg_t cmsg;
+ blkif_fe_driver_status_t st;
+
+ /* Send a driver-UP notification to the domain controller. */
+ cmsg.type = CMSG_BLKIF_FE;
+ cmsg.subtype = CMSG_BLKIF_FE_DRIVER_STATUS;
+ cmsg.length = sizeof(blkif_fe_driver_status_t);
+ st.status = BLKIF_DRIVER_STATUS_UP;
+ memcpy(cmsg.msg, &st, sizeof(st));
+ ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+}
+
+
+__initcall(xlblk_init);
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap.h b/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap.h
new file mode 100644
index 0000000000..2d67d592fc
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap.h
@@ -0,0 +1,239 @@
+/*
+ * blktap.h
+ *
+ * Interfaces for the Xen block tap driver.
+ *
+ * (c) 2004, Andrew Warfield, University of Cambridge
+ *
+ */
+
+#ifndef __BLKTAP_H__
+#define __BLKTAP_H__
+
+#include <linux/version.h>
+#include <linux/blkdev.h>
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <asm-xen/ctrl_if.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/pgalloc.h>
+#include <asm-xen/hypervisor.h>
+#include <asm-xen/xen-public/io/blkif.h>
+#include <asm-xen/xen-public/io/ring.h>
+
+/* Used to signal to the backend that this is a tap domain. */
+#define BLKTAP_COOKIE 0xbeadfeed
+
+/* -------[ debug / pretty printing ]--------------------------------- */
+
+#if 0
+#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \
+ __FILE__ , __LINE__ , ## _a )
+#else
+#define DPRINTK(_f, _a...) ((void)0)
+#endif
+
+#if 1
+#define ASSERT(_p) \
+ if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
+ __LINE__, __FILE__); *(int*)0=0; }
+#else
+#define ASSERT(_p) ((void)0)
+#endif
+
+#define WPRINTK(fmt, args...) printk(KERN_WARNING "blk_tap: " fmt, ##args)
+
+
+/* -------[ connection tracking ]------------------------------------- */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#define VMALLOC_VMADDR(x) ((unsigned long)(x))
+#endif
+
+extern spinlock_t blkif_io_lock;
+
+typedef struct blkif_st {
+ /* Unique identifier for this interface. */
+ domid_t domid;
+ unsigned int handle;
+ /* Physical parameters of the comms window. */
+ unsigned long shmem_frame;
+ unsigned int evtchn;
+ int irq;
+ /* Comms information. */
+ blkif_back_ring_t blk_ring;
+
+ enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
+ /*
+ * DISCONNECT response is deferred until pending requests are ack'ed.
+ * We therefore need to store the id from the original request.
+ */
+ u8 disconnect_rspid;
+ struct blkif_st *hash_next;
+ struct list_head blkdev_list;
+ spinlock_t blk_ring_lock;
+ atomic_t refcnt;
+ struct work_struct work;
+} blkif_t;
+
+blkif_t *blkif_find_by_handle(domid_t domid, unsigned int handle);
+void blkif_disconnect_complete(blkif_t *blkif);
+#define blkif_get(_b) (atomic_inc(&(_b)->refcnt))
+#define blkif_put(_b) \
+ do { \
+ if ( atomic_dec_and_test(&(_b)->refcnt) ) \
+ blkif_disconnect_complete(_b); \
+ } while (0)
+
+
+/* -------[ active request tracking ]--------------------------------- */
+
+typedef struct {
+ blkif_t *blkif;
+ unsigned long id;
+ int nr_pages;
+ unsigned long mach_fas[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ unsigned long virt_fas[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ int next_free;
+ int inuse; /* debugging */
+} active_req_t;
+
+typedef unsigned int ACTIVE_RING_IDX;
+
+active_req_t *lookup_active_req(ACTIVE_RING_IDX idx);
+inline unsigned int ID_TO_IDX(unsigned long id);
+inline domid_t ID_TO_DOM(unsigned long id);
+
+inline void active_reqs_init(void);
+
+/* -------[ interposition -> character device interface ]------------- */
+
+/* /dev/xen/blktap resides at device number major=10, minor=200 */
+#define BLKTAP_MINOR 202
+
+/* size of the extra VMA area to map in attached pages. */
+#define BLKTAP_VMA_PAGES BLKIF_RING_SIZE
+
+/* blktap IOCTLs: */
+#define BLKTAP_IOCTL_KICK_FE 1
+#define BLKTAP_IOCTL_KICK_BE 2
+#define BLKTAP_IOCTL_SETMODE 3
+#define BLKTAP_IOCTL_PRINT_IDXS 100
+
+/* blktap switching modes: (Set with BLKTAP_IOCTL_SETMODE) */
+#define BLKTAP_MODE_PASSTHROUGH 0x00000000 /* default */
+#define BLKTAP_MODE_INTERCEPT_FE 0x00000001
+#define BLKTAP_MODE_INTERCEPT_BE 0x00000002
+#define BLKTAP_MODE_COPY_FE 0x00000004
+#define BLKTAP_MODE_COPY_BE 0x00000008
+#define BLKTAP_MODE_COPY_FE_PAGES 0x00000010
+#define BLKTAP_MODE_COPY_BE_PAGES 0x00000020
+
+#define BLKTAP_MODE_INTERPOSE \
+ (BLKTAP_MODE_INTERCEPT_FE | BLKTAP_MODE_INTERCEPT_BE)
+
+#define BLKTAP_MODE_COPY_BOTH \
+ (BLKTAP_MODE_COPY_FE | BLKTAP_MODE_COPY_BE)
+
+#define BLKTAP_MODE_COPY_BOTH_PAGES \
+ (BLKTAP_MODE_COPY_FE_PAGES | BLKTAP_MODE_COPY_BE_PAGES)
+
+static inline int BLKTAP_MODE_VALID(unsigned long arg)
+{
+ return (
+ ( arg == BLKTAP_MODE_PASSTHROUGH ) ||
+ ( arg == BLKTAP_MODE_INTERCEPT_FE ) ||
+ ( arg == BLKTAP_MODE_INTERCEPT_BE ) ||
+ ( arg == BLKTAP_MODE_INTERPOSE ) ||
+ ( (arg & ~BLKTAP_MODE_COPY_FE_PAGES) == BLKTAP_MODE_COPY_FE ) ||
+ ( (arg & ~BLKTAP_MODE_COPY_BE_PAGES) == BLKTAP_MODE_COPY_BE ) ||
+ ( (arg & ~BLKTAP_MODE_COPY_BOTH_PAGES) == BLKTAP_MODE_COPY_BOTH )
+ );
+}
+
+
+
+/* -------[ Mappings to User VMA ]------------------------------------ */
+#define MAX_PENDING_REQS 64
+#define BATCH_PER_DOMAIN 16
+extern struct vm_area_struct *blktap_vma;
+
+/* The following are from blkback.c and should probably be put in a
+ * header and included from there.
+ * The mmap area described here is where attached data pages eill be mapped.
+ */
+
+extern unsigned long mmap_vstart;
+#define MMAP_PAGES_PER_REQUEST \
+ (BLKIF_MAX_SEGMENTS_PER_REQUEST + 1)
+#define MMAP_PAGES \
+ (MAX_PENDING_REQS * MMAP_PAGES_PER_REQUEST)
+#define MMAP_VADDR(_req,_seg) \
+ (mmap_vstart + \
+ ((_req) * MMAP_PAGES_PER_REQUEST * PAGE_SIZE) + \
+ ((_seg) * PAGE_SIZE))
+
+/* immediately before the mmap area, we have a bunch of pages reserved
+ * for shared memory rings.
+ */
+
+#define RING_PAGES 128
+extern unsigned long rings_vstart;
+
+
+/* -------[ Here be globals ]----------------------------------------- */
+extern unsigned long blktap_mode;
+
+/* Connection to a single backend domain. */
+extern blkif_front_ring_t blktap_be_ring;
+
+/* Event channel to backend domain. */
+extern unsigned int blkif_ptbe_evtchn;
+
+/* User ring status... this will soon vanish into a ring struct. */
+extern unsigned long blktap_ring_ok;
+
+/* -------[ ...and function prototypes. ]----------------------------- */
+
+/* init function for character device interface. */
+int blktap_init(void);
+
+/* init function for the blkif cache. */
+void __init blkif_interface_init(void);
+void __init blkdev_schedule_init(void);
+void blkif_deschedule(blkif_t *blkif);
+
+/* interfaces to the char driver, passing messages to and from apps. */
+void blktap_kick_user(void);
+
+/* user ring access functions: */
+int blktap_write_fe_ring(blkif_request_t *req);
+int blktap_write_be_ring(blkif_response_t *rsp);
+int blktap_read_fe_ring(void);
+int blktap_read_be_ring(void);
+
+/* fe/be ring access functions: */
+int write_resp_to_fe_ring(blkif_t *blkif, blkif_response_t *rsp);
+int write_req_to_be_ring(blkif_request_t *req);
+
+/* event notification functions */
+inline void kick_fe_domain(blkif_t *blkif);
+inline void kick_be_domain(void);
+
+/* Interrupt handlers. */
+irqreturn_t blkif_ptbe_int(int irq, void *dev_id,
+ struct pt_regs *ptregs);
+irqreturn_t blkif_ptfe_int(int irq, void *dev_id, struct pt_regs *regs);
+
+/* Control message receiver. */
+extern void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id);
+
+/* debug */
+void print_vm_ring_idxs(void);
+
+#define __BLKINT_H__
+#endif
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_controlmsg.c b/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_controlmsg.c
new file mode 100644
index 0000000000..b3cd111897
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_controlmsg.c
@@ -0,0 +1,510 @@
+/******************************************************************************
+ * blktap_controlmsg.c
+ *
+ * XenLinux virtual block-device tap.
+ * Control interfaces to the frontend and backend drivers.
+ *
+ * Copyright (c) 2004, Andrew Warfield
+ *
+ */
+
+#include "blktap.h"
+
+#define BLKIF_STATE_CLOSED 0
+#define BLKIF_STATE_DISCONNECTED 1
+#define BLKIF_STATE_CONNECTED 2
+
+static char *blkif_state_name[] = {
+ [BLKIF_STATE_CLOSED] = "closed",
+ [BLKIF_STATE_DISCONNECTED] = "disconnected",
+ [BLKIF_STATE_CONNECTED] = "connected",
+};
+
+static char * blkif_status_name[] = {
+ [BLKIF_INTERFACE_STATUS_CLOSED] = "closed",
+ [BLKIF_INTERFACE_STATUS_DISCONNECTED] = "disconnected",
+ [BLKIF_INTERFACE_STATUS_CONNECTED] = "connected",
+ [BLKIF_INTERFACE_STATUS_CHANGED] = "changed",
+};
+static unsigned int blkif_pt_state = BLKIF_STATE_CLOSED;
+static unsigned blkif_ptbe_irq;
+unsigned int blkif_ptbe_evtchn;
+
+/*-----[ Control Messages to/from Frontend VMs ]--------------------------*/
+
+#define BLKIF_HASHSZ 1024
+#define BLKIF_HASH(_d,_h) (((int)(_d)^(int)(_h))&(BLKIF_HASHSZ-1))
+
+static kmem_cache_t *blkif_cachep;
+static blkif_t *blkif_hash[BLKIF_HASHSZ];
+
+blkif_t *blkif_find_by_handle(domid_t domid, unsigned int handle)
+{
+ blkif_t *blkif = blkif_hash[BLKIF_HASH(domid, handle)];
+ while ( (blkif != NULL) &&
+ ((blkif->domid != domid) || (blkif->handle != handle)) )
+ blkif = blkif->hash_next;
+ return blkif;
+}
+
+static void __blkif_disconnect_complete(void *arg)
+{
+ blkif_t *blkif = (blkif_t *)arg;
+ ctrl_msg_t cmsg;
+ blkif_be_disconnect_t disc;
+
+ /*
+ * These can't be done in blkif_disconnect() because at that point there
+ * may be outstanding requests at the disc whose asynchronous responses
+ * must still be notified to the remote driver.
+ */
+ unbind_evtchn_from_irq(blkif->evtchn);
+ vfree(blkif->blk_ring.sring);
+
+ /* Construct the deferred response message. */
+ cmsg.type = CMSG_BLKIF_BE;
+ cmsg.subtype = CMSG_BLKIF_BE_DISCONNECT;
+ cmsg.id = blkif->disconnect_rspid;
+ cmsg.length = sizeof(blkif_be_disconnect_t);
+ disc.domid = blkif->domid;
+ disc.blkif_handle = blkif->handle;
+ disc.status = BLKIF_BE_STATUS_OKAY;
+ memcpy(cmsg.msg, &disc, sizeof(disc));
+
+ /*
+ * Make sure message is constructed /before/ status change, because
+ * after the status change the 'blkif' structure could be deallocated at
+ * any time. Also make sure we send the response /after/ status change,
+ * as otherwise a subsequent CONNECT request could spuriously fail if
+ * another CPU doesn't see the status change yet.
+ */
+ mb();
+ if ( blkif->status != DISCONNECTING )
+ BUG();
+ blkif->status = DISCONNECTED;
+ mb();
+
+ /* Send the successful response. */
+ ctrl_if_send_response(&cmsg);
+}
+
+void blkif_disconnect_complete(blkif_t *blkif)
+{
+ INIT_WORK(&blkif->work, __blkif_disconnect_complete, (void *)blkif);
+ schedule_work(&blkif->work);
+}
+
+void blkif_ptfe_create(blkif_be_create_t *create)
+{
+ blkif_t *blkif, **pblkif;
+ domid_t domid = create->domid;
+ unsigned int handle = create->blkif_handle;
+
+
+ /* May want to store info on the connecting domain here. */
+
+ DPRINTK("PT got BE_CREATE\n");
+
+ if ( (blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL)) == NULL )
+ {
+ DPRINTK("Could not create blkif: out of memory\n");
+ create->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
+ return;
+ }
+
+ /* blkif struct init code from blkback.c */
+ memset(blkif, 0, sizeof(*blkif));
+ blkif->domid = domid;
+ blkif->handle = handle;
+ blkif->status = DISCONNECTED;
+ spin_lock_init(&blkif->blk_ring_lock);
+ atomic_set(&blkif->refcnt, 0);
+
+ pblkif = &blkif_hash[BLKIF_HASH(domid, handle)];
+ while ( *pblkif != NULL )
+ {
+ if ( ((*pblkif)->domid == domid) && ((*pblkif)->handle == handle) )
+ {
+ DPRINTK("Could not create blkif: already exists\n");
+ create->status = BLKIF_BE_STATUS_INTERFACE_EXISTS;
+ kmem_cache_free(blkif_cachep, blkif);
+ return;
+ }
+ pblkif = &(*pblkif)->hash_next;
+ }
+
+ blkif->hash_next = *pblkif;
+ *pblkif = blkif;
+
+ create->status = BLKIF_BE_STATUS_OKAY;
+}
+
+
+void blkif_ptfe_destroy(blkif_be_destroy_t *destroy)
+{
+ /* Clear anything that we initialized above. */
+
+ domid_t domid = destroy->domid;
+ unsigned int handle = destroy->blkif_handle;
+ blkif_t **pblkif, *blkif;
+
+ DPRINTK("PT got BE_DESTROY\n");
+
+ pblkif = &blkif_hash[BLKIF_HASH(domid, handle)];
+ while ( (blkif = *pblkif) != NULL )
+ {
+ if ( (blkif->domid == domid) && (blkif->handle == handle) )
+ {
+ if ( blkif->status != DISCONNECTED )
+ goto still_connected;
+ goto destroy;
+ }
+ pblkif = &blkif->hash_next;
+ }
+
+ destroy->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return;
+
+ still_connected:
+ destroy->status = BLKIF_BE_STATUS_INTERFACE_CONNECTED;
+ return;
+
+ destroy:
+ *pblkif = blkif->hash_next;
+ kmem_cache_free(blkif_cachep, blkif);
+ destroy->status = BLKIF_BE_STATUS_OKAY;
+}
+
+void blkif_ptfe_connect(blkif_be_connect_t *connect)
+{
+ domid_t domid = connect->domid;
+ unsigned int handle = connect->blkif_handle;
+ unsigned int evtchn = connect->evtchn;
+ unsigned long shmem_frame = connect->shmem_frame;
+ struct vm_struct *vma;
+ pgprot_t prot;
+ int error;
+ blkif_t *blkif;
+ blkif_sring_t *sring;
+
+ DPRINTK("PT got BE_CONNECT\n");
+
+ blkif = blkif_find_by_handle(domid, handle);
+ if ( unlikely(blkif == NULL) )
+ {
+ DPRINTK("blkif_connect attempted for non-existent blkif (%u,%u)\n",
+ connect->domid, connect->blkif_handle);
+ connect->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return;
+ }
+
+ if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL )
+ {
+ connect->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
+ return;
+ }
+
+ prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED);
+ error = direct_remap_area_pages(&init_mm, VMALLOC_VMADDR(vma->addr),
+ shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
+ prot, domid);
+ if ( error != 0 )
+ {
+ WPRINTK("BE_CONNECT: error! (%d)\n", error);
+ if ( error == -ENOMEM )
+ connect->status = BLKIF_BE_STATUS_OUT_OF_MEMORY;
+ else if ( error == -EFAULT ) {
+ connect->status = BLKIF_BE_STATUS_MAPPING_ERROR;
+ WPRINTK("BE_CONNECT: MAPPING error!\n");
+ }
+ else
+ connect->status = BLKIF_BE_STATUS_ERROR;
+ vfree(vma->addr);
+ return;
+ }
+
+ if ( blkif->status != DISCONNECTED )
+ {
+ connect->status = BLKIF_BE_STATUS_INTERFACE_CONNECTED;
+ vfree(vma->addr);
+ return;
+ }
+
+ sring = (blkif_sring_t *)vma->addr;
+ SHARED_RING_INIT(BLKIF_RING, sring);
+ BACK_RING_INIT(BLKIF_RING, &blkif->blk_ring, sring);
+
+ blkif->evtchn = evtchn;
+ blkif->irq = bind_evtchn_to_irq(evtchn);
+ blkif->shmem_frame = shmem_frame;
+ blkif->status = CONNECTED;
+ blkif_get(blkif);
+
+ request_irq(blkif->irq, blkif_ptfe_int, 0, "blkif-pt-backend", blkif);
+
+ connect->status = BLKIF_BE_STATUS_OKAY;
+}
+
+int blkif_ptfe_disconnect(blkif_be_disconnect_t *disconnect, u8 rsp_id)
+{
+ domid_t domid = disconnect->domid;
+ unsigned int handle = disconnect->blkif_handle;
+ blkif_t *blkif;
+
+ DPRINTK("PT got BE_DISCONNECT\n");
+
+ blkif = blkif_find_by_handle(domid, handle);
+ if ( unlikely(blkif == NULL) )
+ {
+ DPRINTK("blkif_disconnect attempted for non-existent blkif"
+ " (%u,%u)\n", disconnect->domid, disconnect->blkif_handle);
+ disconnect->status = BLKIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return 1; /* Caller will send response error message. */
+ }
+
+ if ( blkif->status == CONNECTED )
+ {
+ blkif->status = DISCONNECTING;
+ blkif->disconnect_rspid = rsp_id;
+ wmb(); /* Let other CPUs see the status change. */
+ free_irq(blkif->irq, blkif);
+ blkif_deschedule(blkif);
+ blkif_put(blkif);
+ return 0; /* Caller should not send response message. */
+ }
+
+ disconnect->status = BLKIF_BE_STATUS_OKAY;
+ return 1;
+}
+
+/*-----[ Control Messages to/from Backend VM ]----------------------------*/
+
+/* Tell the controller to bring up the interface. */
+static void blkif_ptbe_send_interface_connect(void)
+{
+ ctrl_msg_t cmsg = {
+ .type = CMSG_BLKIF_FE,
+ .subtype = CMSG_BLKIF_FE_INTERFACE_CONNECT,
+ .length = sizeof(blkif_fe_interface_connect_t),
+ };
+ blkif_fe_interface_connect_t *msg = (void*)cmsg.msg;
+ msg->handle = 0;
+ msg->shmem_frame = virt_to_machine(blktap_be_ring.sring) >> PAGE_SHIFT;
+
+ ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+}
+
+static void blkif_ptbe_close(void)
+{
+}
+
+/* Move from CLOSED to DISCONNECTED state. */
+static void blkif_ptbe_disconnect(void)
+{
+ blkif_sring_t *sring;
+
+ sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL);
+ SHARED_RING_INIT(BLKIF_RING, sring);
+ FRONT_RING_INIT(BLKIF_RING, &blktap_be_ring, sring);
+ blkif_pt_state = BLKIF_STATE_DISCONNECTED;
+ DPRINTK("Blkif-Passthrough-BE is now DISCONNECTED.\n");
+ blkif_ptbe_send_interface_connect();
+}
+
+static void blkif_ptbe_connect(blkif_fe_interface_status_t *status)
+{
+ int err = 0;
+
+ blkif_ptbe_evtchn = status->evtchn;
+ blkif_ptbe_irq = bind_evtchn_to_irq(blkif_ptbe_evtchn);
+
+ err = request_irq(blkif_ptbe_irq, blkif_ptbe_int,
+ SA_SAMPLE_RANDOM, "blkif", NULL);
+ if ( err ) {
+ WPRINTK("blkfront request_irq failed (%d)\n", err);
+ return;
+ } else {
+ /* transtion to connected in case we need to do a
+ a partion probe on a whole disk */
+ blkif_pt_state = BLKIF_STATE_CONNECTED;
+ }
+}
+
+static void unexpected(blkif_fe_interface_status_t *status)
+{
+ WPRINTK(" TAP: Unexpected blkif status %s in state %s\n",
+ blkif_status_name[status->status],
+ blkif_state_name[blkif_pt_state]);
+}
+
+static void blkif_ptbe_status(
+ blkif_fe_interface_status_t *status)
+{
+ if ( status->handle != 0 )
+ {
+ DPRINTK("Status change on unsupported blkif %d\n",
+ status->handle);
+ return;
+ }
+
+ DPRINTK("ptbe_status: got %s\n", blkif_status_name[status->status]);
+
+ switch ( status->status )
+ {
+ case BLKIF_INTERFACE_STATUS_CLOSED:
+ switch ( blkif_pt_state )
+ {
+ case BLKIF_STATE_CLOSED:
+ unexpected(status);
+ break;
+ case BLKIF_STATE_DISCONNECTED:
+ case BLKIF_STATE_CONNECTED:
+ unexpected(status);
+ blkif_ptbe_close();
+ break;
+ }
+ break;
+
+ case BLKIF_INTERFACE_STATUS_DISCONNECTED:
+ switch ( blkif_pt_state )
+ {
+ case BLKIF_STATE_CLOSED:
+ blkif_ptbe_disconnect();
+ break;
+ case BLKIF_STATE_DISCONNECTED:
+ case BLKIF_STATE_CONNECTED:
+ printk(KERN_ALERT "*** add recovery code to the tap driver. ***\n");
+ unexpected(status);
+ break;
+ }
+ break;
+
+ case BLKIF_INTERFACE_STATUS_CONNECTED:
+ switch ( blkif_pt_state )
+ {
+ case BLKIF_STATE_CLOSED:
+ unexpected(status);
+ blkif_ptbe_disconnect();
+ blkif_ptbe_connect(status);
+ break;
+ case BLKIF_STATE_DISCONNECTED:
+ blkif_ptbe_connect(status);
+ break;
+ case BLKIF_STATE_CONNECTED:
+ unexpected(status);
+ blkif_ptbe_connect(status);
+ break;
+ }
+ break;
+
+ case BLKIF_INTERFACE_STATUS_CHANGED:
+ switch ( blkif_pt_state )
+ {
+ case BLKIF_STATE_CLOSED:
+ case BLKIF_STATE_DISCONNECTED:
+ unexpected(status);
+ break;
+ case BLKIF_STATE_CONNECTED:
+ /* vbd_update(); */
+ /* tap doesn't really get state changes... */
+ unexpected(status);
+ break;
+ }
+ break;
+
+ default:
+ DPRINTK("Status change to unknown value %d\n", status->status);
+ break;
+ }
+}
+
+/*-----[ All control messages enter here: ]-------------------------------*/
+
+void blkif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
+{
+ switch ( msg->type )
+ {
+ case CMSG_BLKIF_FE:
+
+ switch ( msg->subtype )
+ {
+ case CMSG_BLKIF_FE_INTERFACE_STATUS:
+ if ( msg->length != sizeof(blkif_fe_interface_status_t) )
+ goto parse_error;
+ blkif_ptbe_status((blkif_fe_interface_status_t *) &msg->msg[0]);
+ break;
+
+ default:
+ goto parse_error;
+ }
+
+ case CMSG_BLKIF_BE:
+
+ switch ( msg->subtype )
+ {
+ case CMSG_BLKIF_BE_CREATE:
+ if ( msg->length != sizeof(blkif_be_create_t) )
+ goto parse_error;
+ blkif_ptfe_create((blkif_be_create_t *)&msg->msg[0]);
+ break;
+ case CMSG_BLKIF_BE_DESTROY:
+ if ( msg->length != sizeof(blkif_be_destroy_t) )
+ goto parse_error;
+ blkif_ptfe_destroy((blkif_be_destroy_t *)&msg->msg[0]);
+ break;
+ case CMSG_BLKIF_BE_CONNECT:
+ if ( msg->length != sizeof(blkif_be_connect_t) )
+ goto parse_error;
+ blkif_ptfe_connect((blkif_be_connect_t *)&msg->msg[0]);
+ break;
+ case CMSG_BLKIF_BE_DISCONNECT:
+ if ( msg->length != sizeof(blkif_be_disconnect_t) )
+ goto parse_error;
+ if ( !blkif_ptfe_disconnect((blkif_be_disconnect_t *)&msg->msg[0],
+ msg->id) )
+ return;
+ break;
+
+ /* We just ignore anything to do with vbds for now. */
+
+ case CMSG_BLKIF_BE_VBD_CREATE:
+ DPRINTK("PT got VBD_CREATE\n");
+ ((blkif_be_vbd_create_t *)&msg->msg[0])->status
+ = BLKIF_BE_STATUS_OKAY;
+ break;
+ case CMSG_BLKIF_BE_VBD_DESTROY:
+ DPRINTK("PT got VBD_DESTROY\n");
+ ((blkif_be_vbd_destroy_t *)&msg->msg[0])->status
+ = BLKIF_BE_STATUS_OKAY;
+ break;
+ case CMSG_BLKIF_BE_VBD_GROW:
+ DPRINTK("PT got VBD_GROW\n");
+ ((blkif_be_vbd_grow_t *)&msg->msg[0])->status
+ = BLKIF_BE_STATUS_OKAY;
+ break;
+ case CMSG_BLKIF_BE_VBD_SHRINK:
+ DPRINTK("PT got VBD_SHRINK\n");
+ ((blkif_be_vbd_shrink_t *)&msg->msg[0])->status
+ = BLKIF_BE_STATUS_OKAY;
+ break;
+ default:
+ goto parse_error;
+ }
+ }
+
+ ctrl_if_send_response(msg);
+ return;
+
+ parse_error:
+ msg->length = 0;
+ ctrl_if_send_response(msg);
+}
+
+/*-----[ All control messages enter here: ]-------------------------------*/
+
+void __init blkif_interface_init(void)
+{
+ blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t),
+ 0, 0, NULL, NULL);
+ memset(blkif_hash, 0, sizeof(blkif_hash));
+}
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_datapath.c b/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_datapath.c
new file mode 100644
index 0000000000..367a83cecc
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_datapath.c
@@ -0,0 +1,468 @@
+/******************************************************************************
+ * blktap_datapath.c
+ *
+ * XenLinux virtual block-device tap.
+ * Block request routing data path.
+ *
+ * Copyright (c) 2004, Andrew Warfield
+ * -- see full header in blktap.c
+ */
+
+#include "blktap.h"
+#include <asm-xen/evtchn.h>
+
+/*-----[ The data paths ]-------------------------------------------------*/
+
+/* Connection to a single backend domain. */
+blkif_front_ring_t blktap_be_ring;
+
+/*-----[ Tracking active requests ]---------------------------------------*/
+
+/* this must be the same as MAX_PENDING_REQS in blkback.c */
+#define MAX_ACTIVE_REQS ((ACTIVE_RING_IDX)64U)
+
+active_req_t active_reqs[MAX_ACTIVE_REQS];
+ACTIVE_RING_IDX active_req_ring[MAX_ACTIVE_REQS];
+spinlock_t active_req_lock = SPIN_LOCK_UNLOCKED;
+ACTIVE_RING_IDX active_prod, active_cons;
+#define MASK_ACTIVE_IDX(_i) ((_i)&(MAX_ACTIVE_REQS-1))
+#define ACTIVE_IDX(_ar) (_ar - active_reqs)
+#define NR_ACTIVE_REQS (MAX_ACTIVE_REQS - active_prod + active_cons)
+
+inline active_req_t *get_active_req(void)
+{
+ ACTIVE_RING_IDX idx;
+ active_req_t *ar;
+ unsigned long flags;
+
+ ASSERT(active_cons != active_prod);
+
+ spin_lock_irqsave(&active_req_lock, flags);
+ idx = active_req_ring[MASK_ACTIVE_IDX(active_cons++)];
+ ar = &active_reqs[idx];
+if (ar->inuse) WPRINTK("AR INUSE! (%lu)\n", ar->id);
+ar->inuse = 1;
+ spin_unlock_irqrestore(&active_req_lock, flags);
+
+ return ar;
+}
+
+inline void free_active_req(active_req_t *ar)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&active_req_lock, flags);
+ar->inuse = 0;
+ active_req_ring[MASK_ACTIVE_IDX(active_prod++)] = ACTIVE_IDX(ar);
+ spin_unlock_irqrestore(&active_req_lock, flags);
+}
+
+active_req_t *lookup_active_req(ACTIVE_RING_IDX idx)
+{
+ return &active_reqs[idx];
+}
+
+inline void active_reqs_init(void)
+{
+ ACTIVE_RING_IDX i;
+
+ active_cons = 0;
+ active_prod = MAX_ACTIVE_REQS;
+ memset(active_reqs, 0, sizeof(active_reqs));
+ for ( i = 0; i < MAX_ACTIVE_REQS; i++ )
+ active_req_ring[i] = i;
+}
+
+/* Requests passing through the tap to the backend hijack the id field
+ * in the request message. In it we put the AR index _AND_ the fe domid.
+ * the domid is used by the backend to map the pages properly.
+ */
+
+static inline unsigned long MAKE_ID(domid_t fe_dom, ACTIVE_RING_IDX idx)
+{
+ return ( (fe_dom << 16) | idx );
+}
+
+inline unsigned int ID_TO_IDX(unsigned long id)
+{
+ return ( id & 0x0000ffff );
+}
+
+inline domid_t ID_TO_DOM(unsigned long id) { return (id >> 16); }
+
+/*-----[ Ring helpers ]---------------------------------------------------*/
+
+inline int write_resp_to_fe_ring(blkif_t *blkif, blkif_response_t *rsp)
+{
+ blkif_response_t *resp_d;
+ active_req_t *ar;
+
+ /* remap id, and free the active req. blkif lookup goes here too.*/
+ ar = &active_reqs[ID_TO_IDX(rsp->id)];
+ /* WPRINTK("%3u > %3lu\n", ID_TO_IDX(rsp->id), ar->id); */
+ rsp->id = ar->id;
+ free_active_req(ar);
+
+ resp_d = RING_GET_RESPONSE(BLKIF_RING, &blkif->blk_ring,
+ blkif->blk_ring.rsp_prod_pvt);
+ memcpy(resp_d, rsp, sizeof(blkif_response_t));
+ wmb();
+ blkif->blk_ring.rsp_prod_pvt++;
+
+ return 0;
+}
+
+inline int write_req_to_be_ring(blkif_request_t *req)
+{
+ blkif_request_t *req_d;
+
+ req_d = RING_GET_REQUEST(BLKIF_RING, &blktap_be_ring,
+ blktap_be_ring.req_prod_pvt);
+ memcpy(req_d, req, sizeof(blkif_request_t));
+ wmb();
+ blktap_be_ring.req_prod_pvt++;
+
+ return 0;
+}
+
+inline void kick_fe_domain(blkif_t *blkif)
+{
+ RING_PUSH_RESPONSES(BLKIF_RING, &blkif->blk_ring);
+ notify_via_evtchn(blkif->evtchn);
+ DPRINTK("notified FE(dom %u)\n", blkif->domid);
+
+}
+
+inline void kick_be_domain(void)
+{
+ wmb(); /* Ensure that the frontend can see the requests. */
+ RING_PUSH_REQUESTS(BLKIF_RING, &blktap_be_ring);
+ notify_via_evtchn(blkif_ptbe_evtchn);
+ DPRINTK("notified BE\n");
+}
+
+/*-----[ Data to/from Frontend (client) VMs ]-----------------------------*/
+
+/*-----[ Scheduler list maint -from blkback ]--- */
+
+static struct list_head blkio_schedule_list;
+static spinlock_t blkio_schedule_list_lock;
+
+static int __on_blkdev_list(blkif_t *blkif)
+{
+ return blkif->blkdev_list.next != NULL;
+}
+
+static void remove_from_blkdev_list(blkif_t *blkif)
+{
+ unsigned long flags;
+ if ( !__on_blkdev_list(blkif) ) return;
+ spin_lock_irqsave(&blkio_schedule_list_lock, flags);
+ if ( __on_blkdev_list(blkif) )
+ {
+ list_del(&blkif->blkdev_list);
+ blkif->blkdev_list.next = NULL;
+ blkif_put(blkif);
+ }
+ spin_unlock_irqrestore(&blkio_schedule_list_lock, flags);
+}
+
+static void add_to_blkdev_list_tail(blkif_t *blkif)
+{
+ unsigned long flags;
+ if ( __on_blkdev_list(blkif) ) return;
+ spin_lock_irqsave(&blkio_schedule_list_lock, flags);
+ if ( !__on_blkdev_list(blkif) && (blkif->status == CONNECTED) )
+ {
+ list_add_tail(&blkif->blkdev_list, &blkio_schedule_list);
+ blkif_get(blkif);
+ }
+ spin_unlock_irqrestore(&blkio_schedule_list_lock, flags);
+}
+
+
+/*-----[ Scheduler functions - from blkback ]--- */
+
+static DECLARE_WAIT_QUEUE_HEAD(blkio_schedule_wait);
+
+static int do_block_io_op(blkif_t *blkif, int max_to_do);
+
+static int blkio_schedule(void *arg)
+{
+ DECLARE_WAITQUEUE(wq, current);
+
+ blkif_t *blkif;
+ struct list_head *ent;
+
+ daemonize(
+ "xentapd"
+ );
+
+ for ( ; ; )
+ {
+ /* Wait for work to do. */
+ add_wait_queue(&blkio_schedule_wait, &wq);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if ( (NR_ACTIVE_REQS == MAX_ACTIVE_REQS) ||
+ list_empty(&blkio_schedule_list) )
+ schedule();
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&blkio_schedule_wait, &wq);
+
+ /* Queue up a batch of requests. */
+ while ( (NR_ACTIVE_REQS < MAX_ACTIVE_REQS) &&
+ !list_empty(&blkio_schedule_list) )
+ {
+ ent = blkio_schedule_list.next;
+ blkif = list_entry(ent, blkif_t, blkdev_list);
+ blkif_get(blkif);
+ remove_from_blkdev_list(blkif);
+ if ( do_block_io_op(blkif, BATCH_PER_DOMAIN) )
+ add_to_blkdev_list_tail(blkif);
+ blkif_put(blkif);
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+ /* Push the batch through to disc. */
+ run_task_queue(&tq_disk);
+#endif
+ }
+}
+
+static void maybe_trigger_blkio_schedule(void)
+{
+ /*
+ * Needed so that two processes, who together make the following predicate
+ * true, don't both read stale values and evaluate the predicate
+ * incorrectly. Incredibly unlikely to stall the scheduler on x86, but...
+ */
+ smp_mb();
+
+ if ( (NR_ACTIVE_REQS < (MAX_ACTIVE_REQS)) && /* XXX!!! was M_A_R/2*/
+ !list_empty(&blkio_schedule_list) )
+ wake_up(&blkio_schedule_wait);
+}
+
+void blkif_deschedule(blkif_t *blkif)
+{
+ remove_from_blkdev_list(blkif);
+}
+
+void __init blkdev_schedule_init(void)
+{
+ spin_lock_init(&blkio_schedule_list_lock);
+ INIT_LIST_HEAD(&blkio_schedule_list);
+
+ if ( kernel_thread(blkio_schedule, 0, CLONE_FS | CLONE_FILES) < 0 )
+ BUG();
+}
+
+/*-----[ Interrupt entry from a frontend ]------ */
+
+irqreturn_t blkif_ptfe_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ blkif_t *blkif = dev_id;
+
+ add_to_blkdev_list_tail(blkif);
+ maybe_trigger_blkio_schedule();
+ return IRQ_HANDLED;
+}
+
+/*-----[ Other Frontend Ring functions ]-------- */
+
+/* irqreturn_t blkif_ptfe_int(int irq, void *dev_id, struct pt_regs *regs)*/
+static int do_block_io_op(blkif_t *blkif, int max_to_do)
+{
+ /* we have pending messages from the real frontend. */
+
+ blkif_request_t *req_s;
+ RING_IDX i, rp;
+ unsigned long flags;
+ active_req_t *ar;
+ int more_to_do = 0;
+ int notify_be = 0, notify_user = 0;
+
+ DPRINTK("PT got FE interrupt.\n");
+
+ if (NR_ACTIVE_REQS == MAX_ACTIVE_REQS) return 1;
+
+ /* lock both rings */
+ spin_lock_irqsave(&blkif_io_lock, flags);
+
+ rp = blkif->blk_ring.sring->req_prod;
+ rmb();
+
+ for ( i = blkif->blk_ring.req_cons;
+ (i != rp) &&
+ !RING_REQUEST_CONS_OVERFLOW(BLKIF_RING, &blkif->blk_ring, i);
+ i++ )
+ {
+
+ if ((--max_to_do == 0) || (NR_ACTIVE_REQS == MAX_ACTIVE_REQS))
+ {
+ more_to_do = 1;
+ break;
+ }
+
+ req_s = RING_GET_REQUEST(BLKIF_RING, &blkif->blk_ring, i);
+ /* This is a new request:
+ * Assign an active request record, and remap the id.
+ */
+ ar = get_active_req();
+ ar->id = req_s->id;
+ ar->blkif = blkif;
+ req_s->id = MAKE_ID(blkif->domid, ACTIVE_IDX(ar));
+ /* WPRINTK("%3u < %3lu\n", ID_TO_IDX(req_s->id), ar->id); */
+
+ /* FE -> BE interposition point is here. */
+
+ /* ------------------------------------------------------------- */
+ /* BLKIF_OP_PROBE_HACK: */
+ /* Signal to the backend that we are a tap domain. */
+
+ if (req_s->operation == BLKIF_OP_PROBE) {
+ DPRINTK("Adding BLKTAP_COOKIE to PROBE request.\n");
+ req_s->frame_and_sects[1] = BLKTAP_COOKIE;
+ }
+
+ /* ------------------------------------------------------------- */
+
+ /* If we are in MODE_INTERCEPT_FE or MODE_COPY_FE: */
+ if ( (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) ||
+ (blktap_mode & BLKTAP_MODE_COPY_FE) ) {
+
+ /* Copy the response message to UFERing */
+ /* In MODE_INTERCEPT_FE, map attached pages into the app vma */
+ /* In MODE_COPY_FE_PAGES, copy attached pages into the app vma */
+
+ DPRINTK("req->UFERing\n");
+ blktap_write_fe_ring(req_s);
+ notify_user = 1;
+ }
+
+ /* If we are not in MODE_INTERCEPT_FE or MODE_INTERCEPT_BE: */
+ if ( !((blktap_mode & BLKTAP_MODE_INTERCEPT_FE) ||
+ (blktap_mode & BLKTAP_MODE_INTERCEPT_BE)) ) {
+
+ /* be included to prevent noise from the fe when its off */
+ /* copy the request message to the BERing */
+
+ DPRINTK("blktap: FERing[%u] -> BERing[%u]\n",
+ (unsigned)__SHARED_RING_MASK(BLKIF_RING,
+ blktap_be_ring.sring, i),
+ (unsigned)__SHARED_RING_MASK(BLKIF_RING,
+ blktap_be_ring.sring, blktap_be_ring.req_prod_pvt));
+
+ write_req_to_be_ring(req_s);
+ notify_be = 1;
+ }
+ }
+
+ blkif->blk_ring.req_cons = i;
+
+ /* unlock rings */
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+ if (notify_user)
+ blktap_kick_user();
+ if (notify_be)
+ kick_be_domain();
+
+ return more_to_do;
+}
+
+/*-----[ Data to/from Backend (server) VM ]------------------------------*/
+
+
+irqreturn_t blkif_ptbe_int(int irq, void *dev_id,
+ struct pt_regs *ptregs)
+{
+ blkif_response_t *resp_s;
+ blkif_t *blkif;
+ RING_IDX rp, i;
+ unsigned long flags;
+
+ DPRINTK("PT got BE interrupt.\n");
+
+ /* lock both rings */
+ spin_lock_irqsave(&blkif_io_lock, flags);
+
+ rp = blktap_be_ring.sring->rsp_prod;
+ rmb();
+
+ for ( i = blktap_be_ring.rsp_cons; i != rp; i++)
+ {
+ resp_s = RING_GET_RESPONSE(BLKIF_RING, &blktap_be_ring, i);
+
+ /* BE -> FE interposition point is here. */
+
+ blkif = active_reqs[ID_TO_IDX(resp_s->id)].blkif;
+
+ /* If we are in MODE_INTERCEPT_BE or MODE_COPY_BE: */
+ if ( (blktap_mode & BLKTAP_MODE_INTERCEPT_BE) ||
+ (blktap_mode & BLKTAP_MODE_COPY_BE) ) {
+
+ /* Copy the response message to UBERing */
+ /* In MODE_INTERCEPT_BE, map attached pages into the app vma */
+ /* In MODE_COPY_BE_PAGES, copy attached pages into the app vma */
+
+ DPRINTK("rsp->UBERing\n");
+ blktap_write_be_ring(resp_s);
+ blktap_kick_user();
+
+ }
+
+ /* If we are NOT in MODE_INTERCEPT_BE or MODE_INTERCEPT_FE: */
+ if ( !((blktap_mode & BLKTAP_MODE_INTERCEPT_BE) ||
+ (blktap_mode & BLKTAP_MODE_INTERCEPT_FE)) ) {
+
+ /* (fe included to prevent random interference from the BE) */
+ /* Copy the response message to FERing */
+
+ DPRINTK("blktap: BERing[%u] -> FERing[%u]\n",
+ (unsigned)__SHARED_RING_MASK(BLKIF_RING,
+ blkif->blk_ring.sring, i),
+ (unsigned)__SHARED_RING_MASK(BLKIF_RING,
+ blkif->blk_ring.sring,
+ blkif->blk_ring.rsp_prod_pvt));
+
+ write_resp_to_fe_ring(blkif, resp_s);
+ kick_fe_domain(blkif);
+
+ }
+ }
+
+ blktap_be_ring.rsp_cons = i;
+
+
+ spin_unlock_irqrestore(&blkif_io_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+/* Debug : print the current ring indices. */
+
+void print_vm_ring_idxs(void)
+{
+ int i;
+ blkif_t *blkif;
+
+ WPRINTK("FE Rings: \n---------\n");
+ for ( i = 0; i < 50; i++) {
+ blkif = blkif_find_by_handle((domid_t)i, 0);
+ if (blkif != NULL)
+ WPRINTK("%2d: req_cons: %2d, rsp_prod_prv: %2d "
+ "| req_prod: %2d, rsp_prod: %2d\n", i,
+ blkif->blk_ring.req_cons,
+ blkif->blk_ring.rsp_prod_pvt,
+ blkif->blk_ring.sring->req_prod,
+ blkif->blk_ring.sring->rsp_prod);
+ }
+ WPRINTK("BE Ring: \n--------\n");
+ WPRINTK("BE: rsp_cons: %2d, req_prod_prv: %2d "
+ "| req_prod: %2d, rsp_prod: %2d\n",
+ blktap_be_ring.rsp_cons,
+ blktap_be_ring.req_prod_pvt,
+ blktap_be_ring.sring->req_prod,
+ blktap_be_ring.sring->rsp_prod);
+}
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_userdev.c b/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_userdev.c
new file mode 100644
index 0000000000..500270259c
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/drivers/xen/blktap/blktap_userdev.c
@@ -0,0 +1,406 @@
+/******************************************************************************
+ * blktap_userdev.c
+ *
+ * XenLinux virtual block-device tap.
+ * Control interface between the driver and a character device.
+ *
+ * Copyright (c) 2004, Andrew Warfield
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/errno.h>
+#include <linux/major.h>
+#include <linux/gfp.h>
+#include <linux/poll.h>
+#include <asm/pgalloc.h>
+
+#include "blktap.h"
+
+
+unsigned long blktap_mode = BLKTAP_MODE_PASSTHROUGH;
+
+/* Only one process may open /dev/xen/blktap at any time. */
+static unsigned long blktap_dev_inuse;
+unsigned long blktap_ring_ok; /* make this ring->state */
+
+/* for poll: */
+static wait_queue_head_t blktap_wait;
+
+/* Where things are inside the device mapping. */
+struct vm_area_struct *blktap_vma;
+unsigned long mmap_vstart;
+unsigned long rings_vstart;
+
+/* Rings up to user space. */
+static blkif_front_ring_t blktap_ufe_ring;
+static blkif_back_ring_t blktap_ube_ring;
+
+/* -------[ blktap vm ops ]------------------------------------------- */
+
+static struct page *blktap_nopage(struct vm_area_struct *vma,
+ unsigned long address,
+ int *type)
+{
+ /*
+ * if the page has not been mapped in by the driver then generate
+ * a SIGBUS to the domain.
+ */
+
+ force_sig(SIGBUS, current);
+
+ return 0;
+}
+
+struct vm_operations_struct blktap_vm_ops = {
+ nopage: blktap_nopage,
+};
+
+/* -------[ blktap file ops ]----------------------------------------- */
+
+static int blktap_open(struct inode *inode, struct file *filp)
+{
+ blkif_sring_t *sring;
+
+ if ( test_and_set_bit(0, &blktap_dev_inuse) )
+ return -EBUSY;
+
+ printk(KERN_ALERT "blktap open.\n");
+
+ /* Allocate the fe ring. */
+ sring = (blkif_sring_t *)get_zeroed_page(GFP_KERNEL);
+ if (sring == NULL)
+ goto fail_nomem;
+
+ SetPageReserved(virt_to_page(sring));
+
+ SHARED_RING_INIT(BLKIF_RING, sring);
+ FRONT_RING_INIT(BLKIF_RING, &blktap_ufe_ring, sring);
+
+ /* Allocate the be ring. */
+ sring = (blkif_sring_t *)get_zeroed_page(GFP_KERNEL);
+ if (sring == NULL)
+ goto fail_free_fe;
+
+ SetPageReserved(virt_to_page(sring));
+
+ SHARED_RING_INIT(BLKIF_RING, sring);
+ BACK_RING_INIT(BLKIF_RING, &blktap_ube_ring, sring);
+
+ DPRINTK(KERN_ALERT "blktap open.\n");
+
+ return 0;
+
+ fail_free_fe:
+ free_page( (unsigned long) blktap_ufe_ring.sring);
+
+ fail_nomem:
+ return -ENOMEM;
+}
+
+static int blktap_release(struct inode *inode, struct file *filp)
+{
+ blktap_dev_inuse = 0;
+ blktap_ring_ok = 0;
+
+ printk(KERN_ALERT "blktap closed.\n");
+
+ /* Free the ring page. */
+ ClearPageReserved(virt_to_page(blktap_ufe_ring.sring));
+ free_page((unsigned long) blktap_ufe_ring.sring);
+
+ ClearPageReserved(virt_to_page(blktap_ube_ring.sring));
+ free_page((unsigned long) blktap_ube_ring.sring);
+
+ return 0;
+}
+
+static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ int size;
+
+ printk(KERN_ALERT "blktap mmap (%lx, %lx)\n",
+ vma->vm_start, vma->vm_end);
+
+ vma->vm_ops = &blktap_vm_ops;
+
+ size = vma->vm_end - vma->vm_start;
+ if ( size != ( (MMAP_PAGES + RING_PAGES) << PAGE_SHIFT ) ) {
+ printk(KERN_INFO
+ "blktap: you _must_ map exactly %d pages!\n",
+ MMAP_PAGES + RING_PAGES);
+ return -EAGAIN;
+ }
+
+ size >>= PAGE_SHIFT;
+ printk(KERN_INFO "blktap: 2 rings + %d pages.\n", size-1);
+
+ rings_vstart = vma->vm_start;
+ mmap_vstart = rings_vstart + (RING_PAGES << PAGE_SHIFT);
+
+ /* Map the ring pages to the start of the region and reserve it. */
+
+ /* not sure if I really need to do this... */
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ DPRINTK("Mapping be_ring page %lx.\n", __pa(blktap_ube_ring.sring));
+ if (remap_page_range(vma, vma->vm_start,
+ __pa(blktap_ube_ring.sring),
+ PAGE_SIZE, vma->vm_page_prot)) {
+ WPRINTK("be_ring: remap_page_range failure!\n");
+ }
+
+ DPRINTK("Mapping fe_ring page %lx.\n", __pa(blktap_ufe_ring.sring));
+ if (remap_page_range(vma, vma->vm_start + PAGE_SIZE,
+ __pa(blktap_ufe_ring.sring),
+ PAGE_SIZE, vma->vm_page_prot)) {
+ WPRINTK("fe_ring: remap_page_range failure!\n");
+ }
+
+ blktap_vma = vma;
+ blktap_ring_ok = 1;
+
+ return 0;
+}
+
+static int blktap_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ switch(cmd) {
+ case BLKTAP_IOCTL_KICK_FE: /* There are fe messages to process. */
+ return blktap_read_fe_ring();
+
+ case BLKTAP_IOCTL_KICK_BE: /* There are be messages to process. */
+ return blktap_read_be_ring();
+
+ case BLKTAP_IOCTL_SETMODE:
+ if (BLKTAP_MODE_VALID(arg)) {
+ blktap_mode = arg;
+ /* XXX: may need to flush rings here. */
+ printk(KERN_INFO "blktap: set mode to %lx\n", arg);
+ return 0;
+ }
+ case BLKTAP_IOCTL_PRINT_IDXS:
+ {
+ print_vm_ring_idxs();
+ WPRINTK("User Rings: \n-----------\n");
+ WPRINTK("UF: rsp_cons: %2d, req_prod_prv: %2d "
+ "| req_prod: %2d, rsp_prod: %2d\n",
+ blktap_ufe_ring.rsp_cons,
+ blktap_ufe_ring.req_prod_pvt,
+ blktap_ufe_ring.sring->req_prod,
+ blktap_ufe_ring.sring->rsp_prod);
+ WPRINTK("UB: req_cons: %2d, rsp_prod_prv: %2d "
+ "| req_prod: %2d, rsp_prod: %2d\n",
+ blktap_ube_ring.req_cons,
+ blktap_ube_ring.rsp_prod_pvt,
+ blktap_ube_ring.sring->req_prod,
+ blktap_ube_ring.sring->rsp_prod);
+
+ }
+ }
+ return -ENOIOCTLCMD;
+}
+
+static unsigned int blktap_poll(struct file *file, poll_table *wait)
+{
+ poll_wait(file, &blktap_wait, wait);
+
+ if ( RING_HAS_UNPUSHED_REQUESTS(BLKIF_RING, &blktap_ufe_ring) ||
+ RING_HAS_UNPUSHED_RESPONSES(BLKIF_RING, &blktap_ube_ring) ) {
+
+ RING_PUSH_REQUESTS(BLKIF_RING, &blktap_ufe_ring);
+ RING_PUSH_RESPONSES(BLKIF_RING, &blktap_ube_ring);
+ return POLLIN | POLLRDNORM;
+ }
+
+ return 0;
+}
+
+void blktap_kick_user(void)
+{
+ /* blktap_ring->req_prod = blktap_req_prod; */
+ wake_up_interruptible(&blktap_wait);
+}
+
+static struct file_operations blktap_fops = {
+ owner: THIS_MODULE,
+ poll: blktap_poll,
+ ioctl: blktap_ioctl,
+ open: blktap_open,
+ release: blktap_release,
+ mmap: blktap_mmap,
+};
+
+/*-----[ Data to/from user space ]----------------------------------------*/
+
+
+int blktap_write_fe_ring(blkif_request_t *req)
+{
+ blkif_request_t *target;
+ int error, i;
+
+ /*
+ * This is called to pass a request from the real frontend domain's
+ * blkif ring to the character device.
+ */
+
+ if ( ! blktap_ring_ok ) {
+ DPRINTK("blktap: ufe_ring not ready for a request!\n");
+ return 0;
+ }
+
+ if ( RING_FULL(BLKIF_RING, &blktap_ufe_ring) ) {
+ DPRINTK("blktap: fe_ring is full, can't add.\n");
+ return 0;
+ }
+
+ //target = RING_NEXT_EMPTY_REQUEST(BLKIF_RING, &blktap_ufe_ring);
+ target = RING_GET_REQUEST(BLKIF_RING, &blktap_ufe_ring,
+ blktap_ufe_ring.req_prod_pvt);
+ memcpy(target, req, sizeof(*req));
+
+ /* Attempt to map the foreign pages directly in to the application */
+ for (i=0; i<target->nr_segments; i++) {
+
+ error = direct_remap_area_pages(blktap_vma->vm_mm,
+ MMAP_VADDR(ID_TO_IDX(req->id), i),
+ target->frame_and_sects[0] & PAGE_MASK,
+ PAGE_SIZE,
+ blktap_vma->vm_page_prot,
+ ID_TO_DOM(req->id));
+ if ( error != 0 ) {
+ printk(KERN_INFO "remapping attached page failed! (%d)\n", error);
+ /* the request is now dropped on the floor. */
+ return 0;
+ }
+ }
+
+ blktap_ufe_ring.req_prod_pvt++;
+
+ return 0;
+}
+
+int blktap_write_be_ring(blkif_response_t *rsp)
+{
+ blkif_response_t *target;
+
+ /*
+ * This is called to pass a request from the real backend domain's
+ * blkif ring to the character device.
+ */
+
+ if ( ! blktap_ring_ok ) {
+ DPRINTK("blktap: be_ring not ready for a request!\n");
+ return 0;
+ }
+
+ /* No test for fullness in the response direction. */
+
+ //target = RING_NEXT_EMPTY_RESPONSE(BLKIF_RING, &blktap_ube_ring);
+ target = RING_GET_RESPONSE(BLKIF_RING, &blktap_ube_ring,
+ blktap_ube_ring.rsp_prod_pvt);
+ memcpy(target, rsp, sizeof(*rsp));
+
+ /* no mapping -- pages were mapped in blktap_write_fe_ring() */
+
+ blktap_ube_ring.rsp_prod_pvt++;
+
+ return 0;
+}
+
+int blktap_read_fe_ring(void)
+{
+ /* This is called to read responses from the UFE ring. */
+
+ RING_IDX i, rp;
+ blkif_response_t *resp_s;
+ blkif_t *blkif;
+ active_req_t *ar;
+
+ DPRINTK("blktap_read_fe_ring()\n");
+
+ /* if we are forwarding from UFERring to FERing */
+ if (blktap_mode & BLKTAP_MODE_INTERCEPT_FE) {
+
+ /* for each outstanding message on the UFEring */
+ //RING_FOREACH_RESPONSE(BLKIF_RING, &blktap_ufe_ring, prod, resp_s) {
+ rp = blktap_ufe_ring.sring->rsp_prod;
+ rmb();
+
+ for ( i = blktap_ufe_ring.rsp_cons; i != rp; i++ )
+ {
+ resp_s = RING_GET_RESPONSE(BLKIF_RING, &blktap_ufe_ring, i);
+
+ DPRINTK("resp->fe_ring\n");
+ ar = lookup_active_req(ID_TO_IDX(resp_s->id));
+ blkif = ar->blkif;
+ write_resp_to_fe_ring(blkif, resp_s);
+ kick_fe_domain(blkif);
+ }
+
+ blktap_ufe_ring.rsp_cons = i;
+ }
+ return 0;
+}
+
+int blktap_read_be_ring(void)
+{
+ /* This is called to read requests from the UBE ring. */
+
+ RING_IDX i, rp;
+ blkif_request_t *req_s;
+
+ DPRINTK("blktap_read_be_ring()\n");
+
+ /* if we are forwarding from UFERring to FERing */
+ if (blktap_mode & BLKTAP_MODE_INTERCEPT_BE) {
+
+ /* for each outstanding message on the UFEring */
+ //RING_FOREACH_REQUEST(BLKIF_RING, &blktap_ube_ring, prod, req_s) {
+ rp = blktap_ube_ring.sring->req_prod;
+ rmb();
+ for ( i = blktap_ube_ring.req_cons; i != rp; i++ )
+ {
+ req_s = RING_GET_REQUEST(BLKIF_RING, &blktap_ube_ring, i);
+
+ DPRINTK("req->be_ring\n");
+ write_req_to_be_ring(req_s);
+ kick_be_domain();
+ }
+
+ blktap_ube_ring.req_cons = i;
+ }
+
+ return 0;
+}
+/* -------[ blktap module setup ]------------------------------------- */
+
+static struct miscdevice blktap_miscdev = {
+ .minor = BLKTAP_MINOR,
+ .name = "blktap",
+ .fops = &blktap_fops,
+ .devfs_name = "misc/blktap",
+};
+
+int blktap_init(void)
+{
+ int err;
+
+ err = misc_register(&blktap_miscdev);
+ if ( err != 0 )
+ {
+ printk(KERN_ALERT "Couldn't register /dev/misc/blktap (%d)\n", err);
+ return err;
+ }
+
+ init_waitqueue_head(&blktap_wait);
+
+
+ return 0;
+}
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/console/console.c b/linux-2.6.10-xen-sparse/drivers/xen/console/console.c
index b9c09c3d73..c62085e281 100644
--- a/linux-2.6.10-xen-sparse/drivers/xen/console/console.c
+++ b/linux-2.6.10-xen-sparse/drivers/xen/console/console.c
@@ -238,7 +238,7 @@ void xencons_force_flush(void)
* We use dangerous control-interface functions that require a quiescent
* system and no interrupts. Try to ensure this with a global cli().
*/
- cli();
+ local_irq_disable(); /* XXXsmp */
/* Spin until console data is flushed through to the domain controller. */
while ( (wc != wp) && !ctrl_if_transmitter_empty() )
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/evtchn/evtchn.c b/linux-2.6.10-xen-sparse/drivers/xen/evtchn/evtchn.c
index 97d229001d..f5da4283d1 100644
--- a/linux-2.6.10-xen-sparse/drivers/xen/evtchn/evtchn.c
+++ b/linux-2.6.10-xen-sparse/drivers/xen/evtchn/evtchn.c
@@ -44,6 +44,7 @@
#include <linux/poll.h>
#include <linux/irq.h>
#include <linux/init.h>
+#define XEN_EVTCHN_MASK_OPS
#include <asm-xen/evtchn.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
@@ -60,8 +61,8 @@ static devfs_handle_t xen_dev_dir;
struct per_user_data {
/* Notification ring, accessed via /dev/xen/evtchn. */
-# define RING_SIZE 2048 /* 2048 16-bit entries */
-# define RING_MASK(_i) ((_i)&(RING_SIZE-1))
+# define EVTCHN_RING_SIZE 2048 /* 2048 16-bit entries */
+# define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1))
u16 *ring;
unsigned int ring_cons, ring_prod, ring_overflow;
@@ -85,9 +86,9 @@ void evtchn_device_upcall(int port)
if ( (u = port_user[port]) != NULL )
{
- if ( (u->ring_prod - u->ring_cons) < RING_SIZE )
+ if ( (u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE )
{
- u->ring[RING_MASK(u->ring_prod)] = (u16)port;
+ u->ring[EVTCHN_RING_MASK(u->ring_prod)] = (u16)port;
if ( u->ring_cons == u->ring_prod++ )
{
wake_up_interruptible(&u->evtchn_wait);
@@ -153,10 +154,10 @@ static ssize_t evtchn_read(struct file *file, char *buf,
}
/* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
- if ( ((c ^ p) & RING_SIZE) != 0 )
+ if ( ((c ^ p) & EVTCHN_RING_SIZE) != 0 )
{
- bytes1 = (RING_SIZE - RING_MASK(c)) * sizeof(u16);
- bytes2 = RING_MASK(p) * sizeof(u16);
+ bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) * sizeof(u16);
+ bytes2 = EVTCHN_RING_MASK(p) * sizeof(u16);
}
else
{
@@ -175,7 +176,7 @@ static ssize_t evtchn_read(struct file *file, char *buf,
bytes2 = count - bytes1;
}
- if ( copy_to_user(buf, &u->ring[RING_MASK(c)], bytes1) ||
+ if ( copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) ||
((bytes2 != 0) && copy_to_user(&buf[bytes1], &u->ring[0], bytes2)) )
{
rc = -EFAULT;
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/netback/common.h b/linux-2.6.10-xen-sparse/drivers/xen/netback/common.h
index 0831cbe311..c5146c4860 100644
--- a/linux-2.6.10-xen-sparse/drivers/xen/netback/common.h
+++ b/linux-2.6.10-xen-sparse/drivers/xen/netback/common.h
@@ -35,6 +35,8 @@ typedef struct netif_st {
domid_t domid;
unsigned int handle;
+ u8 fe_dev_addr[6];
+
/* Physical parameters of the comms window. */
unsigned long tx_shmem_frame;
unsigned long rx_shmem_frame;
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/netback/interface.c b/linux-2.6.10-xen-sparse/drivers/xen/netback/interface.c
index 9a3eea5932..682ece07d9 100644
--- a/linux-2.6.10-xen-sparse/drivers/xen/netback/interface.c
+++ b/linux-2.6.10-xen-sparse/drivers/xen/netback/interface.c
@@ -163,13 +163,24 @@ void netif_create(netif_be_create_t *create)
/* Disable queuing. */
dev->tx_queue_len = 0;
- /*
- * Initialise a dummy MAC address. We choose the numerically largest
- * non-broadcast address to prevent the address getting stolen by an
- * Ethernet bridge for STP purposes. (FE:FF:FF:FF:FF:FF)
- */
- memset(dev->dev_addr, 0xFF, ETH_ALEN);
- dev->dev_addr[0] &= ~0x01;
+ if ( (create->be_mac[0] == 0) && (create->be_mac[1] == 0) &&
+ (create->be_mac[2] == 0) && (create->be_mac[3] == 0) &&
+ (create->be_mac[4] == 0) && (create->be_mac[5] == 0) )
+ {
+ /*
+ * Initialise a dummy MAC address. We choose the numerically largest
+ * non-broadcast address to prevent the address getting stolen by an
+ * Ethernet bridge for STP purposes. (FE:FF:FF:FF:FF:FF)
+ */
+ memset(dev->dev_addr, 0xFF, ETH_ALEN);
+ dev->dev_addr[0] &= ~0x01;
+ }
+ else
+ {
+ memcpy(dev->dev_addr, create->be_mac, ETH_ALEN);
+ }
+
+ memcpy(netif->fe_dev_addr, create->mac, ETH_ALEN);
rtnl_lock();
err = register_netdevice(dev);
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6.10-xen-sparse/drivers/xen/netback/netback.c
index 05b043c175..b75b6169a7 100644
--- a/linux-2.6.10-xen-sparse/drivers/xen/netback/netback.c
+++ b/linux-2.6.10-xen-sparse/drivers/xen/netback/netback.c
@@ -12,6 +12,7 @@
#include "common.h"
#include <asm-xen/balloon.h>
+#include <asm-xen/evtchn.h>
static void netif_idx_release(u16 pending_idx);
static void netif_page_release(struct page *page);
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/privcmd/privcmd.c b/linux-2.6.10-xen-sparse/drivers/xen/privcmd/privcmd.c
index 98e7e92ff4..c97fe7cf21 100644
--- a/linux-2.6.10-xen-sparse/drivers/xen/privcmd/privcmd.c
+++ b/linux-2.6.10-xen-sparse/drivers/xen/privcmd/privcmd.c
@@ -174,13 +174,11 @@ static int privcmd_ioctl(struct inode *inode, struct file *file,
case IOCTL_PRIVCMD_GET_MACH2PHYS_START_MFN:
{
- unsigned long m2p_start_mfn =
- HYPERVISOR_shared_info->arch.mfn_to_pfn_start;
-
- if( put_user( m2p_start_mfn, (unsigned long *) data ) )
- ret = -EFAULT;
- else
- ret = 0;
+ unsigned long m2pv = (unsigned long)machine_to_phys_mapping;
+ pgd_t *pgd = pgd_offset_k(m2pv);
+ pmd_t *pmd = pmd_offset(pgd, m2pv);
+ unsigned long m2p_start_mfn = pmd_val(*pmd) >> PAGE_SHIFT;
+ ret = put_user(m2p_start_mfn, (unsigned long *)data) ? -EFAULT: 0;
}
break;
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/usbback/common.h b/linux-2.6.10-xen-sparse/drivers/xen/usbback/common.h
new file mode 100644
index 0000000000..bcab2041bc
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/drivers/xen/usbback/common.h
@@ -0,0 +1,85 @@
+
+#ifndef __USBIF__BACKEND__COMMON_H__
+#define __USBIF__BACKEND__COMMON_H__
+
+#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/rbtree.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/pgalloc.h>
+#include <asm-xen/ctrl_if.h>
+#include <asm-xen/hypervisor.h>
+
+#include <asm-xen/xen-public/io/usbif.h>
+
+#if 0
+#define ASSERT(_p) \
+ if ( !(_p) ) { printk("Assertion '%s' failed, line %d, file %s", #_p , \
+ __LINE__, __FILE__); *(int*)0=0; }
+#define DPRINTK(_f, _a...) printk(KERN_ALERT "(file=%s, line=%d) " _f, \
+ __FILE__ , __LINE__ , ## _a )
+#else
+#define ASSERT(_p) ((void)0)
+#define DPRINTK(_f, _a...) ((void)0)
+#endif
+
+typedef struct usbif_priv_st usbif_priv_t;
+
+struct usbif_priv_st {
+ /* Unique identifier for this interface. */
+ domid_t domid;
+ unsigned int handle;
+ /* Physical parameters of the comms window. */
+ unsigned long shmem_frame;
+ unsigned int evtchn;
+ int irq;
+ /* Comms Information */
+ usbif_back_ring_t usb_ring;
+ /* Private fields. */
+ enum { DISCONNECTED, DISCONNECTING, CONNECTED } status;
+ /*
+ * DISCONNECT response is deferred until pending requests are ack'ed.
+ * We therefore need to store the id from the original request.
+ */
+ u8 disconnect_rspid;
+ usbif_priv_t *hash_next;
+ struct list_head usbif_list;
+ spinlock_t usb_ring_lock;
+ atomic_t refcnt;
+
+ struct work_struct work;
+};
+
+void usbif_create(usbif_be_create_t *create);
+void usbif_destroy(usbif_be_destroy_t *destroy);
+void usbif_connect(usbif_be_connect_t *connect);
+int usbif_disconnect(usbif_be_disconnect_t *disconnect, u8 rsp_id);
+void usbif_disconnect_complete(usbif_priv_t *up);
+
+void usbif_release_port(usbif_be_release_port_t *msg);
+int usbif_claim_port(usbif_be_claim_port_t *msg);
+void usbif_release_ports(usbif_priv_t *up);
+
+usbif_priv_t *usbif_find(domid_t domid);
+#define usbif_get(_b) (atomic_inc(&(_b)->refcnt))
+#define usbif_put(_b) \
+ do { \
+ if ( atomic_dec_and_test(&(_b)->refcnt) ) \
+ usbif_disconnect_complete(_b); \
+ } while (0)
+
+
+void usbif_interface_init(void);
+void usbif_ctrlif_init(void);
+
+void usbif_deschedule(usbif_priv_t *up);
+void remove_from_usbif_list(usbif_priv_t *up);
+
+irqreturn_t usbif_be_int(int irq, void *dev_id, struct pt_regs *regs);
+
+#endif /* __USBIF__BACKEND__COMMON_H__ */
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/usbback/control.c b/linux-2.6.10-xen-sparse/drivers/xen/usbback/control.c
new file mode 100644
index 0000000000..899394a629
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/drivers/xen/usbback/control.c
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/control.c
+ *
+ * Routines for interfacing with the control plane.
+ *
+ * Copyright (c) 2004, Keir Fraser
+ */
+
+#include "common.h"
+
+static void usbif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
+{
+ DPRINTK("Received usbif backend message, subtype=%d\n", msg->subtype);
+
+ switch ( msg->subtype )
+ {
+ case CMSG_USBIF_BE_CREATE:
+ if ( msg->length != sizeof(usbif_be_create_t) )
+ goto parse_error;
+ usbif_create((usbif_be_create_t *)&msg->msg[0]);
+ break;
+ case CMSG_USBIF_BE_DESTROY:
+ if ( msg->length != sizeof(usbif_be_destroy_t) )
+ goto parse_error;
+ usbif_destroy((usbif_be_destroy_t *)&msg->msg[0]);
+ break;
+ case CMSG_USBIF_BE_CONNECT:
+ if ( msg->length != sizeof(usbif_be_connect_t) )
+ goto parse_error;
+ usbif_connect((usbif_be_connect_t *)&msg->msg[0]);
+ break;
+ case CMSG_USBIF_BE_DISCONNECT:
+ if ( msg->length != sizeof(usbif_be_disconnect_t) )
+ goto parse_error;
+ if ( !usbif_disconnect((usbif_be_disconnect_t *)&msg->msg[0],msg->id) )
+ return; /* Sending the response is deferred until later. */
+ break;
+ case CMSG_USBIF_BE_CLAIM_PORT:
+ if ( msg->length != sizeof(usbif_be_claim_port_t) )
+ goto parse_error;
+ usbif_claim_port((usbif_be_claim_port_t *)&msg->msg[0]);
+ break;
+ case CMSG_USBIF_BE_RELEASE_PORT:
+ if ( msg->length != sizeof(usbif_be_release_port_t) )
+ goto parse_error;
+ usbif_release_port((usbif_be_release_port_t *)&msg->msg[0]);
+ break;
+ default:
+ goto parse_error;
+ }
+
+ ctrl_if_send_response(msg);
+ return;
+
+ parse_error:
+ DPRINTK("Parse error while reading message subtype %d, len %d\n",
+ msg->subtype, msg->length);
+ msg->length = 0;
+ ctrl_if_send_response(msg);
+}
+
+void usbif_ctrlif_init(void)
+{
+ ctrl_msg_t cmsg;
+ usbif_be_driver_status_changed_t st;
+
+ (void)ctrl_if_register_receiver(CMSG_USBIF_BE, usbif_ctrlif_rx,
+ CALLBACK_IN_BLOCKING_CONTEXT);
+
+ /* Send a driver-UP notification to the domain controller. */
+ cmsg.type = CMSG_USBIF_BE;
+ cmsg.subtype = CMSG_USBIF_BE_DRIVER_STATUS_CHANGED;
+ cmsg.length = sizeof(usbif_be_driver_status_changed_t);
+ st.status = USBIF_DRIVER_STATUS_UP;
+ memcpy(cmsg.msg, &st, sizeof(st));
+ ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+}
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/usbback/interface.c b/linux-2.6.10-xen-sparse/drivers/xen/usbback/interface.c
new file mode 100644
index 0000000000..ad240aa129
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/drivers/xen/usbback/interface.c
@@ -0,0 +1,252 @@
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/interface.c
+ *
+ * USB device interface management.
+ *
+ * by Mark Williamson, Copyright (c) 2004
+ */
+
+
+/******************************************************************************
+ * arch/xen/drivers/blkif/backend/interface.c
+ *
+ * Block-device interface management.
+ *
+ * Copyright (c) 2004, Keir Fraser
+ */
+
+#include "common.h"
+
+#define USBIF_HASHSZ 1024
+#define USBIF_HASH(_d) (((int)(_d))&(USBIF_HASHSZ-1))
+
+static kmem_cache_t *usbif_priv_cachep;
+static usbif_priv_t *usbif_priv_hash[USBIF_HASHSZ];
+
+usbif_priv_t *usbif_find(domid_t domid)
+{
+ usbif_priv_t *up = usbif_priv_hash[USBIF_HASH(domid)];
+ while ( (up != NULL ) && ( up->domid != domid ) )
+ up = up->hash_next;
+ return up;
+}
+
+static void __usbif_disconnect_complete(void *arg)
+{
+ usbif_priv_t *usbif = (usbif_priv_t *)arg;
+ ctrl_msg_t cmsg;
+ usbif_be_disconnect_t disc;
+
+ /*
+ * These can't be done in usbif_disconnect() because at that point there
+ * may be outstanding requests at the device whose asynchronous responses
+ * must still be notified to the remote driver.
+ */
+ unbind_evtchn_from_irq(usbif->evtchn);
+ vfree(usbif->usb_ring.sring);
+
+ /* Construct the deferred response message. */
+ cmsg.type = CMSG_USBIF_BE;
+ cmsg.subtype = CMSG_USBIF_BE_DISCONNECT;
+ cmsg.id = usbif->disconnect_rspid;
+ cmsg.length = sizeof(usbif_be_disconnect_t);
+ disc.domid = usbif->domid;
+ disc.status = USBIF_BE_STATUS_OKAY;
+ memcpy(cmsg.msg, &disc, sizeof(disc));
+
+ /*
+ * Make sure message is constructed /before/ status change, because
+ * after the status change the 'usbif' structure could be deallocated at
+ * any time. Also make sure we send the response /after/ status change,
+ * as otherwise a subsequent CONNECT request could spuriously fail if
+ * another CPU doesn't see the status change yet.
+ */
+ mb();
+ if ( usbif->status != DISCONNECTING )
+ BUG();
+ usbif->status = DISCONNECTED;
+ mb();
+
+ /* Send the successful response. */
+ ctrl_if_send_response(&cmsg);
+}
+
+void usbif_disconnect_complete(usbif_priv_t *up)
+{
+ INIT_WORK(&up->work, __usbif_disconnect_complete, (void *)up);
+ schedule_work(&up->work);
+}
+
+void usbif_create(usbif_be_create_t *create)
+{
+ domid_t domid = create->domid;
+ usbif_priv_t **pup, *up;
+
+ if ( (up = kmem_cache_alloc(usbif_priv_cachep, GFP_KERNEL)) == NULL )
+ {
+ DPRINTK("Could not create usbif: out of memory\n");
+ create->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
+ return;
+ }
+
+ memset(up, 0, sizeof(*up));
+ up->domid = domid;
+ up->status = DISCONNECTED;
+ spin_lock_init(&up->usb_ring_lock);
+ atomic_set(&up->refcnt, 0);
+
+ pup = &usbif_priv_hash[USBIF_HASH(domid)];
+ while ( *pup != NULL )
+ {
+ if ( (*pup)->domid == domid )
+ {
+ create->status = USBIF_BE_STATUS_INTERFACE_EXISTS;
+ kmem_cache_free(usbif_priv_cachep, up);
+ return;
+ }
+ pup = &(*pup)->hash_next;
+ }
+
+ up->hash_next = *pup;
+ *pup = up;
+
+ create->status = USBIF_BE_STATUS_OKAY;
+}
+
+void usbif_destroy(usbif_be_destroy_t *destroy)
+{
+ domid_t domid = destroy->domid;
+ usbif_priv_t **pup, *up;
+
+ pup = &usbif_priv_hash[USBIF_HASH(domid)];
+ while ( (up = *pup) != NULL )
+ {
+ if ( up->domid == domid )
+ {
+ if ( up->status != DISCONNECTED )
+ goto still_connected;
+ goto destroy;
+ }
+ pup = &up->hash_next;
+ }
+
+ destroy->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return;
+
+ still_connected:
+ destroy->status = USBIF_BE_STATUS_INTERFACE_CONNECTED;
+ return;
+
+ destroy:
+ *pup = up->hash_next;
+ usbif_release_ports(up);
+ kmem_cache_free(usbif_priv_cachep, up);
+ destroy->status = USBIF_BE_STATUS_OKAY;
+}
+
+void usbif_connect(usbif_be_connect_t *connect)
+{
+ domid_t domid = connect->domid;
+ unsigned int evtchn = connect->evtchn;
+ unsigned long shmem_frame = connect->shmem_frame;
+ struct vm_struct *vma;
+ pgprot_t prot;
+ int error;
+ usbif_priv_t *up;
+ usbif_sring_t *sring;
+
+ up = usbif_find(domid);
+ if ( unlikely(up == NULL) )
+ {
+ DPRINTK("usbif_connect attempted for non-existent usbif (%u)\n",
+ connect->domid);
+ connect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return;
+ }
+
+ if ( (vma = get_vm_area(PAGE_SIZE, VM_IOREMAP)) == NULL )
+ {
+ connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
+ return;
+ }
+
+ prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED);
+ error = direct_remap_area_pages(&init_mm, VMALLOC_VMADDR(vma->addr),
+ shmem_frame<<PAGE_SHIFT, PAGE_SIZE,
+ prot, domid);
+ if ( error != 0 )
+ {
+ if ( error == -ENOMEM )
+ connect->status = USBIF_BE_STATUS_OUT_OF_MEMORY;
+ else if ( error == -EFAULT )
+ connect->status = USBIF_BE_STATUS_MAPPING_ERROR;
+ else
+ connect->status = USBIF_BE_STATUS_ERROR;
+ vfree(vma->addr);
+ return;
+ }
+
+ if ( up->status != DISCONNECTED )
+ {
+ connect->status = USBIF_BE_STATUS_INTERFACE_CONNECTED;
+ vfree(vma->addr);
+ return;
+ }
+
+ sring = (usbif_sring_t *)vma->addr;
+ SHARED_RING_INIT(USBIF_RING, sring);
+ BACK_RING_INIT(USBIF_RING, &up->usb_ring, sring);
+
+ up->evtchn = evtchn;
+ up->irq = bind_evtchn_to_irq(evtchn);
+ up->shmem_frame = shmem_frame;
+ up->status = CONNECTED;
+ usbif_get(up);
+
+ request_irq(up->irq, usbif_be_int, 0, "usbif-backend", up);
+
+ connect->status = USBIF_BE_STATUS_OKAY;
+}
+
+/* Remove URBs for this interface before destroying it. */
+void usbif_deschedule(usbif_priv_t *up)
+{
+ remove_from_usbif_list(up);
+}
+
+int usbif_disconnect(usbif_be_disconnect_t *disconnect, u8 rsp_id)
+{
+ domid_t domid = disconnect->domid;
+ usbif_priv_t *up;
+
+ up = usbif_find(domid);
+ if ( unlikely(up == NULL) )
+ {
+ DPRINTK("usbif_disconnect attempted for non-existent usbif"
+ " (%u)\n", disconnect->domid);
+ disconnect->status = USBIF_BE_STATUS_INTERFACE_NOT_FOUND;
+ return 1; /* Caller will send response error message. */
+ }
+
+ if ( up->status == CONNECTED )
+ {
+ up->status = DISCONNECTING;
+ up->disconnect_rspid = rsp_id;
+ wmb(); /* Let other CPUs see the status change. */
+ free_irq(up->irq, up);
+ usbif_deschedule(up);
+ usbif_put(up);
+ return 0; /* Caller should not send response message. */
+ }
+
+ disconnect->status = USBIF_BE_STATUS_OKAY;
+ return 1;
+}
+
+void __init usbif_interface_init(void)
+{
+ usbif_priv_cachep = kmem_cache_create("usbif_priv_cache",
+ sizeof(usbif_priv_t),
+ 0, 0, NULL, NULL);
+ memset(usbif_priv_hash, 0, sizeof(usbif_priv_hash));
+}
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/usbback/usbback.c b/linux-2.6.10-xen-sparse/drivers/xen/usbback/usbback.c
new file mode 100644
index 0000000000..35fcdd84e4
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/drivers/xen/usbback/usbback.c
@@ -0,0 +1,1049 @@
+/******************************************************************************
+ * arch/xen/drivers/usbif/backend/main.c
+ *
+ * Backend for the Xen virtual USB driver - provides an abstraction of a
+ * USB host controller to the corresponding frontend driver.
+ *
+ * by Mark Williamson
+ * Copyright (c) 2004 Intel Research Cambridge
+ * Copyright (c) 2004, 2005 Mark Williamson
+ *
+ * Based on arch/xen/drivers/blkif/backend/main.c
+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
+ */
+
+#include "common.h"
+
+
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/tqueue.h>
+
+/*
+ * This is rather arbitrary.
+ */
+#define MAX_PENDING_REQS 4
+#define BATCH_PER_DOMAIN 1
+
+static unsigned long mmap_vstart;
+
+/* Needs to be sufficiently large that we can map the (large) buffers
+ * the USB mass storage driver wants. */
+#define MMAP_PAGES_PER_REQUEST \
+ (128)
+#define MMAP_PAGES \
+ (MAX_PENDING_REQS * MMAP_PAGES_PER_REQUEST)
+
+#define MMAP_VADDR(_req,_seg) \
+ (mmap_vstart + \
+ ((_req) * MMAP_PAGES_PER_REQUEST * PAGE_SIZE) + \
+ ((_seg) * PAGE_SIZE))
+
+
+static spinlock_t owned_ports_lock;
+LIST_HEAD(owned_ports);
+
+/* A list of these structures is used to track ownership of physical USB
+ * ports. */
+typedef struct
+{
+ usbif_priv_t *usbif_priv;
+ char path[16];
+ int guest_port;
+ int enabled;
+ struct list_head list;
+ unsigned long guest_address; /* The USB device address that has been
+ * assigned by the guest. */
+ int dev_present; /* Is there a device present? */
+ struct usb_device * dev;
+ unsigned long ifaces; /* What interfaces are present on this device? */
+} owned_port_t;
+
+
+/*
+ * Each outstanding request that we've passed to the lower device layers has a
+ * 'pending_req' allocated to it. The request is complete, the specified
+ * domain has a response queued for it, with the saved 'id' passed back.
+ */
+typedef struct {
+ usbif_priv_t *usbif_priv;
+ usbif_iso_t *iso_sched;
+ unsigned long id;
+ int nr_pages;
+ unsigned short operation;
+ int status;
+} pending_req_t;
+
+/*
+ * We can't allocate pending_req's in order, since they may complete out of
+ * order. We therefore maintain an allocation ring. This ring also indicates
+ * when enough work has been passed down -- at that point the allocation ring
+ * will be empty.
+ */
+static pending_req_t pending_reqs[MAX_PENDING_REQS];
+static unsigned char pending_ring[MAX_PENDING_REQS];
+static spinlock_t pend_prod_lock;
+
+/* NB. We use a different index type to differentiate from shared usb rings. */
+typedef unsigned int PEND_RING_IDX;
+#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1))
+static PEND_RING_IDX pending_prod, pending_cons;
+#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
+
+static int do_usb_io_op(usbif_priv_t *usbif, int max_to_do);
+static void make_response(usbif_priv_t *usbif, unsigned long id,
+ unsigned short op, int st, int inband,
+ unsigned long actual_length);
+static void dispatch_usb_probe(usbif_priv_t *up, unsigned long id, unsigned long port);
+static void dispatch_usb_io(usbif_priv_t *up, usbif_request_t *req);
+static void dispatch_usb_reset(usbif_priv_t *up, unsigned long portid);
+static owned_port_t *usbif_find_port(char *);
+
+/******************************************************************
+ * PRIVATE DEBUG FUNCTIONS
+ */
+
+#undef DEBUG
+#ifdef DEBUG
+
+static void dump_port(owned_port_t *p)
+{
+ printk(KERN_DEBUG "owned_port_t @ %p\n"
+ " usbif_priv @ %p\n"
+ " path: %s\n"
+ " guest_port: %d\n"
+ " guest_address: %ld\n"
+ " dev_present: %d\n"
+ " dev @ %p\n"
+ " ifaces: 0x%lx\n",
+ p, p->usbif_priv, p->path, p->guest_port, p->guest_address,
+ p->dev_present, p->dev, p->ifaces);
+}
+
+
+static void dump_request(usbif_request_t *req)
+{
+ printk(KERN_DEBUG "id = 0x%lx\n"
+ "devnum %d\n"
+ "endpoint 0x%x\n"
+ "direction %d\n"
+ "speed %d\n"
+ "pipe_type 0x%x\n"
+ "transfer_buffer 0x%lx\n"
+ "length 0x%lx\n"
+ "transfer_flags 0x%lx\n"
+ "setup = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x }\n"
+ "iso_schedule = 0x%lx\n"
+ "num_iso %ld\n",
+ req->id, req->devnum, req->endpoint, req->direction, req->speed,
+ req->pipe_type, req->transfer_buffer, req->length,
+ req->transfer_flags, req->setup[0], req->setup[1], req->setup[2],
+ req->setup[3], req->setup[4], req->setup[5], req->setup[6],
+ req->setup[7], req->iso_schedule, req->num_iso);
+}
+
+static void dump_urb(struct urb *urb)
+{
+ printk(KERN_DEBUG "dumping urb @ %p\n", urb);
+
+#define DUMP_URB_FIELD(name, format) \
+ printk(KERN_DEBUG " " # name " " format "\n", urb-> name)
+
+ DUMP_URB_FIELD(pipe, "0x%x");
+ DUMP_URB_FIELD(status, "%d");
+ DUMP_URB_FIELD(transfer_flags, "0x%x");
+ DUMP_URB_FIELD(transfer_buffer, "%p");
+ DUMP_URB_FIELD(transfer_buffer_length, "%d");
+ DUMP_URB_FIELD(actual_length, "%d");
+}
+
+static void dump_response(usbif_response_t *resp)
+{
+ printk(KERN_DEBUG "usbback: Sending response:\n"
+ " id = 0x%x\n"
+ " op = %d\n"
+ " status = %d\n"
+ " data = %d\n"
+ " length = %d\n",
+ resp->id, resp->op, resp->status, resp->data, resp->length);
+}
+
+#else /* DEBUG */
+
+#define dump_port(blah) ((void)0)
+#define dump_request(blah) ((void)0)
+#define dump_urb(blah) ((void)0)
+#define dump_response(blah) ((void)0)
+
+#endif /* DEBUG */
+
+/******************************************************************
+ * MEMORY MANAGEMENT
+ */
+
+static void fast_flush_area(int idx, int nr_pages)
+{
+ multicall_entry_t mcl[MMAP_PAGES_PER_REQUEST];
+ int i;
+
+ for ( i = 0; i < nr_pages; i++ )
+ {
+ mcl[i].op = __HYPERVISOR_update_va_mapping;
+ mcl[i].args[0] = MMAP_VADDR(idx, i) >> PAGE_SHIFT;
+ mcl[i].args[1] = 0;
+ mcl[i].args[2] = 0;
+ }
+
+ mcl[nr_pages-1].args[2] = UVMF_FLUSH_TLB;
+ if ( unlikely(HYPERVISOR_multicall(mcl, nr_pages) != 0) )
+ BUG();
+}
+
+
+/******************************************************************
+ * USB INTERFACE SCHEDULER LIST MAINTENANCE
+ */
+
+static struct list_head usbio_schedule_list;
+static spinlock_t usbio_schedule_list_lock;
+
+static int __on_usbif_list(usbif_priv_t *up)
+{
+ return up->usbif_list.next != NULL;
+}
+
+void remove_from_usbif_list(usbif_priv_t *up)
+{
+ unsigned long flags;
+ if ( !__on_usbif_list(up) ) return;
+ spin_lock_irqsave(&usbio_schedule_list_lock, flags);
+ if ( __on_usbif_list(up) )
+ {
+ list_del(&up->usbif_list);
+ up->usbif_list.next = NULL;
+ usbif_put(up);
+ }
+ spin_unlock_irqrestore(&usbio_schedule_list_lock, flags);
+}
+
+static void add_to_usbif_list_tail(usbif_priv_t *up)
+{
+ unsigned long flags;
+ if ( __on_usbif_list(up) ) return;
+ spin_lock_irqsave(&usbio_schedule_list_lock, flags);
+ if ( !__on_usbif_list(up) && (up->status == CONNECTED) )
+ {
+ list_add_tail(&up->usbif_list, &usbio_schedule_list);
+ usbif_get(up);
+ }
+ spin_unlock_irqrestore(&usbio_schedule_list_lock, flags);
+}
+
+void free_pending(int pending_idx)
+{
+ unsigned long flags;
+
+ /* Free the pending request. */
+ spin_lock_irqsave(&pend_prod_lock, flags);
+ pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
+ spin_unlock_irqrestore(&pend_prod_lock, flags);
+}
+
+/******************************************************************
+ * COMPLETION CALLBACK -- Called as urb->complete()
+ */
+
+static void maybe_trigger_usbio_schedule(void);
+
+static void __end_usb_io_op(struct urb *purb)
+{
+ pending_req_t *pending_req;
+ int pending_idx;
+
+ pending_req = purb->context;
+
+ pending_idx = pending_req - pending_reqs;
+
+ ASSERT(purb->actual_length <= purb->transfer_buffer_length);
+ ASSERT(purb->actual_length <= pending_req->nr_pages * PAGE_SIZE);
+
+ /* An error fails the entire request. */
+ if ( purb->status )
+ {
+ printk(KERN_WARNING "URB @ %p failed. Status %d\n", purb, purb->status);
+ }
+
+ if ( usb_pipetype(purb->pipe) == 0 )
+ {
+ int i;
+ usbif_iso_t *sched = (usbif_iso_t *)MMAP_VADDR(pending_idx, pending_req->nr_pages - 1);
+
+ ASSERT(sched == pending_req->sched);
+
+ /* If we're dealing with an iso pipe, we need to copy back the schedule. */
+ for ( i = 0; i < purb->number_of_packets; i++ )
+ {
+ sched[i].length = purb->iso_frame_desc[i].actual_length;
+ ASSERT(sched[i].buffer_offset ==
+ purb->iso_frame_desc[i].offset);
+ sched[i].status = purb->iso_frame_desc[i].status;
+ }
+ }
+
+ fast_flush_area(pending_req - pending_reqs, pending_req->nr_pages);
+
+ kfree(purb->setup_packet);
+
+ make_response(pending_req->usbif_priv, pending_req->id,
+ pending_req->operation, pending_req->status, 0, purb->actual_length);
+ usbif_put(pending_req->usbif_priv);
+
+ usb_free_urb(purb);
+
+ free_pending(pending_idx);
+
+ rmb();
+
+ /* Check for anything still waiting in the rings, having freed a request... */
+ maybe_trigger_usbio_schedule();
+}
+
+/******************************************************************
+ * SCHEDULER FUNCTIONS
+ */
+
+static DECLARE_WAIT_QUEUE_HEAD(usbio_schedule_wait);
+
+static int usbio_schedule(void *arg)
+{
+ DECLARE_WAITQUEUE(wq, current);
+
+ usbif_priv_t *up;
+ struct list_head *ent;
+
+ daemonize();
+
+ for ( ; ; )
+ {
+ /* Wait for work to do. */
+ add_wait_queue(&usbio_schedule_wait, &wq);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if ( (NR_PENDING_REQS == MAX_PENDING_REQS) ||
+ list_empty(&usbio_schedule_list) )
+ schedule();
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&usbio_schedule_wait, &wq);
+
+ /* Queue up a batch of requests. */
+ while ( (NR_PENDING_REQS < MAX_PENDING_REQS) &&
+ !list_empty(&usbio_schedule_list) )
+ {
+ ent = usbio_schedule_list.next;
+ up = list_entry(ent, usbif_priv_t, usbif_list);
+ usbif_get(up);
+ remove_from_usbif_list(up);
+ if ( do_usb_io_op(up, BATCH_PER_DOMAIN) )
+ add_to_usbif_list_tail(up);
+ usbif_put(up);
+ }
+ }
+}
+
+static void maybe_trigger_usbio_schedule(void)
+{
+ /*
+ * Needed so that two processes, who together make the following predicate
+ * true, don't both read stale values and evaluate the predicate
+ * incorrectly. Incredibly unlikely to stall the scheduler on x86, but...
+ */
+ smp_mb();
+
+ if ( !list_empty(&usbio_schedule_list) )
+ wake_up(&usbio_schedule_wait);
+}
+
+
+/******************************************************************************
+ * NOTIFICATION FROM GUEST OS.
+ */
+
+irqreturn_t usbif_be_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+ usbif_priv_t *up = dev_id;
+
+ smp_mb();
+
+ add_to_usbif_list_tail(up);
+
+ /* Will in fact /always/ trigger an io schedule in this case. */
+ maybe_trigger_usbio_schedule();
+
+ return IRQ_HANDLED;
+}
+
+
+
+/******************************************************************
+ * DOWNWARD CALLS -- These interface with the usb-device layer proper.
+ */
+
+static int do_usb_io_op(usbif_priv_t *up, int max_to_do)
+{
+ usbif_back_ring_t *usb_ring = &up->usb_ring;
+ usbif_request_t *req;
+ RING_IDX i, rp;
+ int more_to_do = 0;
+
+ rp = usb_ring->sring->req_prod;
+ rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+ /* Take items off the comms ring, taking care not to overflow. */
+ for ( i = usb_ring->req_cons;
+ (i != rp) && !RING_REQUEST_CONS_OVERFLOW(USBIF_RING, usb_ring, i);
+ i++ )
+ {
+ if ( (max_to_do-- == 0) || (NR_PENDING_REQS == MAX_PENDING_REQS) )
+ {
+ more_to_do = 1;
+ break;
+ }
+
+ req = RING_GET_REQUEST(USBIF_RING, usb_ring, i);
+
+ switch ( req->operation )
+ {
+ case USBIF_OP_PROBE:
+ dispatch_usb_probe(up, req->id, req->port);
+ break;
+
+ case USBIF_OP_IO:
+ /* Assemble an appropriate URB. */
+ dispatch_usb_io(up, req);
+ break;
+
+ case USBIF_OP_RESET:
+ dispatch_usb_reset(up, req->port);
+ break;
+
+ default:
+ DPRINTK("error: unknown USB io operation [%d]\n",
+ req->operation);
+ make_response(up, req->id, req->operation, -EINVAL, 0, 0);
+ break;
+ }
+ }
+
+ usb_ring->req_cons = i;
+
+ return more_to_do;
+}
+
+static owned_port_t *find_guest_port(usbif_priv_t *up, int port)
+{
+ unsigned long flags;
+ struct list_head *l;
+
+ spin_lock_irqsave(&owned_ports_lock, flags);
+ list_for_each(l, &owned_ports)
+ {
+ owned_port_t *p = list_entry(l, owned_port_t, list);
+ if(p->usbif_priv == up && p->guest_port == port)
+ {
+ spin_unlock_irqrestore(&owned_ports_lock, flags);
+ return p;
+ }
+ }
+ spin_unlock_irqrestore(&owned_ports_lock, flags);
+
+ return NULL;
+}
+
+static void dispatch_usb_reset(usbif_priv_t *up, unsigned long portid)
+{
+ owned_port_t *port = find_guest_port(up, portid);
+ int ret = 0;
+
+
+ /* Allowing the guest to actually reset the device causes more problems
+ * than it's worth. We just fake it out in software but we will do a real
+ * reset when the interface is destroyed. */
+
+ dump_port(port);
+
+ port->guest_address = 0;
+ /* If there's an attached device then the port is now enabled. */
+ if ( port->dev_present )
+ port->enabled = 1;
+ else
+ port->enabled = 0;
+
+ make_response(up, 0, USBIF_OP_RESET, ret, 0, 0);
+}
+
+static void dispatch_usb_probe(usbif_priv_t *up, unsigned long id, unsigned long portid)
+{
+ owned_port_t *port = find_guest_port(up, portid);
+ int ret;
+
+ if ( port != NULL )
+ ret = port->dev_present;
+ else
+ {
+ ret = -EINVAL;
+ printk(KERN_INFO "dispatch_usb_probe(): invalid port probe request "
+ "(port %ld)\n", portid);
+ }
+
+ /* Probe result is sent back in-band. Probes don't have an associated id
+ * right now... */
+ make_response(up, id, USBIF_OP_PROBE, ret, portid, 0);
+}
+
+owned_port_t *find_port_for_request(usbif_priv_t *up, usbif_request_t *req);
+
+static void dispatch_usb_io(usbif_priv_t *up, usbif_request_t *req)
+{
+ unsigned long buffer_mach;
+ int i = 0, offset = 0,
+ pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
+ pending_req_t *pending_req;
+ unsigned long remap_prot;
+ multicall_entry_t mcl[MMAP_PAGES_PER_REQUEST];
+ struct urb *purb = NULL;
+ owned_port_t *port;
+ unsigned char *setup;
+
+ dump_request(req);
+
+ if ( NR_PENDING_REQS == MAX_PENDING_REQS )
+ {
+ printk(KERN_WARNING "usbback: Max requests already queued. "
+ "Giving up!\n");
+
+ return;
+ }
+
+ port = find_port_for_request(up, req);
+
+ if ( port == NULL )
+ {
+ printk(KERN_WARNING "No such device! (%d)\n", req->devnum);
+ dump_request(req);
+
+ make_response(up, req->id, req->operation, -ENODEV, 0, 0);
+ return;
+ }
+ else if ( !port->dev_present )
+ {
+ /* In normal operation, we'll only get here if a device is unplugged
+ * and the frontend hasn't noticed yet. */
+ make_response(up, req->id, req->operation, -ENODEV, 0, 0);
+ return;
+ }
+
+
+ setup = kmalloc(8, GFP_KERNEL);
+
+ if ( setup == NULL )
+ goto no_mem;
+
+ /* Copy request out for safety. */
+ memcpy(setup, req->setup, 8);
+
+ if( setup[0] == 0x0 && setup[1] == 0x5)
+ {
+ /* To virtualise the USB address space, we need to intercept
+ * set_address messages and emulate. From the USB specification:
+ * bmRequestType = 0x0;
+ * Brequest = SET_ADDRESS (i.e. 0x5)
+ * wValue = device address
+ * wIndex = 0
+ * wLength = 0
+ * data = None
+ */
+ /* Store into the guest transfer buffer using cpu_to_le16 */
+ port->guest_address = le16_to_cpu(*(u16 *)(setup + 2));
+ /* Make a successful response. That was easy! */
+
+ make_response(up, req->id, req->operation, 0, 0, 0);
+
+ kfree(setup);
+ return;
+ }
+ else if ( setup[0] == 0x0 && setup[1] == 0x9 )
+ {
+ /* The host kernel needs to know what device configuration is in use
+ * because various error checks get confused otherwise. We just do
+ * configuration settings here, under controlled conditions.
+ */
+
+ /* Ignore configuration setting and hope that the host kernel
+ did it right. */
+ /* usb_set_configuration(port->dev, setup[2]); */
+
+ make_response(up, req->id, req->operation, 0, 0, 0);
+
+ kfree(setup);
+ return;
+ }
+
+ else if ( setup[0] == 0x1 && setup[1] == 0xB )
+ {
+ /* The host kernel needs to know what device interface is in use
+ * because various error checks get confused otherwise. We just do
+ * configuration settings here, under controlled conditions.
+ */
+ usb_set_interface(port->dev, (setup[4] | setup[5] << 8),
+ (setup[2] | setup[3] << 8) );
+
+ make_response(up, req->id, req->operation, 0, 0, 0);
+
+ kfree(setup);
+ return;
+ }
+
+ if ( ( req->transfer_buffer - (req->transfer_buffer & PAGE_MASK)
+ + req->length )
+ > MMAP_PAGES_PER_REQUEST * PAGE_SIZE )
+ {
+ printk(KERN_WARNING "usbback: request of %lu bytes too large\n",
+ req->length);
+ make_response(up, req->id, req->operation, -EINVAL, 0, 0);
+ kfree(setup);
+ return;
+ }
+
+ buffer_mach = req->transfer_buffer;
+
+ if( buffer_mach == 0 )
+ goto no_remap;
+
+ ASSERT((req->length >> PAGE_SHIFT) <= MMAP_PAGES_PER_REQUEST);
+ ASSERT(buffer_mach);
+
+ /* Always map writeable for now. */
+ remap_prot = _PAGE_PRESENT|_PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_RW;
+
+ for ( i = 0, offset = 0; offset < req->length;
+ i++, offset += PAGE_SIZE )
+ {
+ mcl[i].op = __HYPERVISOR_update_va_mapping_otherdomain;
+ mcl[i].args[0] = MMAP_VADDR(pending_idx, i) >> PAGE_SHIFT;
+ mcl[i].args[1] = ((buffer_mach & PAGE_MASK) + offset) | remap_prot;
+ mcl[i].args[2] = 0;
+ mcl[i].args[3] = up->domid;
+
+ phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] =
+ FOREIGN_FRAME((buffer_mach + offset) >> PAGE_SHIFT);
+
+ ASSERT(virt_to_machine(MMAP_VADDR(pending_idx, i))
+ == buffer_mach + i << PAGE_SHIFT);
+ }
+
+ if ( req->pipe_type == 0 && req->num_iso > 0 ) /* Maybe schedule ISO... */
+ {
+ /* Map in ISO schedule, if necessary. */
+ mcl[i].op = __HYPERVISOR_update_va_mapping_otherdomain;
+ mcl[i].args[0] = MMAP_VADDR(pending_idx, i) >> PAGE_SHIFT;
+ mcl[i].args[1] = (req->iso_schedule & PAGE_MASK) | remap_prot;
+ mcl[i].args[2] = 0;
+ mcl[i].args[3] = up->domid;
+
+ phys_to_machine_mapping[__pa(MMAP_VADDR(pending_idx, i))>>PAGE_SHIFT] =
+ FOREIGN_FRAME(req->iso_schedule >> PAGE_SHIFT);
+
+ i++;
+ }
+
+ if ( unlikely(HYPERVISOR_multicall(mcl, i) != 0) )
+ BUG();
+
+ {
+ int j;
+ for ( j = 0; j < i; j++ )
+ {
+ if ( unlikely(mcl[j].args[5] != 0) )
+ {
+ printk(KERN_WARNING
+ "invalid buffer %d -- could not remap it\n", j);
+ fast_flush_area(pending_idx, i);
+ goto bad_descriptor;
+ }
+ }
+ }
+
+ no_remap:
+
+ ASSERT(i <= MMAP_PAGES_PER_REQUEST);
+ ASSERT(i * PAGE_SIZE >= req->length);
+
+ /* We have to do this because some things might complete out of order. */
+ pending_req = &pending_reqs[pending_idx];
+ pending_req->usbif_priv= up;
+ pending_req->id = req->id;
+ pending_req->operation = req->operation;
+ pending_req->nr_pages = i;
+
+ pending_cons++;
+
+ usbif_get(up);
+
+ /* Fill out an actual request for the USB layer. */
+ purb = usb_alloc_urb(req->num_iso);
+
+ if ( purb == NULL )
+ {
+ usbif_put(up);
+ free_pending(pending_idx);
+ goto no_mem;
+ }
+
+ purb->dev = port->dev;
+ purb->context = pending_req;
+ purb->transfer_buffer =
+ (void *)MMAP_VADDR(pending_idx, 0) + (buffer_mach & ~PAGE_MASK);
+ if(buffer_mach == 0)
+ purb->transfer_buffer = NULL;
+ purb->complete = __end_usb_io_op;
+ purb->transfer_buffer_length = req->length;
+ purb->transfer_flags = req->transfer_flags;
+
+ purb->pipe = 0;
+ purb->pipe |= req->direction << 7;
+ purb->pipe |= port->dev->devnum << 8;
+ purb->pipe |= req->speed << 26;
+ purb->pipe |= req->pipe_type << 30;
+ purb->pipe |= req->endpoint << 15;
+
+ purb->number_of_packets = req->num_iso;
+
+ /* Make sure there's always some kind of timeout. */
+ purb->timeout = ( req->timeout > 0 ) ? (req->timeout * HZ) / 1000
+ : 1000;
+
+ purb->setup_packet = setup;
+
+ if ( req->pipe_type == 0 ) /* ISO */
+ {
+ int j;
+ usbif_iso_t *iso_sched = (usbif_iso_t *)MMAP_VADDR(pending_idx, i - 1);
+
+ /* If we're dealing with an iso pipe, we need to copy in a schedule. */
+ for ( j = 0; j < req->num_iso; j++ )
+ {
+ purb->iso_frame_desc[j].length = iso_sched[j].length;
+ purb->iso_frame_desc[j].offset = iso_sched[j].buffer_offset;
+ iso_sched[j].status = 0;
+ }
+ pending_req->iso_sched = iso_sched;
+ }
+
+ {
+ int ret;
+ ret = usb_submit_urb(purb);
+
+ dump_urb(purb);
+
+ if ( ret != 0 )
+ {
+ usbif_put(up);
+ free_pending(pending_idx);
+ goto bad_descriptor;
+ }
+ }
+
+ return;
+
+ bad_descriptor:
+ kfree ( setup );
+ if ( purb != NULL )
+ usb_free_urb(purb);
+ make_response(up, req->id, req->operation, -EINVAL, 0, 0);
+ return;
+
+ no_mem:
+ if ( setup != NULL )
+ kfree(setup);
+ make_response(up, req->id, req->operation, -ENOMEM, 0, 0);
+ return;
+}
+
+
+
+/******************************************************************
+ * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING
+ */
+
+
+static void make_response(usbif_priv_t *up, unsigned long id,
+ unsigned short op, int st, int inband,
+ unsigned long length)
+{
+ usbif_response_t *resp;
+ unsigned long flags;
+ usbif_back_ring_t *usb_ring = &up->usb_ring;
+
+ /* Place on the response ring for the relevant domain. */
+ spin_lock_irqsave(&up->usb_ring_lock, flags);
+ resp = RING_GET_RESPONSE(USBIF_RING, usb_ring, usb_ring->rsp_prod_pvt);
+ resp->id = id;
+ resp->operation = op;
+ resp->status = st;
+ resp->data = inband;
+ resp->length = length;
+ wmb(); /* Ensure other side can see the response fields. */
+
+ dump_response(resp);
+
+ usb_ring->rsp_prod_pvt++;
+ RING_PUSH_RESPONSES(USBIF_RING, usb_ring);
+ spin_unlock_irqrestore(&up->usb_ring_lock, flags);
+
+ /* Kick the relevant domain. */
+ notify_via_evtchn(up->evtchn);
+}
+
+/**
+ * usbif_claim_port - claim devices on a port on behalf of guest
+ *
+ * Once completed, this will ensure that any device attached to that
+ * port is claimed by this driver for use by the guest.
+ */
+int usbif_claim_port(usbif_be_claim_port_t *msg)
+{
+ owned_port_t *o_p;
+
+ /* Sanity... */
+ if ( usbif_find_port(msg->path) != NULL )
+ {
+ printk(KERN_WARNING "usbback: Attempted to claim USB port "
+ "we already own!\n");
+ return -EINVAL;
+ }
+
+ /* No need for a slab cache - this should be infrequent. */
+ o_p = kmalloc(sizeof(owned_port_t), GFP_KERNEL);
+
+ if ( o_p == NULL )
+ return -ENOMEM;
+
+ o_p->enabled = 0;
+ o_p->usbif_priv = usbif_find(msg->domid);
+ o_p->guest_port = msg->usbif_port;
+ o_p->dev_present = 0;
+ o_p->guest_address = 0; /* Default address. */
+
+ strcpy(o_p->path, msg->path);
+
+ spin_lock_irq(&owned_ports_lock);
+
+ list_add(&o_p->list, &owned_ports);
+
+ spin_unlock_irq(&owned_ports_lock);
+
+ printk(KERN_INFO "usbback: Claimed USB port (%s) for %d.%d\n", o_p->path,
+ msg->domid, msg->usbif_port);
+
+ /* Force a reprobe for unclaimed devices. */
+ usb_scan_devices();
+
+ return 0;
+}
+
+owned_port_t *find_port_for_request(usbif_priv_t *up, usbif_request_t *req)
+{
+ unsigned long flags;
+ struct list_head *port;
+
+ /* I'm assuming this is not called from IRQ context - correct? I think
+ * it's probably only called in response to control messages or plug events
+ * in the USB hub kernel thread, so should be OK. */
+ spin_lock_irqsave(&owned_ports_lock, flags);
+ list_for_each(port, &owned_ports)
+ {
+ owned_port_t *p = list_entry(port, owned_port_t, list);
+ if(p->usbif_priv == up && p->guest_address == req->devnum && p->enabled )
+ {
+ dump_port(p);
+
+ spin_unlock_irqrestore(&owned_ports_lock, flags);
+ return p;
+ }
+ }
+ spin_unlock_irqrestore(&owned_ports_lock, flags);
+
+ return NULL;
+}
+
+owned_port_t *__usbif_find_port(char *path)
+{
+ struct list_head *port;
+
+ list_for_each(port, &owned_ports)
+ {
+ owned_port_t *p = list_entry(port, owned_port_t, list);
+ if(!strcmp(path, p->path))
+ {
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+owned_port_t *usbif_find_port(char *path)
+{
+ owned_port_t *ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&owned_ports_lock, flags);
+ ret = __usbif_find_port(path);
+ spin_unlock_irqrestore(&owned_ports_lock, flags);
+
+ return ret;
+}
+
+
+static void *probe(struct usb_device *dev, unsigned iface,
+ const struct usb_device_id *id)
+{
+ owned_port_t *p;
+
+ /* We don't care what the device is - if we own the port, we want it. We
+ * don't deal with device-specifics in this driver, so we don't care what
+ * the device actually is ;-) */
+ if ( ( p = usbif_find_port(dev->devpath) ) != NULL )
+ {
+ printk(KERN_INFO "usbback: claimed device attached to owned port\n");
+
+ p->dev_present = 1;
+ p->dev = dev;
+ set_bit(iface, &p->ifaces);
+
+ return p->usbif_priv;
+ }
+ else
+ printk(KERN_INFO "usbback: hotplug for non-owned port (%s), ignoring\n",
+ dev->devpath);
+
+
+ return NULL;
+}
+
+static void disconnect(struct usb_device *dev, void *usbif)
+{
+ /* Note the device is removed so we can tell the guest when it probes. */
+ owned_port_t *port = usbif_find_port(dev->devpath);
+ port->dev_present = 0;
+ port->dev = NULL;
+ port->ifaces = 0;
+}
+
+
+struct usb_driver driver =
+{
+ .owner = THIS_MODULE,
+ .name = "Xen USB Backend",
+ .probe = probe,
+ .disconnect = disconnect,
+ .id_table = NULL,
+};
+
+/* __usbif_release_port - internal mechanics for releasing a port */
+void __usbif_release_port(owned_port_t *p)
+{
+ int i;
+
+ for ( i = 0; p->ifaces != 0; i++)
+ if ( p->ifaces & 1 << i )
+ {
+ usb_driver_release_interface(&driver, usb_ifnum_to_if(p->dev, i));
+ clear_bit(i, &p->ifaces);
+ }
+ list_del(&p->list);
+
+ /* Reset the real device. We don't simulate disconnect / probe for other
+ * drivers in this kernel because we assume the device is completely under
+ * the control of ourselves (i.e. the guest!). This should ensure that the
+ * device is in a sane state for the next customer ;-) */
+
+ /* MAW NB: we're not resetting the real device here. This looks perfectly
+ * valid to me but it causes memory corruption. We seem to get away with not
+ * resetting for now, although it'd be nice to have this tracked down. */
+/* if ( p->dev != NULL) */
+/* usb_reset_device(p->dev); */
+
+ kfree(p);
+}
+
+
+/**
+ * usbif_release_port - stop claiming devices on a port on behalf of guest
+ */
+void usbif_release_port(usbif_be_release_port_t *msg)
+{
+ owned_port_t *p;
+
+ spin_lock_irq(&owned_ports_lock);
+ p = __usbif_find_port(msg->path);
+ __usbif_release_port(p);
+ spin_unlock_irq(&owned_ports_lock);
+}
+
+void usbif_release_ports(usbif_priv_t *up)
+{
+ struct list_head *port, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&owned_ports_lock, flags);
+ list_for_each_safe(port, tmp, &owned_ports)
+ {
+ owned_port_t *p = list_entry(port, owned_port_t, list);
+ if ( p->usbif_priv == up )
+ __usbif_release_port(p);
+ }
+ spin_unlock_irqrestore(&owned_ports_lock, flags);
+}
+
+static int __init usbif_init(void)
+{
+ int i;
+
+ if ( !(xen_start_info.flags & SIF_INITDOMAIN) &&
+ !(xen_start_info.flags & SIF_USB_BE_DOMAIN) )
+ return 0;
+
+ if ( (mmap_vstart = allocate_empty_lowmem_region(MMAP_PAGES)) == 0 )
+ BUG();
+
+ pending_cons = 0;
+ pending_prod = MAX_PENDING_REQS;
+ memset(pending_reqs, 0, sizeof(pending_reqs));
+ for ( i = 0; i < MAX_PENDING_REQS; i++ )
+ pending_ring[i] = i;
+
+ spin_lock_init(&pend_prod_lock);
+
+ spin_lock_init(&owned_ports_lock);
+ INIT_LIST_HEAD(&owned_ports);
+
+ spin_lock_init(&usbio_schedule_list_lock);
+ INIT_LIST_HEAD(&usbio_schedule_list);
+
+ if ( kernel_thread(usbio_schedule, 0, CLONE_FS | CLONE_FILES) < 0 )
+ BUG();
+
+ usbif_interface_init();
+
+ usbif_ctrlif_init();
+
+ usb_register(&driver);
+
+ printk(KERN_INFO "Xen USB Backend Initialised");
+
+ return 0;
+}
+
+__initcall(usbif_init);
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/usbfront/usbfront.c b/linux-2.6.10-xen-sparse/drivers/xen/usbfront/usbfront.c
new file mode 100644
index 0000000000..7f9d372bac
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/drivers/xen/usbfront/usbfront.c
@@ -0,0 +1,1691 @@
+/*
+ * Xen Virtual USB Frontend Driver
+ *
+ * This file contains the first version of the Xen virtual USB hub
+ * that I've managed not to delete by mistake (3rd time lucky!).
+ *
+ * Based on Linux's uhci.c, original copyright notices are displayed
+ * below. Portions also (c) 2004 Intel Research Cambridge
+ * and (c) 2004 Mark Williamson
+ *
+ * Contact <mark.williamson@cl.cam.ac.uk> or
+ * <xen-devel@lists.sourceforge.net> regarding this code.
+ *
+ * Still to be (maybe) implemented:
+ * - multiple port
+ * - multiple interfaces
+ * - migration / backend restart support?
+ * - unloading support
+ *
+ * Differences to a normal host controller:
+ * - the backend does most of the mucky stuff so we don't have to do various
+ * things that are necessary for a normal host controller (e.g. FSBR).
+ * - we don't have any hardware, so status registers are simulated in software.
+ */
+
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
+ * (C) Copyright 1999 Randy Dunlap
+ * (C) Copyright 1999 Georg Acher, acher@in.tum.de
+ * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
+ * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
+ * (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ * - the low-level protocol (fairly simple but lots of small details)
+ * - working around the horridness of the rest
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#ifdef CONFIG_USB_DEBUG
+#define DEBUG
+#else
+#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "xhci.h"
+
+#include <linux/pm.h>
+
+#include "../../../../../drivers/usb/hcd.h"
+
+#include <asm-xen/xen-public/io/usbif.h>
+#include <asm/ctrl_if.h>
+#include <asm/xen-public/io/domain_controller.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.0"
+#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, Mark Williamson"
+#define DRIVER_DESC "Xen Virtual USB Host Controller Interface driver"
+
+/*
+ * debug = 0, no debugging messages
+ * debug = 1, dump failed URB's except for stalls
+ * debug = 2, dump all failed URB's (including stalls)
+ */
+#ifdef DEBUG
+static int debug = 1;
+#else
+static int debug = 0;
+#endif
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debug level");
+static char *errbuf;
+#define ERRBUF_LEN (PAGE_SIZE * 8)
+
+static kmem_cache_t *xhci_up_cachep; /* urb_priv */
+
+static int rh_submit_urb(struct urb *urb);
+static int rh_unlink_urb(struct urb *urb);
+//static int xhci_get_current_frame_number(struct usb_device *dev);
+static int xhci_unlink_urb(struct urb *urb);
+static void xhci_unlink_generic(struct urb *urb);
+static void xhci_call_completion(struct urb *urb);
+static void xhci_drain_ring(void);
+
+#define MAX_URB_LOOP 2048 /* Maximum number of linked URB's */
+
+static struct xhci *xhci;
+
+enum { USBIF_STATE_CONNECTED = 2,
+ USBIF_STATE_DISCONNECTED = 1,
+ USBIF_STATE_CLOSED =0
+};
+
+static int awaiting_reset = 0;
+
+#ifdef DEBUG
+
+static void dump_urb(struct urb *urb)
+{
+ printk(KERN_DEBUG "dumping urb @ %p\n"
+ " hcpriv = %p\n"
+ " next = %p\n"
+ " dev = %p\n"
+ " pipe = 0x%lx\n"
+ " status = %d\n"
+ " transfer_flags = 0x%lx\n"
+ " transfer_buffer = %p\n"
+ " transfer_buffer_length = %d\n"
+ " actual_length = %d\n"
+ " bandwidth = %d\n"
+ " setup_packet = %p\n",
+ urb, urb->hcpriv, urb->next, urb->dev, urb->pipe, urb->status,
+ urb->transfer_flags, urb->transfer_buffer, urb->transfer_buffer_length,
+ urb->actual_length, urb->bandwidth, urb->setup_packet);
+ if ( urb->setup_packet != NULL )
+ printk(KERN_DEBUG
+ "setup = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x }\n",
+ urb->setup_packet[0], urb->setup_packet[1], urb->setup_packet[2], urb->setup_packet[3],
+ urb->setup_packet[4], urb->setup_packet[5], urb->setup_packet[6], urb->setup_packet[7]);
+ printk(KERN_DEBUG "complete = %p\n"
+ "interval = %d\n", urb->complete, urb->interval);
+
+}
+
+static void xhci_show_resp(usbif_response_t *r)
+{
+ printk(KERN_DEBUG "dumping response @ %p\n"
+ " id=0x%lx\n"
+ " op=0x%x\n"
+ " data=0x%x\n"
+ " status=0x%x\n"
+ " length=0x%lx\n",
+ r->id, r->operation, r->data, r->status, r->length);
+}
+
+#define DPRINK(...) printk(KERN_DEBUG __VA_ARGS__)
+
+#else /* DEBUG */
+
+#define dump_urb(blah) ((void)0)
+#define xhci_show_resp(blah) ((void)0)
+#define DPRINTK(blah,...) ((void)0)
+
+#endif /* DEBUG */
+
+/**
+ * xhci_construct_isoc - add isochronous information to a request
+ */
+static int xhci_construct_isoc(usbif_request_t *req, struct urb *urb)
+{
+ usbif_iso_t *schedule;
+ int i;
+ struct urb_priv *urb_priv = urb->hcpriv;
+
+ req->num_iso = urb->number_of_packets;
+ schedule = (usbif_iso_t *)__get_free_page(GFP_KERNEL);
+
+ if ( schedule == NULL )
+ return -ENOMEM;
+
+ for ( i = 0; i < req->num_iso; i++ )
+ {
+ schedule[i].buffer_offset = urb->iso_frame_desc[i].offset;
+ schedule[i].length = urb->iso_frame_desc[i].length;
+ }
+
+ urb_priv->schedule = schedule;
+ req->iso_schedule = virt_to_machine(schedule);
+
+ return 0;
+}
+
+static int xhci_queue_req(struct urb *urb)
+{
+ usbif_request_t *req;
+ usbif_front_ring_t *usb_ring = &xhci->usb_ring;
+
+#if DEBUG
+ printk(KERN_DEBUG
+ "usbif = %p, req_prod = %d (@ 0x%lx), resp_prod = %d, resp_cons = %d\n",
+ usbif, usbif->req_prod, virt_to_machine(&usbif->req_prod),
+ usbif->resp_prod, xhci->usb_resp_cons);
+#endif
+
+
+ if ( RING_FULL(USBIF_RING, usb_ring) )
+ {
+ printk(KERN_WARNING
+ "xhci_queue_req(): USB ring full, not queuing request\n");
+ return -ENOBUFS;
+ }
+
+ /* Stick something in the shared communications ring. */
+ req = RING_GET_REQUEST(USBIF_RING, usb_ring, usb_ring->req_prod_pvt);
+
+ req->operation = USBIF_OP_IO;
+ req->port = 0; /* We don't care what the port is. */
+ req->id = (unsigned long) urb->hcpriv;
+ req->transfer_buffer = virt_to_machine(urb->transfer_buffer);
+ req->devnum = usb_pipedevice(urb->pipe);
+ req->direction = usb_pipein(urb->pipe);
+ req->speed = usb_pipeslow(urb->pipe);
+ req->pipe_type = usb_pipetype(urb->pipe);
+ req->length = urb->transfer_buffer_length;
+ req->transfer_flags = urb->transfer_flags;
+ req->endpoint = usb_pipeendpoint(urb->pipe);
+ req->speed = usb_pipeslow(urb->pipe);
+ req->timeout = urb->timeout * (1000 / HZ);
+
+ if ( usb_pipetype(urb->pipe) == 0 ) /* ISO */
+ {
+ int ret = xhci_construct_isoc(req, urb);
+ if ( ret != 0 )
+ return ret;
+ }
+
+ if(urb->setup_packet != NULL)
+ memcpy(req->setup, urb->setup_packet, 8);
+ else
+ memset(req->setup, 0, 8);
+
+ usb_ring->req_prod_pvt++;
+ RING_PUSH_REQUESTS(USBIF_RING, usb_ring);
+
+ notify_via_evtchn(xhci->evtchn);
+
+ DPRINTK("Queued request for an URB.\n");
+ dump_urb(urb);
+
+ return -EINPROGRESS;
+}
+
+static inline usbif_request_t *xhci_queue_probe(usbif_vdev_t port)
+{
+ usbif_request_t *req;
+ usbif_front_ring_t *usb_ring = &xhci->usb_ring;
+
+#if DEBUG
+ printk(KERN_DEBUG
+ "queuing probe: req_prod = %d (@ 0x%lx), resp_prod = %d, resp_cons = %d\n",
+ usbif->req_prod, virt_to_machine(&usbif->req_prod),
+ usbif->resp_prod, xhci->usb_resp_cons);
+#endif
+
+ if ( RING_FULL(USBIF_RING, usb_ring) )
+ {
+ printk(KERN_WARNING
+ "xhci_queue_probe(): USB ring full, not queuing request\n");
+ return NULL;
+ }
+
+ /* Stick something in the shared communications ring. */
+ req = RING_GET_REQUEST(USBIF_RING, usb_ring, usb_ring->req_prod_pvt);
+
+ req->operation = USBIF_OP_PROBE;
+ req->port = port;
+ req->id = 0;
+ req->transfer_buffer = 0;
+ req->devnum = 0;
+ req->direction = 0;
+ req->speed = 0;
+ req->pipe_type = 0;
+ req->length = 0;
+ req->transfer_flags = 0;
+ req->endpoint = 0;
+ req->speed = 0;
+
+ usb_ring->req_prod_pvt++;
+ RING_PUSH_REQUESTS(USBIF_RING, usb_ring);
+
+ notify_via_evtchn(xhci->evtchn);
+
+ return req;
+}
+
+static int xhci_port_reset(usbif_vdev_t port)
+{
+ usbif_request_t *req;
+ usbif_front_ring_t *usb_ring = &xhci->usb_ring;
+
+ /* We only reset one port at a time, so we only need one variable per
+ * hub. */
+ awaiting_reset = 1;
+
+ /* Stick something in the shared communications ring. */
+ req = RING_GET_REQUEST(USBIF_RING, usb_ring, usb_ring->req_prod_pvt);
+
+ req->operation = USBIF_OP_RESET;
+ req->port = port;
+
+ usb_ring->req_prod_pvt++;
+ RING_PUSH_REQUESTS(USBIF_RING, usb_ring);
+
+ notify_via_evtchn(xhci->evtchn);
+
+ while ( awaiting_reset > 0 )
+ {
+ mdelay(1);
+ xhci_drain_ring();
+ }
+
+ return awaiting_reset;
+}
+
+
+/*
+ * Only the USB core should call xhci_alloc_dev and xhci_free_dev
+ */
+static int xhci_alloc_dev(struct usb_device *dev)
+{
+ return 0;
+}
+
+static int xhci_free_dev(struct usb_device *dev)
+{
+ return 0;
+}
+
+static inline void xhci_add_complete(struct urb *urb)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&xhci->complete_list_lock, flags);
+ list_add_tail(&urbp->complete_list, &xhci->complete_list);
+ spin_unlock_irqrestore(&xhci->complete_list_lock, flags);
+}
+
+/* When this returns, the owner of the URB may free its
+ * storage.
+ *
+ * We spin and wait for the URB to complete before returning.
+ */
+static void xhci_delete_urb(struct urb *urb)
+{
+ struct urb_priv *urbp;
+
+ urbp = urb->hcpriv;
+
+ /* If there's no urb_priv structure for this URB then it can't have
+ * been submitted at all. */
+ if ( urbp == NULL )
+ return;
+
+ /* For now we just spin until the URB completes. It shouldn't take too
+ * long and we don't expect to have to do this very often. */
+ while ( urb->status == -EINPROGRESS )
+ {
+ xhci_drain_ring();
+ mdelay(1);
+ }
+
+ /* Now we know that further transfers to the buffer won't
+ * occur, so we can safely return. */
+}
+
+static struct urb_priv *xhci_alloc_urb_priv(struct urb *urb)
+{
+ struct urb_priv *urbp;
+
+ urbp = kmem_cache_alloc(xhci_up_cachep, SLAB_ATOMIC);
+ if (!urbp) {
+ err("xhci_alloc_urb_priv: couldn't allocate memory for urb_priv\n");
+ return NULL;
+ }
+
+ memset((void *)urbp, 0, sizeof(*urbp));
+
+ urbp->inserttime = jiffies;
+ urbp->urb = urb;
+ urbp->dev = urb->dev;
+
+ INIT_LIST_HEAD(&urbp->complete_list);
+
+ urb->hcpriv = urbp;
+
+ return urbp;
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+/* When is this called? Do we need to stop the transfer (as we
+ * currently do)? */
+static void xhci_destroy_urb_priv(struct urb *urb)
+{
+ struct urb_priv *urbp;
+
+ urbp = (struct urb_priv *)urb->hcpriv;
+ if (!urbp)
+ return;
+
+ if (!list_empty(&urb->urb_list))
+ warn("xhci_destroy_urb_priv: urb %p still on xhci->urb_list or xhci->remove_list", urb);
+
+ if (!list_empty(&urbp->complete_list))
+ warn("xhci_destroy_urb_priv: urb %p still on xhci->complete_list", urb);
+
+ kmem_cache_free(xhci_up_cachep, urb->hcpriv);
+
+ urb->hcpriv = NULL;
+}
+
+/**
+ * Try to find URBs in progress on the same pipe to the same device.
+ *
+ * MUST be called with xhci->urb_list_lock acquired
+ */
+static struct urb *xhci_find_urb_ep(struct xhci *xhci, struct urb *urb)
+{
+ struct list_head *tmp, *head;
+
+ /* We don't match Isoc transfers since they are special */
+ if (usb_pipeisoc(urb->pipe))
+ return NULL;
+
+ head = &xhci->urb_list;
+ tmp = head->next;
+ while (tmp != head) {
+ struct urb *u = list_entry(tmp, struct urb, urb_list);
+
+ tmp = tmp->next;
+
+ if (u->dev == urb->dev && u->pipe == urb->pipe &&
+ u->status == -EINPROGRESS)
+ return u;
+ }
+
+ return NULL;
+}
+
+static int xhci_submit_urb(struct urb *urb)
+{
+ int ret = -EINVAL;
+ unsigned long flags;
+ struct urb *eurb;
+ int bustime;
+
+ DPRINTK("URB submitted to XHCI driver.\n");
+ dump_urb(urb);
+
+ if (!urb)
+ return -EINVAL;
+
+ if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv) {
+ warn("xhci_submit_urb: urb %p belongs to disconnected device or bus?", urb);
+ return -ENODEV;
+ }
+
+ if ( urb->dev->devpath == NULL )
+ BUG();
+
+ usb_inc_dev_use(urb->dev);
+
+ spin_lock_irqsave(&xhci->urb_list_lock, flags);
+ spin_lock(&urb->lock);
+
+ if (urb->status == -EINPROGRESS || urb->status == -ECONNRESET ||
+ urb->status == -ECONNABORTED) {
+ dbg("xhci_submit_urb: urb not available to submit (status = %d)", urb->status);
+ /* Since we can have problems on the out path */
+ spin_unlock(&urb->lock);
+ spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+ usb_dec_dev_use(urb->dev);
+
+ return ret;
+ }
+
+ INIT_LIST_HEAD(&urb->urb_list);
+ if (!xhci_alloc_urb_priv(urb)) {
+ ret = -ENOMEM;
+
+ goto out;
+ }
+
+ ( (struct urb_priv *)urb->hcpriv )->in_progress = 1;
+
+ eurb = xhci_find_urb_ep(xhci, urb);
+ if (eurb && !(urb->transfer_flags & USB_QUEUE_BULK)) {
+ ret = -ENXIO;
+
+ goto out;
+ }
+
+ /* Short circuit the virtual root hub */
+ if (urb->dev == xhci->rh.dev) {
+ ret = rh_submit_urb(urb);
+
+ goto out;
+ }
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ ret = xhci_queue_req(urb);
+ break;
+ case PIPE_INTERRUPT:
+ if (urb->bandwidth == 0) { /* not yet checked/allocated */
+ bustime = usb_check_bandwidth(urb->dev, urb);
+ if (bustime < 0)
+ ret = bustime;
+ else {
+ ret = xhci_queue_req(urb);
+ if (ret == -EINPROGRESS)
+ usb_claim_bandwidth(urb->dev, urb, bustime, 0);
+ }
+ } else /* bandwidth is already set */
+ ret = xhci_queue_req(urb);
+ break;
+ case PIPE_BULK:
+ ret = xhci_queue_req(urb);
+ break;
+ case PIPE_ISOCHRONOUS:
+ if (urb->bandwidth == 0) { /* not yet checked/allocated */
+ if (urb->number_of_packets <= 0) {
+ ret = -EINVAL;
+ break;
+ }
+ bustime = usb_check_bandwidth(urb->dev, urb);
+ if (bustime < 0) {
+ ret = bustime;
+ break;
+ }
+
+ ret = xhci_queue_req(urb);
+ if (ret == -EINPROGRESS)
+ usb_claim_bandwidth(urb->dev, urb, bustime, 1);
+ } else /* bandwidth is already set */
+ ret = xhci_queue_req(urb);
+ break;
+ }
+
+out:
+ urb->status = ret;
+
+ if (ret == -EINPROGRESS) {
+ /* We use _tail to make find_urb_ep more efficient */
+ list_add_tail(&urb->urb_list, &xhci->urb_list);
+
+ spin_unlock(&urb->lock);
+ spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+
+ return 0;
+ }
+
+ xhci_unlink_generic(urb);
+
+ spin_unlock(&urb->lock);
+ spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+
+ /* Only call completion if it was successful */
+ if (!ret)
+ xhci_call_completion(urb);
+
+ return ret;
+}
+
+/*
+ * Return the result of a transfer
+ *
+ * MUST be called with urb_list_lock acquired
+ */
+static void xhci_transfer_result(struct xhci *xhci, struct urb *urb)
+{
+ int ret = 0;
+ unsigned long flags;
+ struct urb_priv *urbp;
+
+ /* The root hub is special */
+ if (urb->dev == xhci->rh.dev)
+ return;
+
+ spin_lock_irqsave(&urb->lock, flags);
+
+ urbp = (struct urb_priv *)urb->hcpriv;
+
+ if ( ( (struct urb_priv *)urb->hcpriv )->in_progress )
+ ret = -EINPROGRESS;
+
+ if (urb->actual_length < urb->transfer_buffer_length) {
+ if (urb->transfer_flags & USB_DISABLE_SPD) {
+ ret = -EREMOTEIO;
+ }
+ }
+
+ if (urb->status == -EPIPE)
+ {
+ ret = urb->status;
+ /* endpoint has stalled - mark it halted */
+ usb_endpoint_halt(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe));
+ }
+
+ if ((debug == 1 && ret != 0 && ret != -EPIPE) ||
+ (ret != 0 && debug > 1)) {
+ /* Some debugging code */
+ dbg("xhci_result_interrupt/bulk() failed with status %x",
+ status);
+ }
+
+ if (ret == -EINPROGRESS)
+ goto out;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ case PIPE_ISOCHRONOUS:
+ /* Release bandwidth for Interrupt or Isoc. transfers */
+ /* Spinlock needed ? */
+ if (urb->bandwidth)
+ usb_release_bandwidth(urb->dev, urb, 1);
+ xhci_unlink_generic(urb);
+ break;
+ case PIPE_INTERRUPT:
+ /* Interrupts are an exception */
+ if (urb->interval)
+ goto out_complete;
+
+ /* Release bandwidth for Interrupt or Isoc. transfers */
+ /* Spinlock needed ? */
+ if (urb->bandwidth)
+ usb_release_bandwidth(urb->dev, urb, 0);
+ xhci_unlink_generic(urb);
+ break;
+ default:
+ info("xhci_transfer_result: unknown pipe type %d for urb %p\n",
+ usb_pipetype(urb->pipe), urb);
+ }
+
+ /* Remove it from xhci->urb_list */
+ list_del_init(&urb->urb_list);
+
+out_complete:
+ xhci_add_complete(urb);
+
+out:
+ spin_unlock_irqrestore(&urb->lock, flags);
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+static void xhci_unlink_generic(struct urb *urb)
+{
+ struct urb_priv *urbp = urb->hcpriv;
+
+ /* We can get called when urbp allocation fails, so check */
+ if (!urbp)
+ return;
+
+ /* ??? This function is now so minimal it doesn't do much. Do we really
+ * need it? */
+
+ xhci_delete_urb(urb);
+}
+
+static int xhci_unlink_urb(struct urb *urb)
+{
+ unsigned long flags;
+ struct urb_priv *urbp = urb->hcpriv;
+
+ if (!urb)
+ return -EINVAL;
+
+ if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
+ return -ENODEV;
+
+ spin_lock_irqsave(&xhci->urb_list_lock, flags);
+ spin_lock(&urb->lock);
+
+ /* Release bandwidth for Interrupt or Isoc. transfers */
+ /* Spinlock needed ? */
+ if (urb->bandwidth) {
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_INTERRUPT:
+ usb_release_bandwidth(urb->dev, urb, 0);
+ break;
+ case PIPE_ISOCHRONOUS:
+ usb_release_bandwidth(urb->dev, urb, 1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (urb->status != -EINPROGRESS) {
+ spin_unlock(&urb->lock);
+ spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+ return 0;
+ }
+
+ list_del_init(&urb->urb_list);
+
+ xhci_unlink_generic(urb);
+
+ /* Short circuit the virtual root hub */
+ if (urb->dev == xhci->rh.dev) {
+ rh_unlink_urb(urb);
+
+ spin_unlock(&urb->lock);
+ spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+
+ xhci_call_completion(urb);
+ } else {
+ if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+ urbp->status = urb->status = -ECONNABORTED;
+
+ spin_lock(&xhci->urb_remove_list_lock);
+
+ list_add(&urb->urb_list, &xhci->urb_remove_list);
+
+ spin_unlock(&xhci->urb_remove_list_lock);
+
+ spin_unlock(&urb->lock);
+ spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+
+ } else {
+ urb->status = -ENOENT;
+
+ spin_unlock(&urb->lock);
+ spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+
+ if (in_interrupt()) { /* wait at least 1 frame */
+ static int errorcount = 10;
+
+ if (errorcount--)
+ dbg("xhci_unlink_urb called from interrupt for urb %p", urb);
+ udelay(1000);
+ } else
+ schedule_timeout(1+1*HZ/1000);
+
+ xhci_call_completion(urb);
+ }
+ }
+
+ return 0;
+}
+
+
+static struct usb_operations xhci_device_operations = {
+ .allocate = xhci_alloc_dev,
+ .deallocate = xhci_free_dev,
+ /* It doesn't look like any drivers actually care what the frame number
+ * is at the moment! If necessary, we could approximate the current
+ * frame nubmer by passing it from the backend in response messages. */
+ .get_frame_number = NULL,
+ .submit_urb = xhci_submit_urb,
+ .unlink_urb = xhci_unlink_urb
+};
+
+/* Virtual Root Hub */
+
+static __u8 root_hub_dev_des[] =
+{
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x00, /* __u16 bcdUSB; v1.0 */
+ 0x01,
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+ 0x00, /* __u16 idVendor; */
+ 0x00,
+ 0x00, /* __u16 idProduct; */
+ 0x00,
+ 0x00, /* __u16 bcdDevice; */
+ 0x00,
+ 0x00, /* __u8 iManufacturer; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, /* __u16 wTotalLength; */
+ 0x00,
+ 0x01, /* __u8 bNumInterfaces; */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes;
+ Bit 7: Bus-powered, 6: Self-powered,
+ Bit 5 Remote-wakeup, 4..0: resvd */
+ 0x00, /* __u8 MaxPower; */
+
+ /* interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */
+ 0x00,
+ 0xff /* __u8 ep_bInterval; 255 ms */
+};
+
+static __u8 root_hub_hub_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x29, /* __u8 bDescriptorType; Hub-descriptor */
+ 0x02, /* __u8 bNbrPorts; */
+ 0x00, /* __u16 wHubCharacteristics; */
+ 0x00,
+ 0x01, /* __u8 bPwrOn2pwrGood; 2ms */
+ 0x00, /* __u8 bHubContrCurrent; 0 mA */
+ 0x00, /* __u8 DeviceRemovable; *** 7 Ports max *** */
+ 0xff /* __u8 PortPwrCtrlMask; *** 7 ports max *** */
+};
+
+/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
+static int rh_send_irq(struct urb *urb)
+{
+ struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+ xhci_port_t *ports = xhci->rh.ports;
+ unsigned long flags;
+ int i, len = 1;
+ __u16 data = 0;
+
+ spin_lock_irqsave(&urb->lock, flags);
+ for (i = 0; i < xhci->rh.numports; i++) {
+ /* MAW: No idea what the old code was doing here or why it worked.
+ * This implementation sets a bit if anything at all has changed on the
+ * port, as per USB spec 11.12 */
+ data |= (ports[i].cs_chg || ports[i].pe_chg )
+ ? (1 << (i + 1))
+ : 0;
+
+ len = (i + 1) / 8 + 1;
+ }
+
+ *(__u16 *) urb->transfer_buffer = cpu_to_le16(data);
+ urb->actual_length = len;
+ urbp->status = 0;
+
+ spin_unlock_irqrestore(&urb->lock, flags);
+
+ if ((data > 0) && (xhci->rh.send != 0)) {
+ dbg("root-hub INT complete: data: %x", data);
+ xhci_call_completion(urb);
+ }
+
+ return 0;
+}
+
+/* Virtual Root Hub INTs are polled by this timer every "interval" ms */
+static int rh_init_int_timer(struct urb *urb);
+
+static void rh_int_timer_do(unsigned long ptr)
+{
+ struct urb *urb = (struct urb *)ptr;
+ struct list_head list, *tmp, *head;
+ unsigned long flags;
+ int i;
+
+ for ( i = 0; i < xhci->rh.numports; i++)
+ xhci_queue_probe(i);
+
+ if (xhci->rh.send)
+ rh_send_irq(urb);
+
+ INIT_LIST_HEAD(&list);
+
+ spin_lock_irqsave(&xhci->urb_list_lock, flags);
+ head = &xhci->urb_list;
+ tmp = head->next;
+ while (tmp != head) {
+ struct urb *u = list_entry(tmp, struct urb, urb_list);
+ struct urb_priv *up = (struct urb_priv *)u->hcpriv;
+
+ tmp = tmp->next;
+
+ spin_lock(&u->lock);
+
+ /* Check if the URB timed out */
+ if (u->timeout && time_after_eq(jiffies, up->inserttime + u->timeout)) {
+ list_del(&u->urb_list);
+ list_add_tail(&u->urb_list, &list);
+ }
+
+ spin_unlock(&u->lock);
+ }
+ spin_unlock_irqrestore(&xhci->urb_list_lock, flags);
+
+ head = &list;
+ tmp = head->next;
+ while (tmp != head) {
+ struct urb *u = list_entry(tmp, struct urb, urb_list);
+
+ tmp = tmp->next;
+
+ u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
+ xhci_unlink_urb(u);
+ }
+
+ rh_init_int_timer(urb);
+}
+
+/* Root Hub INTs are polled by this timer */
+static int rh_init_int_timer(struct urb *urb)
+{
+ xhci->rh.interval = urb->interval;
+ init_timer(&xhci->rh.rh_int_timer);
+ xhci->rh.rh_int_timer.function = rh_int_timer_do;
+ xhci->rh.rh_int_timer.data = (unsigned long)urb;
+ xhci->rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30 ? 30 : urb->interval)) / 1000;
+ add_timer(&xhci->rh.rh_int_timer);
+
+ return 0;
+}
+
+#define OK(x) len = (x); break
+
+/* Root Hub Control Pipe */
+static int rh_submit_urb(struct urb *urb)
+{
+ unsigned int pipe = urb->pipe;
+ struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *)urb->setup_packet;
+ void *data = urb->transfer_buffer;
+ int leni = urb->transfer_buffer_length;
+ int len = 0;
+ xhci_port_t *status;
+ int stat = 0;
+ int i;
+ int retstatus;
+ unsigned long flags;
+
+ __u16 cstatus;
+ __u16 bmRType_bReq;
+ __u16 wValue;
+ __u16 wIndex;
+ __u16 wLength;
+
+ if (usb_pipetype(pipe) == PIPE_INTERRUPT) {
+ xhci->rh.urb = urb;
+ xhci->rh.send = 1;
+ xhci->rh.interval = urb->interval;
+ rh_init_int_timer(urb);
+
+ return -EINPROGRESS;
+ }
+
+ bmRType_bReq = cmd->bRequestType | cmd->bRequest << 8;
+ wValue = le16_to_cpu(cmd->wValue);
+ wIndex = le16_to_cpu(cmd->wIndex);
+ wLength = le16_to_cpu(cmd->wLength);
+
+ for (i = 0; i < 8; i++)
+ xhci->rh.c_p_r[i] = 0;
+
+ status = &xhci->rh.ports[wIndex - 1];
+
+ spin_lock_irqsave(&xhci->rh.port_state_lock, flags);
+
+ switch (bmRType_bReq) {
+ /* Request Destination:
+ without flags: Device,
+ RH_INTERFACE: interface,
+ RH_ENDPOINT: endpoint,
+ RH_CLASS means HUB here,
+ RH_OTHER | RH_CLASS almost ever means HUB_PORT here
+ */
+
+ case RH_GET_STATUS:
+ *(__u16 *)data = cpu_to_le16(1);
+ OK(2);
+ case RH_GET_STATUS | RH_INTERFACE:
+ *(__u16 *)data = cpu_to_le16(0);
+ OK(2);
+ case RH_GET_STATUS | RH_ENDPOINT:
+ *(__u16 *)data = cpu_to_le16(0);
+ OK(2);
+ case RH_GET_STATUS | RH_CLASS:
+ *(__u32 *)data = cpu_to_le32(0);
+ OK(4); /* hub power */
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+ cstatus = (status->cs_chg) |
+ (status->pe_chg << 1) |
+ (xhci->rh.c_p_r[wIndex - 1] << 4);
+ retstatus = (status->ccs) |
+ (status->pe << 1) |
+ (status->susp << 2) |
+ (status->pr << 8) |
+ (1 << 8) | /* power on */
+ (status->lsda << 9);
+ *(__u16 *)data = cpu_to_le16(retstatus);
+ *(__u16 *)(data + 2) = cpu_to_le16(cstatus);
+ OK(4);
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ switch (wValue) {
+ case RH_ENDPOINT_STALL:
+ OK(0);
+ }
+ break;
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ switch (wValue) {
+ case RH_C_HUB_OVER_CURRENT:
+ OK(0); /* hub power over current */
+ }
+ break;
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case RH_PORT_ENABLE:
+ status->pe = 0;
+ OK(0);
+ case RH_PORT_SUSPEND:
+ status->susp = 0;
+ OK(0);
+ case RH_PORT_POWER:
+ OK(0); /* port power */
+ case RH_C_PORT_CONNECTION:
+ status->cs_chg = 0;
+ OK(0);
+ case RH_C_PORT_ENABLE:
+ status->pe_chg = 0;
+ OK(0);
+ case RH_C_PORT_SUSPEND:
+ /*** WR_RH_PORTSTAT(RH_PS_PSSC); */
+ OK(0);
+ case RH_C_PORT_OVER_CURRENT:
+ OK(0); /* port power over current */
+ case RH_C_PORT_RESET:
+ xhci->rh.c_p_r[wIndex - 1] = 0;
+ OK(0);
+ }
+ break;
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case RH_PORT_SUSPEND:
+ status->susp = 1;
+ OK(0);
+ case RH_PORT_RESET:
+ {
+ int ret;
+ xhci->rh.c_p_r[wIndex - 1] = 1;
+ status->pr = 0;
+ status->pe = 1;
+ ret = xhci_port_reset(wIndex - 1);
+ /* XXX MAW: should probably cancel queued transfers during reset... *\/ */
+ if ( ret == 0 ) { OK(0); }
+ else { return ret; }
+ }
+ break;
+ case RH_PORT_POWER:
+ OK(0); /* port power ** */
+ case RH_PORT_ENABLE:
+ status->pe = 1;
+ OK(0);
+ }
+ break;
+ case RH_SET_ADDRESS:
+ xhci->rh.devnum = wValue;
+ OK(0);
+ case RH_GET_DESCRIPTOR:
+ switch ((wValue & 0xff00) >> 8) {
+ case 0x01: /* device descriptor */
+ len = min_t(unsigned int, leni,
+ min_t(unsigned int,
+ sizeof(root_hub_dev_des), wLength));
+ memcpy(data, root_hub_dev_des, len);
+ OK(len);
+ case 0x02: /* configuration descriptor */
+ len = min_t(unsigned int, leni,
+ min_t(unsigned int,
+ sizeof(root_hub_config_des), wLength));
+ memcpy (data, root_hub_config_des, len);
+ OK(len);
+ case 0x03: /* string descriptors */
+ len = usb_root_hub_string (wValue & 0xff,
+ 0, "XHCI-alt",
+ data, wLength);
+ if (len > 0) {
+ OK(min_t(int, leni, len));
+ } else
+ stat = -EPIPE;
+ }
+ break;
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ root_hub_hub_des[2] = xhci->rh.numports;
+ len = min_t(unsigned int, leni,
+ min_t(unsigned int, sizeof(root_hub_hub_des), wLength));
+ memcpy(data, root_hub_hub_des, len);
+ OK(len);
+ case RH_GET_CONFIGURATION:
+ *(__u8 *)data = 0x01;
+ OK(1);
+ case RH_SET_CONFIGURATION:
+ OK(0);
+ case RH_GET_INTERFACE | RH_INTERFACE:
+ *(__u8 *)data = 0x00;
+ OK(1);
+ case RH_SET_INTERFACE | RH_INTERFACE:
+ OK(0);
+ default:
+ stat = -EPIPE;
+ }
+
+ spin_unlock_irqrestore(&xhci->rh.port_state_lock, flags);
+
+ urb->actual_length = len;
+
+ return stat;
+}
+
+/*
+ * MUST be called with urb->lock acquired
+ */
+static int rh_unlink_urb(struct urb *urb)
+{
+ if (xhci->rh.urb == urb) {
+ urb->status = -ENOENT;
+ xhci->rh.send = 0;
+ xhci->rh.urb = NULL;
+ del_timer(&xhci->rh.rh_int_timer);
+ }
+ return 0;
+}
+
+static void xhci_call_completion(struct urb *urb)
+{
+ struct urb_priv *urbp;
+ struct usb_device *dev = urb->dev;
+ int is_ring = 0, killed, resubmit_interrupt, status;
+ struct urb *nurb;
+ unsigned long flags;
+
+ spin_lock_irqsave(&urb->lock, flags);
+
+ urbp = (struct urb_priv *)urb->hcpriv;
+ if (!urbp || !urb->dev) {
+ spin_unlock_irqrestore(&urb->lock, flags);
+ return;
+ }
+
+ killed = (urb->status == -ENOENT || urb->status == -ECONNABORTED ||
+ urb->status == -ECONNRESET);
+ resubmit_interrupt = (usb_pipetype(urb->pipe) == PIPE_INTERRUPT &&
+ urb->interval);
+
+ nurb = urb->next;
+ if (nurb && !killed) {
+ int count = 0;
+
+ while (nurb && nurb != urb && count < MAX_URB_LOOP) {
+ if (nurb->status == -ENOENT ||
+ nurb->status == -ECONNABORTED ||
+ nurb->status == -ECONNRESET) {
+ killed = 1;
+ break;
+ }
+
+ nurb = nurb->next;
+ count++;
+ }
+
+ if (count == MAX_URB_LOOP)
+ err("xhci_call_completion: too many linked URB's, loop? (first loop)");
+
+ /* Check to see if chain is a ring */
+ is_ring = (nurb == urb);
+ }
+
+ status = urbp->status;
+ if (!resubmit_interrupt || killed)
+ /* We don't need urb_priv anymore */
+ xhci_destroy_urb_priv(urb);
+
+ if (!killed)
+ urb->status = status;
+
+ spin_unlock_irqrestore(&urb->lock, flags);
+
+ if (urb->complete)
+ urb->complete(urb);
+
+ if (resubmit_interrupt)
+ /* Recheck the status. The completion handler may have */
+ /* unlinked the resubmitting interrupt URB */
+ killed = (urb->status == -ENOENT ||
+ urb->status == -ECONNABORTED ||
+ urb->status == -ECONNRESET);
+
+ if (resubmit_interrupt && !killed) {
+ if ( urb->dev != xhci->rh.dev )
+ xhci_queue_req(urb); /* XXX What if this fails? */
+ /* Don't need to resubmit URBs for the virtual root dev. */
+ } else {
+ if (is_ring && !killed) {
+ urb->dev = dev;
+ xhci_submit_urb(urb);
+ } else {
+ /* We decrement the usage count after we're done */
+ /* with everything */
+ usb_dec_dev_use(dev);
+ }
+ }
+}
+
+static void xhci_finish_completion(void)
+{
+ struct list_head *tmp, *head;
+ unsigned long flags;
+
+ spin_lock_irqsave(&xhci->complete_list_lock, flags);
+ head = &xhci->complete_list;
+ tmp = head->next;
+ while (tmp != head) {
+ struct urb_priv *urbp = list_entry(tmp, struct urb_priv, complete_list);
+ struct urb *urb = urbp->urb;
+
+ list_del_init(&urbp->complete_list);
+ spin_unlock_irqrestore(&xhci->complete_list_lock, flags);
+
+ xhci_call_completion(urb);
+
+ spin_lock_irqsave(&xhci->complete_list_lock, flags);
+ head = &xhci->complete_list;
+ tmp = head->next;
+ }
+ spin_unlock_irqrestore(&xhci->complete_list_lock, flags);
+}
+
+static void receive_usb_reset(usbif_response_t *resp)
+{
+ awaiting_reset = resp->status;
+ rmb();
+
+}
+
+static void receive_usb_probe(usbif_response_t *resp)
+{
+ spin_lock(&xhci->rh.port_state_lock);
+
+ if ( resp->status > 0 )
+ {
+ if ( resp->status == 1 )
+ {
+ /* If theres a device there and there wasn't one before there must
+ * have been a connection status change. */
+ if( xhci->rh.ports[resp->data].cs == 0 )
+ {
+ xhci->rh.ports[resp->data].cs = 1;
+ xhci->rh.ports[resp->data].ccs = 1;
+ xhci->rh.ports[resp->data].cs_chg = 1;
+ }
+ }
+ else
+ printk(KERN_WARNING "receive_usb_probe(): unexpected status %d for port %d\n",
+ resp->status, resp->data);
+ }
+ else if ( resp->status < 0)
+ printk(KERN_WARNING "receive_usb_probe(): got error status %d\n", resp->status);
+
+ spin_unlock(&xhci->rh.port_state_lock);
+}
+
+static void receive_usb_io(usbif_response_t *resp)
+{
+ struct urb_priv *urbp = (struct urb_priv *)resp->id;
+ struct urb *urb = urbp->urb;
+
+ urb->actual_length = resp->length;
+ urb->status = resp->status;
+ urbp->status = resp->status;
+ urbp->in_progress = 0;
+
+ if( usb_pipetype(urb->pipe) == 0 ) /* ISO */
+ {
+ int i;
+
+ /* Copy ISO schedule results back in. */
+
+ for ( i = 0; i < urb->number_of_packets; i++ )
+ {
+ urb->iso_frame_desc[i].status
+ = urbp->schedule[i].status;
+ urb->iso_frame_desc[i].actual_length
+ = urbp->schedule[i].length;
+ }
+ free_page((unsigned long)urbp->schedule);
+ }
+}
+
+static void xhci_drain_ring(void)
+{
+ struct list_head *tmp, *head;
+ usbif_front_ring_t *usb_ring = &xhci->usb_ring;
+ usbif_response_t *resp;
+ RING_IDX i, rp;
+
+ /* Walk the ring here to get responses, updating URBs to show what
+ * completed. */
+
+ rp = usb_ring->sring->rsp_prod;
+ rmb(); /* Ensure we see queued requests up to 'rp'. */
+
+ /* Take items off the comms ring, taking care not to overflow. */
+ for ( i = usb_ring->rsp_cons; i != rp; i++ )
+ {
+ resp = RING_GET_RESPONSE(USBIF_RING, usb_ring, i);
+
+ /* May need to deal with batching and with putting a ceiling on
+ the number dispatched for performance and anti-dos reasons */
+
+ xhci_show_resp(resp);
+
+ switch ( resp->operation )
+ {
+ case USBIF_OP_PROBE:
+ receive_usb_probe(resp);
+ break;
+
+ case USBIF_OP_IO:
+ receive_usb_io(resp);
+ break;
+
+ case USBIF_OP_RESET:
+ receive_usb_reset(resp);
+ break;
+
+ default:
+ printk(KERN_WARNING
+ "error: unknown USB io operation response [%d]\n",
+ resp->operation);
+ break;
+ }
+ }
+
+ usb_ring->rsp_cons = i;
+
+ /* Walk the list of pending URB's to see which ones completed and do
+ * callbacks, etc. */
+ spin_lock(&xhci->urb_list_lock);
+ head = &xhci->urb_list;
+ tmp = head->next;
+ while (tmp != head) {
+
+ struct urb *urb = list_entry(tmp, struct urb, urb_list);
+
+ tmp = tmp->next;
+
+ /* Checks the status and does all of the magic necessary */
+ xhci_transfer_result(xhci, urb);
+ }
+ spin_unlock(&xhci->urb_list_lock);
+
+ xhci_finish_completion();
+}
+
+
+static void xhci_interrupt(int irq, void *__xhci, struct pt_regs *regs)
+{
+ xhci_drain_ring();
+}
+
+static void free_xhci(struct xhci *xhci)
+{
+ kfree(xhci);
+}
+
+/**
+ * Initialise a new virtual root hub for a new USB device channel.
+ */
+static int alloc_xhci(void)
+{
+ int retval;
+ struct usb_bus *bus;
+
+ retval = -EBUSY;
+
+ xhci = kmalloc(sizeof(*xhci), GFP_KERNEL);
+ if (!xhci) {
+ err("couldn't allocate xhci structure");
+ retval = -ENOMEM;
+ goto err_alloc_xhci;
+ }
+
+ /* Reset here so we don't get any interrupts from an old setup */
+ /* or broken setup */
+ // reset_hc(xhci);
+
+
+ xhci->state = USBIF_STATE_CLOSED;
+ xhci->is_suspended = 0;
+
+ spin_lock_init(&xhci->urb_remove_list_lock);
+ INIT_LIST_HEAD(&xhci->urb_remove_list);
+
+ spin_lock_init(&xhci->urb_list_lock);
+ INIT_LIST_HEAD(&xhci->urb_list);
+
+ spin_lock_init(&xhci->complete_list_lock);
+ INIT_LIST_HEAD(&xhci->complete_list);
+
+ spin_lock_init(&xhci->frame_list_lock);
+
+ /* We need exactly one page (per XHCI specs), how convenient */
+ /* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
+#if PAGE_SIZE < (4 * 1024)
+#error PAGE_SIZE is not atleast 4k
+#endif
+ bus = usb_alloc_bus(&xhci_device_operations);
+ if (!bus) {
+ err("unable to allocate bus");
+ goto err_alloc_bus;
+ }
+
+ xhci->bus = bus;
+ bus->bus_name = "XHCI";
+ bus->hcpriv = xhci;
+
+ usb_register_bus(xhci->bus);
+
+ /* Initialize the root hub */
+
+ xhci->rh.numports = 0;
+
+ xhci->bus->root_hub = xhci->rh.dev = usb_alloc_dev(NULL, xhci->bus);
+ if (!xhci->rh.dev) {
+ err("unable to allocate root hub");
+ goto err_alloc_root_hub;
+ }
+
+ xhci->state = 0;
+
+ return 0;
+
+/*
+ * error exits:
+ */
+err_alloc_root_hub:
+ usb_free_bus(xhci->bus);
+ xhci->bus = NULL;
+
+err_alloc_bus:
+ free_xhci(xhci);
+
+err_alloc_xhci:
+ return retval;
+}
+
+static void usbif_status_change(usbif_fe_interface_status_changed_t *status)
+{
+ ctrl_msg_t cmsg;
+ usbif_fe_interface_connect_t up;
+ long rc;
+ usbif_sring_t *sring;
+
+ switch ( status->status )
+ {
+ case USBIF_INTERFACE_STATUS_DESTROYED:
+ printk(KERN_WARNING "Unexpected usbif-DESTROYED message in state %d\n",
+ xhci->state);
+ break;
+
+ case USBIF_INTERFACE_STATUS_DISCONNECTED:
+ if ( xhci->state != USBIF_STATE_CLOSED )
+ {
+ printk(KERN_WARNING "Unexpected usbif-DISCONNECTED message"
+ " in state %d\n", xhci->state);
+ break;
+ /* Not bothering to do recovery here for now. Keep things
+ * simple. */
+ }
+
+ /* Move from CLOSED to DISCONNECTED state. */
+ sring = (usbif_sring_t *)__get_free_page(GFP_KERNEL);
+ SHARED_RING_INIT(USBIF_RING, sring);
+ FRONT_RING_INIT(USBIF_RING, &xhci->usb_ring, sring);
+ xhci->state = USBIF_STATE_DISCONNECTED;
+
+ /* Construct an interface-CONNECT message for the domain controller. */
+ cmsg.type = CMSG_USBIF_FE;
+ cmsg.subtype = CMSG_USBIF_FE_INTERFACE_CONNECT;
+ cmsg.length = sizeof(usbif_fe_interface_connect_t);
+ up.shmem_frame = virt_to_machine(sring) >> PAGE_SHIFT;
+ memcpy(cmsg.msg, &up, sizeof(up));
+
+ /* Tell the controller to bring up the interface. */
+ ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+ break;
+
+ case USBIF_INTERFACE_STATUS_CONNECTED:
+ if ( xhci->state == USBIF_STATE_CLOSED )
+ {
+ printk(KERN_WARNING "Unexpected usbif-CONNECTED message"
+ " in state %d\n", xhci->state);
+ break;
+ }
+
+ xhci->evtchn = status->evtchn;
+ xhci->irq = bind_evtchn_to_irq(xhci->evtchn);
+ xhci->bandwidth = status->bandwidth;
+ xhci->rh.numports = status->num_ports;
+
+ xhci->rh.ports = kmalloc (sizeof(xhci_port_t) * xhci->rh.numports, GFP_KERNEL);
+ memset(xhci->rh.ports, 0, sizeof(xhci_port_t) * xhci->rh.numports);
+
+ usb_connect(xhci->rh.dev);
+
+ if (usb_new_device(xhci->rh.dev) != 0) {
+ err("unable to start root hub");
+ }
+
+ /* Allocate the appropriate USB bandwidth here... Need to
+ * somehow know what the total available is thought to be so we
+ * can calculate the reservation correctly. */
+ usb_claim_bandwidth(xhci->rh.dev, xhci->rh.urb,
+ 1000 - xhci->bandwidth, 0);
+
+ if ( (rc = request_irq(xhci->irq, xhci_interrupt,
+ SA_SAMPLE_RANDOM, "usbif", xhci)) )
+ printk(KERN_ALERT"usbfront request_irq failed (%ld)\n",rc);
+
+ DPRINTK(KERN_INFO __FILE__ ": USB XHCI: SHM at %p (0x%lx), EVTCHN %d IRQ %d\n",
+ xhci->usb_ring.sring, virt_to_machine(xhci->usbif), xhci->evtchn, xhci->irq);
+
+ xhci->state = USBIF_STATE_CONNECTED;
+
+ break;
+
+ default:
+ printk(KERN_WARNING "Status change to unknown value %d\n",
+ status->status);
+ break;
+ }
+}
+
+
+static void usbif_ctrlif_rx(ctrl_msg_t *msg, unsigned long id)
+{
+ switch ( msg->subtype )
+ {
+ case CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED:
+ if ( msg->length != sizeof(usbif_fe_interface_status_changed_t) )
+ goto parse_error;
+ usbif_status_change((usbif_fe_interface_status_changed_t *)
+ &msg->msg[0]);
+ break;
+
+ /* New interface...? */
+ default:
+ goto parse_error;
+ }
+
+ ctrl_if_send_response(msg);
+ return;
+
+ parse_error:
+ msg->length = 0;
+ ctrl_if_send_response(msg);
+}
+
+
+static int __init xhci_hcd_init(void)
+{
+ int retval = -ENOMEM, i;
+ usbif_fe_interface_status_changed_t st;
+ control_msg_t cmsg;
+
+ if ( (xen_start_info.flags & SIF_INITDOMAIN)
+ || (xen_start_info.flags & SIF_USB_BE_DOMAIN) )
+ return 0;
+
+ info(DRIVER_DESC " " DRIVER_VERSION);
+
+ if (debug) {
+ errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
+ if (!errbuf)
+ goto errbuf_failed;
+ }
+
+ xhci_up_cachep = kmem_cache_create("xhci_urb_priv",
+ sizeof(struct urb_priv), 0, 0, NULL, NULL);
+ if (!xhci_up_cachep)
+ goto up_failed;
+
+ /* Lazily avoid unloading issues for now. ;-)*/
+ MOD_INC_USE_COUNT;
+
+ /* Let the domain controller know we're here. For now we wait until
+ * connection, as for the block and net drivers. This is only strictly
+ * necessary if we're going to boot off a USB device. */
+ printk(KERN_INFO "Initialising Xen virtual USB hub\n");
+
+ (void)ctrl_if_register_receiver(CMSG_USBIF_FE, usbif_ctrlif_rx,
+ CALLBACK_IN_BLOCKING_CONTEXT);
+
+ alloc_xhci();
+
+ /* Send a driver-UP notification to the domain controller. */
+ cmsg.type = CMSG_USBIF_FE;
+ cmsg.subtype = CMSG_USBIF_FE_DRIVER_STATUS_CHANGED;
+ cmsg.length = sizeof(usbif_fe_driver_status_changed_t);
+ st.status = USBIF_DRIVER_STATUS_UP;
+ memcpy(cmsg.msg, &st, sizeof(st));
+ ctrl_if_send_message_block(&cmsg, NULL, 0, TASK_UNINTERRUPTIBLE);
+
+ /*
+ * We should read 'nr_interfaces' from response message and wait
+ * for notifications before proceeding. For now we assume that we
+ * will be notified of exactly one interface.
+ */
+ for ( i=0; (xhci->state != USBIF_STATE_CONNECTED) && (i < 10*HZ); i++ )
+ {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(1);
+ }
+
+ if (xhci->state != USBIF_STATE_CONNECTED)
+ printk(KERN_WARNING "Timeout connecting USB frontend driver!\n");
+
+ return 0;
+
+up_failed:
+
+ if (errbuf)
+ kfree(errbuf);
+
+errbuf_failed:
+
+ return retval;
+}
+
+static void __exit xhci_hcd_cleanup(void)
+{
+ if (kmem_cache_destroy(xhci_up_cachep))
+ printk(KERN_WARNING "xhci: not all urb_priv's were freed\n");
+
+// release_xhci(); do some calls here
+
+
+ if (errbuf)
+ kfree(errbuf);
+}
+
+module_init(xhci_hcd_init);
+module_exit(xhci_hcd_cleanup);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
diff --git a/linux-2.6.10-xen-sparse/drivers/xen/usbfront/xhci.h b/linux-2.6.10-xen-sparse/drivers/xen/usbfront/xhci.h
new file mode 100644
index 0000000000..2a0907f600
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/drivers/xen/usbfront/xhci.h
@@ -0,0 +1,210 @@
+#ifndef __LINUX_XHCI_H
+#define __LINUX_XHCI_H
+
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <asm-xen/xen-public/io/usbif.h>
+#include <linux/spinlock.h>
+
+#define XHCI_NUMFRAMES 1024 /* in the frame list [array] */
+#define XHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
+#define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */
+
+/* In the absence of actual hardware state, we maintain the current known state
+ * of the virtual hub ports in this data structure.
+ */
+typedef struct
+{
+ unsigned int cs :1; /* Connection status. do we really need this /and/ ccs? */
+ unsigned int cs_chg :1; /* Connection status change. */
+ unsigned int pe :1; /* Port enable. */
+ unsigned int pe_chg :1; /* Port enable change. */
+ unsigned int ccs :1; /* Current connect status. */
+ unsigned int susp :1; /* Suspended. */
+ unsigned int lsda :1; /* Low speed device attached. */
+ unsigned int pr :1; /* Port reset. */
+
+ /* Device info? */
+} xhci_port_t;
+
+struct xhci_frame_list {
+ __u32 frame[XHCI_NUMFRAMES];
+
+ void *frame_cpu[XHCI_NUMFRAMES];
+};
+
+struct urb_priv;
+
+#define xhci_status_bits(ctrl_sts) (ctrl_sts & 0xFE0000)
+#define xhci_actual_length(ctrl_sts) ((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */
+
+#define xhci_maxlen(token) ((token) >> 21)
+#define xhci_expected_length(info) (((info >> 21) + 1) & TD_TOKEN_EXPLEN_MASK) /* 1-based */
+#define xhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE_SHIFT) & 1)
+#define xhci_endpoint(token) (((token) >> 15) & 0xf)
+#define xhci_devaddr(token) (((token) >> 8) & 0x7f)
+#define xhci_devep(token) (((token) >> 8) & 0x7ff)
+#define xhci_packetid(token) ((token) & TD_TOKEN_PID_MASK)
+#define xhci_packetout(token) (xhci_packetid(token) != USB_PID_IN)
+#define xhci_packetin(token) (xhci_packetid(token) == USB_PID_IN)
+
+struct virt_root_hub {
+ struct usb_device *dev;
+ int devnum; /* Address of Root Hub endpoint */
+ struct urb *urb;
+ void *int_addr;
+ int send;
+ int interval;
+ int numports;
+ int c_p_r[8];
+ struct timer_list rh_int_timer;
+ spinlock_t port_state_lock;
+ xhci_port_t *ports; /* */
+};
+
+/*
+ * This describes the full xhci information.
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs.
+ */
+struct xhci {
+
+#ifdef CONFIG_PROC_FS
+ /* procfs */
+ int num;
+ struct proc_dir_entry *proc_entry;
+#endif
+
+ int evtchn; /* Interdom channel to backend */
+ int irq; /* Bound to evtchn */
+ int state; /* State of this USB interface */
+ unsigned long bandwidth;
+ int handle;
+
+ struct usb_bus *bus;
+
+ spinlock_t frame_list_lock;
+ struct xhci_frame_list *fl; /* P: xhci->frame_list_lock */
+ int is_suspended;
+
+ /* Main list of URB's currently controlled by this HC */
+ spinlock_t urb_list_lock;
+ struct list_head urb_list; /* P: xhci->urb_list_lock */
+
+ /* List of asynchronously unlinked URB's */
+ spinlock_t urb_remove_list_lock;
+ struct list_head urb_remove_list; /* P: xhci->urb_remove_list_lock */
+
+ /* List of URB's awaiting completion callback */
+ spinlock_t complete_list_lock;
+ struct list_head complete_list; /* P: xhci->complete_list_lock */
+
+ struct virt_root_hub rh; /* private data of the virtual root hub */
+
+ spinlock_t response_lock;
+
+ usbif_front_ring_t usb_ring;
+ int usb_resp_cons;
+};
+
+struct urb_priv {
+ struct urb *urb;
+ usbif_iso_t *schedule;
+ struct usb_device *dev;
+
+ int in_progress : 1; /* QH was queued (not linked in) */
+ int short_control_packet : 1; /* If we get a short packet during */
+ /* a control transfer, retrigger */
+ /* the status phase */
+
+ int status; /* Final status */
+
+ unsigned long inserttime; /* In jiffies */
+
+ struct list_head queue_list; /* P: xhci->frame_list_lock */
+ struct list_head complete_list; /* P: xhci->complete_list_lock */
+};
+
+/*
+ * Locking in xhci.c
+ *
+ * spinlocks are used extensively to protect the many lists and data
+ * structures we have. It's not that pretty, but it's necessary. We
+ * need to be done with all of the locks (except complete_list_lock) when
+ * we call urb->complete. I've tried to make it simple enough so I don't
+ * have to spend hours racking my brain trying to figure out if the
+ * locking is safe.
+ *
+ * Here's the safe locking order to prevent deadlocks:
+ *
+ * #1 xhci->urb_list_lock
+ * #2 urb->lock
+ * #3 xhci->urb_remove_list_lock, xhci->frame_list_lock,
+ * xhci->qh_remove_list_lock
+ * #4 xhci->complete_list_lock
+ *
+ * If you're going to grab 2 or more locks at once, ALWAYS grab the lock
+ * at the lowest level FIRST and NEVER grab locks at the same level at the
+ * same time.
+ *
+ * So, if you need xhci->urb_list_lock, grab it before you grab urb->lock
+ */
+
+/* -------------------------------------------------------------------------
+ Virtual Root HUB
+ ------------------------------------------------------------------------- */
+/* destination of request */
+#define RH_DEVICE 0x00
+#define RH_INTERFACE 0x01
+#define RH_ENDPOINT 0x02
+#define RH_OTHER 0x03
+
+#define RH_CLASS 0x20
+#define RH_VENDOR 0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS 0x0080
+#define RH_CLEAR_FEATURE 0x0100
+#define RH_SET_FEATURE 0x0300
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_DESCRIPTOR 0x0700
+#define RH_GET_CONFIGURATION 0x0880
+#define RH_SET_CONFIGURATION 0x0900
+#define RH_GET_STATE 0x0280
+#define RH_GET_INTERFACE 0x0A80
+#define RH_SET_INTERFACE 0x0B00
+#define RH_SYNC_FRAME 0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP 0x2000
+
+/* Hub port features */
+#define RH_PORT_CONNECTION 0x00
+#define RH_PORT_ENABLE 0x01
+#define RH_PORT_SUSPEND 0x02
+#define RH_PORT_OVER_CURRENT 0x03
+#define RH_PORT_RESET 0x04
+#define RH_PORT_POWER 0x08
+#define RH_PORT_LOW_SPEED 0x09
+#define RH_C_PORT_CONNECTION 0x10
+#define RH_C_PORT_ENABLE 0x11
+#define RH_C_PORT_SUSPEND 0x12
+#define RH_C_PORT_OVER_CURRENT 0x13
+#define RH_C_PORT_RESET 0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER 0x00
+#define RH_C_HUB_OVER_CURRENT 0x01
+#define RH_DEVICE_REMOTE_WAKEUP 0x00
+#define RH_ENDPOINT_STALL 0x01
+
+/* Our Vendor Specific feature */
+#define RH_REMOVE_EP 0x00
+
+#define RH_ACK 0x01
+#define RH_REQ_ERR -1
+#define RH_NACK 0x00
+
+#endif
+
diff --git a/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h b/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h
index 30f4d88b62..dd28b49175 100644
--- a/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h
+++ b/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/mach-xen/irq_vectors.h
@@ -34,6 +34,7 @@
* Vectors 0x20-0x2f are used for ISA interrupts.
*/
+#if 0
/*
* Special IRQ vectors used by the SMP architecture, 0xf0-0xff
*
@@ -56,6 +57,7 @@
* sources per level' errata.
*/
#define LOCAL_TIMER_VECTOR 0xef
+#endif
/*
* First APIC vector available to drivers: (vectors 0x30-0xee)
@@ -65,8 +67,6 @@
#define FIRST_DEVICE_VECTOR 0x31
#define FIRST_SYSTEM_VECTOR 0xef
-#define TIMER_IRQ timer_irq
-
/*
* 16 8259A IRQ's, 208 potential APIC interrupt sources.
* Right now the APIC is mostly only used for SMP.
@@ -77,14 +77,18 @@
* the usable vector space is 0x20-0xff (224 vectors)
*/
-#if 0
+#define NR_IPIS 8
+
+#define RESCHEDULE_VECTOR 1
+#define INVALIDATE_TLB_VECTOR 2
+#define CALL_FUNCTION_VECTOR 3
+
/*
* The maximum number of vectors supported by i386 processors
* is limited to 256. For processors other than i386, NR_VECTORS
* should be changed accordingly.
*/
#define NR_VECTORS 256
-#endif
#define FPU_IRQ 13
@@ -103,10 +107,10 @@
*/
#define PIRQ_BASE 0
-#define NR_PIRQS 128
+#define NR_PIRQS 256
#define DYNIRQ_BASE (PIRQ_BASE + NR_PIRQS)
-#define NR_DYNIRQS 128
+#define NR_DYNIRQS 256
#define NR_IRQS (NR_PIRQS + NR_DYNIRQS)
#define NR_IRQ_VECTORS NR_IRQS
@@ -121,6 +125,8 @@
/* Dynamic binding of event channels and VIRQ sources to Linux IRQ space. */
extern int bind_virq_to_irq(int virq);
extern void unbind_virq_from_irq(int virq);
+extern int bind_ipi_on_cpu_to_irq(int cpu, int ipi);
+extern void unbind_ipi_on_cpu_from_irq(int cpu, int ipi);
extern int bind_evtchn_to_irq(int evtchn);
extern void unbind_evtchn_from_irq(int evtchn);
diff --git a/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h b/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h
new file mode 100644
index 0000000000..421a81f17b
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/mach-xen/smpboot_hooks.h
@@ -0,0 +1,59 @@
+/* two abstractions specific to kernel/smpboot.c, mainly to cater to visws
+ * which needs to alter them. */
+
+static inline void smpboot_clear_io_apic_irqs(void)
+{
+#if 1
+ printk("smpboot_clear_io_apic_irqs\n");
+#else
+ io_apic_irqs = 0;
+#endif
+}
+
+static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
+{
+#if 1
+ printk("smpboot_setup_warm_reset_vector\n");
+#else
+ CMOS_WRITE(0xa, 0xf);
+ local_flush_tlb();
+ Dprintk("1.\n");
+ *((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4;
+ Dprintk("2.\n");
+ *((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf;
+ Dprintk("3.\n");
+#endif
+}
+
+static inline void smpboot_restore_warm_reset_vector(void)
+{
+ /*
+ * Install writable page 0 entry to set BIOS data area.
+ */
+ local_flush_tlb();
+
+ /*
+ * Paranoid: Set warm reset code and vector here back
+ * to default values.
+ */
+ CMOS_WRITE(0, 0xf);
+
+ *((volatile long *) phys_to_virt(0x467)) = 0;
+}
+
+static inline void smpboot_setup_io_apic(void)
+{
+#if 1
+ printk("smpboot_setup_io_apic\n");
+#else
+ /*
+ * Here we can be sure that there is an IO-APIC in the system. Let's
+ * go and set it up:
+ */
+ if (!skip_ioapic_setup && nr_ioapics)
+ setup_IO_APIC();
+#endif
+}
+
+
+#define smp_found_config (HYPERVISOR_shared_info->n_vcpu > 1)
diff --git a/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/msr.h b/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/msr.h
deleted file mode 100644
index 4cc4f318ba..0000000000
--- a/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/msr.h
+++ /dev/null
@@ -1,272 +0,0 @@
-#ifndef __ASM_MSR_H
-#define __ASM_MSR_H
-
-#include <linux/smp.h>
-#include <asm-xen/hypervisor.h>
-
-/*
- * Access to machine-specific registers (available on 586 and better only)
- * Note: the rd* operations modify the parameters directly (without using
- * pointer indirection), this allows gcc to optimize better
- */
-
-#define rdmsr(_msr,_val1,_val2) do { \
- dom0_op_t op; \
- op.cmd = DOM0_MSR; \
- op.u.msr.write = 0; \
- op.u.msr.msr = (_msr); \
- op.u.msr.cpu_mask = (1 << smp_processor_id()); \
- HYPERVISOR_dom0_op(&op); \
- (_val1) = op.u.msr.out1; \
- (_val2) = op.u.msr.out2; \
-} while(0)
-
-#define wrmsr(_msr,_val1,_val2) do { \
- dom0_op_t op; \
- op.cmd = DOM0_MSR; \
- op.u.msr.write = 1; \
- op.u.msr.cpu_mask = (1 << smp_processor_id()); \
- op.u.msr.msr = (_msr); \
- op.u.msr.in1 = (_val1); \
- op.u.msr.in2 = (_val2); \
- HYPERVISOR_dom0_op(&op); \
-} while(0)
-
-#define rdmsrl(msr,val) do { \
- unsigned long l__,h__; \
- rdmsr (msr, l__, h__); \
- val = l__; \
- val |= ((u64)h__<<32); \
-} while(0)
-
-static inline void wrmsrl (unsigned long msr, unsigned long long val)
-{
- unsigned long lo, hi;
- lo = (unsigned long) val;
- hi = val >> 32;
- wrmsr (msr, lo, hi);
-}
-
-#define rdtsc(low,high) \
- __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
-
-#define rdtscl(low) \
- __asm__ __volatile__("rdtsc" : "=a" (low) : : "edx")
-
-#define rdtscll(val) \
- __asm__ __volatile__("rdtsc" : "=A" (val))
-
-#define write_tsc(val1,val2) wrmsr(0x10, val1, val2)
-
-#define rdpmc(counter,low,high) \
- __asm__ __volatile__("rdpmc" \
- : "=a" (low), "=d" (high) \
- : "c" (counter))
-
-/* symbolic names for some interesting MSRs */
-/* Intel defined MSRs. */
-#define MSR_IA32_P5_MC_ADDR 0
-#define MSR_IA32_P5_MC_TYPE 1
-#define MSR_IA32_PLATFORM_ID 0x17
-#define MSR_IA32_EBL_CR_POWERON 0x2a
-
-#define MSR_IA32_APICBASE 0x1b
-#define MSR_IA32_APICBASE_BSP (1<<8)
-#define MSR_IA32_APICBASE_ENABLE (1<<11)
-#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
-
-#define MSR_IA32_UCODE_WRITE 0x79
-#define MSR_IA32_UCODE_REV 0x8b
-
-#define MSR_P6_PERFCTR0 0xc1
-#define MSR_P6_PERFCTR1 0xc2
-
-#define MSR_IA32_BBL_CR_CTL 0x119
-
-#define MSR_IA32_SYSENTER_CS 0x174
-#define MSR_IA32_SYSENTER_ESP 0x175
-#define MSR_IA32_SYSENTER_EIP 0x176
-
-#define MSR_IA32_MCG_CAP 0x179
-#define MSR_IA32_MCG_STATUS 0x17a
-#define MSR_IA32_MCG_CTL 0x17b
-
-/* P4/Xeon+ specific */
-#define MSR_IA32_MCG_EAX 0x180
-#define MSR_IA32_MCG_EBX 0x181
-#define MSR_IA32_MCG_ECX 0x182
-#define MSR_IA32_MCG_EDX 0x183
-#define MSR_IA32_MCG_ESI 0x184
-#define MSR_IA32_MCG_EDI 0x185
-#define MSR_IA32_MCG_EBP 0x186
-#define MSR_IA32_MCG_ESP 0x187
-#define MSR_IA32_MCG_EFLAGS 0x188
-#define MSR_IA32_MCG_EIP 0x189
-#define MSR_IA32_MCG_RESERVED 0x18A
-
-#define MSR_P6_EVNTSEL0 0x186
-#define MSR_P6_EVNTSEL1 0x187
-
-#define MSR_IA32_PERF_STATUS 0x198
-#define MSR_IA32_PERF_CTL 0x199
-
-#define MSR_IA32_THERM_CONTROL 0x19a
-#define MSR_IA32_THERM_INTERRUPT 0x19b
-#define MSR_IA32_THERM_STATUS 0x19c
-#define MSR_IA32_MISC_ENABLE 0x1a0
-
-#define MSR_IA32_DEBUGCTLMSR 0x1d9
-#define MSR_IA32_LASTBRANCHFROMIP 0x1db
-#define MSR_IA32_LASTBRANCHTOIP 0x1dc
-#define MSR_IA32_LASTINTFROMIP 0x1dd
-#define MSR_IA32_LASTINTTOIP 0x1de
-
-#define MSR_IA32_MC0_CTL 0x400
-#define MSR_IA32_MC0_STATUS 0x401
-#define MSR_IA32_MC0_ADDR 0x402
-#define MSR_IA32_MC0_MISC 0x403
-
-/* Pentium IV performance counter MSRs */
-#define MSR_P4_BPU_PERFCTR0 0x300
-#define MSR_P4_BPU_PERFCTR1 0x301
-#define MSR_P4_BPU_PERFCTR2 0x302
-#define MSR_P4_BPU_PERFCTR3 0x303
-#define MSR_P4_MS_PERFCTR0 0x304
-#define MSR_P4_MS_PERFCTR1 0x305
-#define MSR_P4_MS_PERFCTR2 0x306
-#define MSR_P4_MS_PERFCTR3 0x307
-#define MSR_P4_FLAME_PERFCTR0 0x308
-#define MSR_P4_FLAME_PERFCTR1 0x309
-#define MSR_P4_FLAME_PERFCTR2 0x30a
-#define MSR_P4_FLAME_PERFCTR3 0x30b
-#define MSR_P4_IQ_PERFCTR0 0x30c
-#define MSR_P4_IQ_PERFCTR1 0x30d
-#define MSR_P4_IQ_PERFCTR2 0x30e
-#define MSR_P4_IQ_PERFCTR3 0x30f
-#define MSR_P4_IQ_PERFCTR4 0x310
-#define MSR_P4_IQ_PERFCTR5 0x311
-#define MSR_P4_BPU_CCCR0 0x360
-#define MSR_P4_BPU_CCCR1 0x361
-#define MSR_P4_BPU_CCCR2 0x362
-#define MSR_P4_BPU_CCCR3 0x363
-#define MSR_P4_MS_CCCR0 0x364
-#define MSR_P4_MS_CCCR1 0x365
-#define MSR_P4_MS_CCCR2 0x366
-#define MSR_P4_MS_CCCR3 0x367
-#define MSR_P4_FLAME_CCCR0 0x368
-#define MSR_P4_FLAME_CCCR1 0x369
-#define MSR_P4_FLAME_CCCR2 0x36a
-#define MSR_P4_FLAME_CCCR3 0x36b
-#define MSR_P4_IQ_CCCR0 0x36c
-#define MSR_P4_IQ_CCCR1 0x36d
-#define MSR_P4_IQ_CCCR2 0x36e
-#define MSR_P4_IQ_CCCR3 0x36f
-#define MSR_P4_IQ_CCCR4 0x370
-#define MSR_P4_IQ_CCCR5 0x371
-#define MSR_P4_ALF_ESCR0 0x3ca
-#define MSR_P4_ALF_ESCR1 0x3cb
-#define MSR_P4_BPU_ESCR0 0x3b2
-#define MSR_P4_BPU_ESCR1 0x3b3
-#define MSR_P4_BSU_ESCR0 0x3a0
-#define MSR_P4_BSU_ESCR1 0x3a1
-#define MSR_P4_CRU_ESCR0 0x3b8
-#define MSR_P4_CRU_ESCR1 0x3b9
-#define MSR_P4_CRU_ESCR2 0x3cc
-#define MSR_P4_CRU_ESCR3 0x3cd
-#define MSR_P4_CRU_ESCR4 0x3e0
-#define MSR_P4_CRU_ESCR5 0x3e1
-#define MSR_P4_DAC_ESCR0 0x3a8
-#define MSR_P4_DAC_ESCR1 0x3a9
-#define MSR_P4_FIRM_ESCR0 0x3a4
-#define MSR_P4_FIRM_ESCR1 0x3a5
-#define MSR_P4_FLAME_ESCR0 0x3a6
-#define MSR_P4_FLAME_ESCR1 0x3a7
-#define MSR_P4_FSB_ESCR0 0x3a2
-#define MSR_P4_FSB_ESCR1 0x3a3
-#define MSR_P4_IQ_ESCR0 0x3ba
-#define MSR_P4_IQ_ESCR1 0x3bb
-#define MSR_P4_IS_ESCR0 0x3b4
-#define MSR_P4_IS_ESCR1 0x3b5
-#define MSR_P4_ITLB_ESCR0 0x3b6
-#define MSR_P4_ITLB_ESCR1 0x3b7
-#define MSR_P4_IX_ESCR0 0x3c8
-#define MSR_P4_IX_ESCR1 0x3c9
-#define MSR_P4_MOB_ESCR0 0x3aa
-#define MSR_P4_MOB_ESCR1 0x3ab
-#define MSR_P4_MS_ESCR0 0x3c0
-#define MSR_P4_MS_ESCR1 0x3c1
-#define MSR_P4_PMH_ESCR0 0x3ac
-#define MSR_P4_PMH_ESCR1 0x3ad
-#define MSR_P4_RAT_ESCR0 0x3bc
-#define MSR_P4_RAT_ESCR1 0x3bd
-#define MSR_P4_SAAT_ESCR0 0x3ae
-#define MSR_P4_SAAT_ESCR1 0x3af
-#define MSR_P4_SSU_ESCR0 0x3be
-#define MSR_P4_SSU_ESCR1 0x3bf /* guess: not defined in manual */
-#define MSR_P4_TBPU_ESCR0 0x3c2
-#define MSR_P4_TBPU_ESCR1 0x3c3
-#define MSR_P4_TC_ESCR0 0x3c4
-#define MSR_P4_TC_ESCR1 0x3c5
-#define MSR_P4_U2L_ESCR0 0x3b0
-#define MSR_P4_U2L_ESCR1 0x3b1
-
-/* AMD Defined MSRs */
-#define MSR_K6_EFER 0xC0000080
-#define MSR_K6_STAR 0xC0000081
-#define MSR_K6_WHCR 0xC0000082
-#define MSR_K6_UWCCR 0xC0000085
-#define MSR_K6_EPMR 0xC0000086
-#define MSR_K6_PSOR 0xC0000087
-#define MSR_K6_PFIR 0xC0000088
-
-#define MSR_K7_EVNTSEL0 0xC0010000
-#define MSR_K7_EVNTSEL1 0xC0010001
-#define MSR_K7_EVNTSEL2 0xC0010002
-#define MSR_K7_EVNTSEL3 0xC0010003
-#define MSR_K7_PERFCTR0 0xC0010004
-#define MSR_K7_PERFCTR1 0xC0010005
-#define MSR_K7_PERFCTR2 0xC0010006
-#define MSR_K7_PERFCTR3 0xC0010007
-#define MSR_K7_HWCR 0xC0010015
-#define MSR_K7_CLK_CTL 0xC001001b
-#define MSR_K7_FID_VID_CTL 0xC0010041
-#define MSR_K7_FID_VID_STATUS 0xC0010042
-
-/* extended feature register */
-#define MSR_EFER 0xc0000080
-
-/* EFER bits: */
-
-/* Execute Disable enable */
-#define _EFER_NX 11
-#define EFER_NX (1<<_EFER_NX)
-
-/* Centaur-Hauls/IDT defined MSRs. */
-#define MSR_IDT_FCR1 0x107
-#define MSR_IDT_FCR2 0x108
-#define MSR_IDT_FCR3 0x109
-#define MSR_IDT_FCR4 0x10a
-
-#define MSR_IDT_MCR0 0x110
-#define MSR_IDT_MCR1 0x111
-#define MSR_IDT_MCR2 0x112
-#define MSR_IDT_MCR3 0x113
-#define MSR_IDT_MCR4 0x114
-#define MSR_IDT_MCR5 0x115
-#define MSR_IDT_MCR6 0x116
-#define MSR_IDT_MCR7 0x117
-#define MSR_IDT_MCR_CTRL 0x120
-
-/* VIA Cyrix defined MSRs*/
-#define MSR_VIA_FCR 0x1107
-#define MSR_VIA_LONGHAUL 0x110a
-#define MSR_VIA_RNG 0x110b
-#define MSR_VIA_BCR2 0x1147
-
-/* Transmeta defined MSRs */
-#define MSR_TMTA_LONGRUN_CTRL 0x80868010
-#define MSR_TMTA_LONGRUN_FLAGS 0x80868011
-#define MSR_TMTA_LRTI_READOUT 0x80868018
-#define MSR_TMTA_LRTI_VOLT_MHZ 0x8086801a
-
-#endif /* __ASM_MSR_H */
diff --git a/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/pgtable-2level.h b/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/pgtable-2level.h
index 36a2420a29..c7db3fee59 100644
--- a/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/pgtable-2level.h
+++ b/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/pgtable-2level.h
@@ -25,8 +25,20 @@ static inline int pgd_present(pgd_t pgd) { return 1; }
*/
#define set_pte_batched(pteptr, pteval) \
queue_l1_entry_update(pteptr, (pteval).pte_low)
+
+#ifdef CONFIG_SMP
+#define set_pte(pteptr, pteval) xen_l1_entry_update(pteptr, (pteval).pte_low)
+#if 0
+do { \
+ (*(pteptr) = pteval); \
+ HYPERVISOR_xen_version(0); \
+} while (0)
+#endif
+#define set_pte_atomic(pteptr, pteval) set_pte(pteptr, pteval)
+#else
#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
#define set_pte_atomic(pteptr, pteval) set_pte(pteptr,pteval)
+#endif
/*
* (pmds are folded into pgds so this doesn't get actually called,
* but the define is needed for a generic inline function.)
diff --git a/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/processor.h b/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/processor.h
index 53b71d3113..2e89e92e04 100644
--- a/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/processor.h
+++ b/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/processor.h
@@ -87,7 +87,7 @@ extern struct cpuinfo_x86 boot_cpu_data;
extern struct cpuinfo_x86 new_cpu_data;
extern struct tss_struct doublefault_tss;
DECLARE_PER_CPU(struct tss_struct, init_tss);
-extern pgd_t *cur_pgd; /* XXXsmp */
+DECLARE_PER_CPU(pgd_t *, cur_pgd);
#ifdef CONFIG_SMP
extern struct cpuinfo_x86 cpu_data[];
@@ -184,7 +184,7 @@ static inline unsigned int cpuid_edx(unsigned int op)
#define load_cr3(pgdir) do { \
queue_pt_switch(__pa(pgdir)); \
- cur_pgd = pgdir; /* XXXsmp */ \
+ per_cpu(cur_pgd, smp_processor_id()) = pgdir; \
} while (/* CONSTCOND */0)
diff --git a/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/spinlock.h b/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/spinlock.h
new file mode 100644
index 0000000000..fb8bd00753
--- /dev/null
+++ b/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/spinlock.h
@@ -0,0 +1,224 @@
+#ifndef __ASM_SPINLOCK_H
+#define __ASM_SPINLOCK_H
+
+#include <asm/atomic.h>
+#include <asm/rwlock.h>
+#include <asm/page.h>
+#include <linux/config.h>
+#include <linux/compiler.h>
+
+asmlinkage int printk(const char * fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+
+/*
+ * Your basic SMP spinlocks, allowing only a single CPU anywhere
+ */
+
+typedef struct {
+ volatile unsigned int lock;
+#ifdef CONFIG_DEBUG_SPINLOCK
+ unsigned magic;
+#endif
+} spinlock_t;
+
+#define SPINLOCK_MAGIC 0xdead4ead
+
+#ifdef CONFIG_DEBUG_SPINLOCK
+#define SPINLOCK_MAGIC_INIT , SPINLOCK_MAGIC
+#else
+#define SPINLOCK_MAGIC_INIT /* */
+#endif
+
+#define SPIN_LOCK_UNLOCKED (spinlock_t) { 1 SPINLOCK_MAGIC_INIT }
+
+#define spin_lock_init(x) do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
+
+/*
+ * Simple spin lock operations. There are two variants, one clears IRQ's
+ * on the local processor, one does not.
+ *
+ * We make no fairness assumptions. They have a cost.
+ */
+
+#define spin_is_locked(x) (*(volatile signed char *)(&(x)->lock) <= 0)
+#define spin_unlock_wait(x) do { barrier(); } while(spin_is_locked(x))
+
+#define spin_lock_string \
+ "\n1:\t" \
+ "lock ; decb %0\n\t" \
+ "jns 3f\n" \
+ "2:\t" \
+ "rep;nop\n\t" \
+ "cmpb $0,%0\n\t" \
+ "jle 2b\n\t" \
+ "jmp 1b\n" \
+ "3:\n\t"
+
+#define spin_lock_string_flags \
+ "\n1:\t" \
+ "lock ; decb %0\n\t" \
+ "jns 4f\n\t" \
+ "2:\t" \
+ "testl $0x200, %1\n\t" \
+ "jz 3f\n\t" \
+ "#sti\n\t" \
+ "3:\t" \
+ "rep;nop\n\t" \
+ "cmpb $0, %0\n\t" \
+ "jle 3b\n\t" \
+ "#cli\n\t" \
+ "jmp 1b\n" \
+ "4:\n\t"
+
+/*
+ * This works. Despite all the confusion.
+ * (except on PPro SMP or if we are using OOSTORE)
+ * (PPro errata 66, 92)
+ */
+
+#if !defined(CONFIG_X86_OOSTORE) && !defined(CONFIG_X86_PPRO_FENCE)
+
+#define spin_unlock_string \
+ "movb $1,%0" \
+ :"=m" (lock->lock) : : "memory"
+
+
+static inline void _raw_spin_unlock(spinlock_t *lock)
+{
+#ifdef CONFIG_DEBUG_SPINLOCK
+ BUG_ON(lock->magic != SPINLOCK_MAGIC);
+ BUG_ON(!spin_is_locked(lock));
+#endif
+ __asm__ __volatile__(
+ spin_unlock_string
+ );
+}
+
+#else
+
+#define spin_unlock_string \
+ "xchgb %b0, %1" \
+ :"=q" (oldval), "=m" (lock->lock) \
+ :"0" (oldval) : "memory"
+
+static inline void _raw_spin_unlock(spinlock_t *lock)
+{
+ char oldval = 1;
+#ifdef CONFIG_DEBUG_SPINLOCK
+ BUG_ON(lock->magic != SPINLOCK_MAGIC);
+ BUG_ON(!spin_is_locked(lock));
+#endif
+ __asm__ __volatile__(
+ spin_unlock_string
+ );
+}
+
+#endif
+
+static inline int _raw_spin_trylock(spinlock_t *lock)
+{
+ char oldval;
+ __asm__ __volatile__(
+ "xchgb %b0,%1"
+ :"=q" (oldval), "=m" (lock->lock)
+ :"0" (0) : "memory");
+ return oldval > 0;
+}
+
+static inline void _raw_spin_lock(spinlock_t *lock)
+{
+#ifdef CONFIG_DEBUG_SPINLOCK
+ if (unlikely(lock->magic != SPINLOCK_MAGIC)) {
+ printk("eip: %p\n", __builtin_return_address(0));
+ BUG();
+ }
+#endif
+ __asm__ __volatile__(
+ spin_lock_string
+ :"=m" (lock->lock) : : "memory");
+}
+
+static inline void _raw_spin_lock_flags (spinlock_t *lock, unsigned long flags)
+{
+#ifdef CONFIG_DEBUG_SPINLOCK
+ if (unlikely(lock->magic != SPINLOCK_MAGIC)) {
+ printk("eip: %p\n", __builtin_return_address(0));
+ BUG();
+ }
+#endif
+ __asm__ __volatile__(
+ spin_lock_string_flags
+ :"=m" (lock->lock) : "r" (flags) : "memory");
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * NOTE! it is quite common to have readers in interrupts
+ * but no interrupt writers. For those circumstances we
+ * can "mix" irq-safe locks - any writer needs to get a
+ * irq-safe write-lock, but readers can get non-irqsafe
+ * read-locks.
+ */
+typedef struct {
+ volatile unsigned int lock;
+#ifdef CONFIG_DEBUG_SPINLOCK
+ unsigned magic;
+#endif
+} rwlock_t;
+
+#define RWLOCK_MAGIC 0xdeaf1eed
+
+#ifdef CONFIG_DEBUG_SPINLOCK
+#define RWLOCK_MAGIC_INIT , RWLOCK_MAGIC
+#else
+#define RWLOCK_MAGIC_INIT /* */
+#endif
+
+#define RW_LOCK_UNLOCKED (rwlock_t) { RW_LOCK_BIAS RWLOCK_MAGIC_INIT }
+
+#define rwlock_init(x) do { *(x) = RW_LOCK_UNLOCKED; } while(0)
+
+#define rwlock_is_locked(x) ((x)->lock != RW_LOCK_BIAS)
+
+/*
+ * On x86, we implement read-write locks as a 32-bit counter
+ * with the high bit (sign) being the "contended" bit.
+ *
+ * The inline assembly is non-obvious. Think about it.
+ *
+ * Changed to use the same technique as rw semaphores. See
+ * semaphore.h for details. -ben
+ */
+/* the spinlock helpers are in arch/i386/kernel/semaphore.c */
+
+static inline void _raw_read_lock(rwlock_t *rw)
+{
+#ifdef CONFIG_DEBUG_SPINLOCK
+ BUG_ON(rw->magic != RWLOCK_MAGIC);
+#endif
+ __build_read_lock(rw, "__read_lock_failed");
+}
+
+static inline void _raw_write_lock(rwlock_t *rw)
+{
+#ifdef CONFIG_DEBUG_SPINLOCK
+ BUG_ON(rw->magic != RWLOCK_MAGIC);
+#endif
+ __build_write_lock(rw, "__write_lock_failed");
+}
+
+#define _raw_read_unlock(rw) asm volatile("lock ; incl %0" :"=m" ((rw)->lock) : : "memory")
+#define _raw_write_unlock(rw) asm volatile("lock ; addl $" RW_LOCK_BIAS_STR ",%0":"=m" ((rw)->lock) : : "memory")
+
+static inline int _raw_write_trylock(rwlock_t *lock)
+{
+ atomic_t *count = (atomic_t *)lock;
+ if (atomic_sub_and_test(RW_LOCK_BIAS, count))
+ return 1;
+ atomic_add(RW_LOCK_BIAS, count);
+ return 0;
+}
+
+#endif /* __ASM_SPINLOCK_H */
diff --git a/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/system.h b/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/system.h
index b8eb62d37a..78f760df03 100644
--- a/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/system.h
+++ b/linux-2.6.10-xen-sparse/include/asm-xen/asm-i386/system.h
@@ -8,7 +8,6 @@
#include <asm/segment.h>
#include <asm/cpufeature.h>
#include <asm-xen/hypervisor.h>
-#include <asm-xen/evtchn.h>
#ifdef __KERNEL__
@@ -444,61 +443,67 @@ struct alt_instr {
/*
* The use of 'barrier' in the following reflects their use as local-lock
* operations. Reentrancy must be prevented (e.g., __cli()) /before/ following
- * critical operations are executed. All critical operatiosn must complete
+ * critical operations are executed. All critical operations must complete
* /before/ reentrancy is permitted (e.g., __sti()). Alpha architecture also
* includes these barriers, for example.
*/
#define __cli() \
do { \
- HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask = 1; \
+ vcpu_info_t *_vcpu; \
+ preempt_disable(); \
+ _vcpu = &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \
+ _vcpu->evtchn_upcall_mask = 1; \
+ preempt_enable_no_resched(); \
barrier(); \
} while (0)
#define __sti() \
do { \
- shared_info_t *_shared = HYPERVISOR_shared_info; \
+ vcpu_info_t *_vcpu; \
barrier(); \
- _shared->vcpu_data[0].evtchn_upcall_mask = 0; \
+ preempt_disable(); \
+ _vcpu = &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \
+ _vcpu->evtchn_upcall_mask = 0; \
barrier(); /* unmask then check (avoid races) */ \
- if ( unlikely(_shared->vcpu_data[0].evtchn_upcall_pending) ) \
- force_evtchn_callback(); \
+ if ( unlikely(_vcpu->evtchn_upcall_pending) ) \
+ force_evtchn_callback(); \
+ preempt_enable(); \
} while (0)
#define __save_flags(x) \
do { \
- (x) = HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask; \
+ vcpu_info_t *_vcpu; \
+ _vcpu = &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \
+ (x) = _vcpu->evtchn_upcall_mask; \
} while (0)
#define __restore_flags(x) \
do { \
- shared_info_t *_shared = HYPERVISOR_shared_info; \
+ vcpu_info_t *_vcpu; \
barrier(); \
- if ( (_shared->vcpu_data[0].evtchn_upcall_mask = (x)) == 0 ) { \
- barrier(); /* unmask then check (avoid races) */ \
- if ( unlikely(_shared->vcpu_data[0].evtchn_upcall_pending) ) \
- force_evtchn_callback(); \
- } \
+ preempt_disable(); \
+ _vcpu = &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \
+ if ((_vcpu->evtchn_upcall_mask = (x)) == 0) { \
+ barrier(); /* unmask then check (avoid races) */ \
+ if ( unlikely(_vcpu->evtchn_upcall_pending) ) \
+ force_evtchn_callback(); \
+ preempt_enable(); \
+ } else \
+ preempt_enable_no_resched(); \
} while (0)
-#define safe_halt() ((void)0)
+#define safe_halt() ((void)0)
#define __save_and_cli(x) \
do { \
- (x) = HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask; \
- HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask = 1; \
- barrier(); \
-} while (0)
-
-#define __save_and_sti(x) \
-do { \
- shared_info_t *_shared = HYPERVISOR_shared_info; \
+ vcpu_info_t *_vcpu; \
+ preempt_disable(); \
+ _vcpu = &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \
+ (x) = _vcpu->evtchn_upcall_mask; \
+ _vcpu->evtchn_upcall_mask = 1; \
+ preempt_enable_no_resched(); \
barrier(); \
- (x) = _shared->vcpu_data[0].evtchn_upcall_mask; \
- _shared->vcpu_data[0].evtchn_upcall_mask = 0; \
- barrier(); /* unmask then check (avoid races) */ \
- if ( unlikely(_shared->vcpu_data[0].evtchn_upcall_pending) ) \
- force_evtchn_callback(); \
} while (0)
#define local_irq_save(x) __save_and_cli(x)
@@ -507,7 +512,8 @@ do { \
#define local_irq_disable() __cli()
#define local_irq_enable() __sti()
-#define irqs_disabled() HYPERVISOR_shared_info->vcpu_data[0].evtchn_upcall_mask
+#define irqs_disabled() \
+ HYPERVISOR_shared_info->vcpu_data[smp_processor_id()].evtchn_upcall_mask
/*
* disable hlt during certain critical i/o operations
diff --git a/linux-2.6.10-xen-sparse/include/asm-xen/evtchn.h b/linux-2.6.10-xen-sparse/include/asm-xen/evtchn.h
index d6f0b0b545..59a7ba3991 100644
--- a/linux-2.6.10-xen-sparse/include/asm-xen/evtchn.h
+++ b/linux-2.6.10-xen-sparse/include/asm-xen/evtchn.h
@@ -36,14 +36,12 @@
#include <asm/ptrace.h>
#include <asm/synch_bitops.h>
#include <asm-xen/xen-public/event_channel.h>
+#include <linux/smp.h>
/*
* LOW-LEVEL DEFINITIONS
*/
-/* Force a proper event-channel callback from Xen. */
-void force_evtchn_callback(void);
-
/* Entry point for notifications into Linux subsystems. */
asmlinkage void evtchn_do_upcall(struct pt_regs *regs);
@@ -59,6 +57,7 @@ static inline void mask_evtchn(int port)
static inline void unmask_evtchn(int port)
{
shared_info_t *s = HYPERVISOR_shared_info;
+ vcpu_info_t *vcpu_info = &s->vcpu_data[smp_processor_id()];
synch_clear_bit(port, &s->evtchn_mask[0]);
@@ -67,10 +66,10 @@ static inline void unmask_evtchn(int port)
* a real IO-APIC we 'lose the interrupt edge' if the channel is masked.
*/
if ( synch_test_bit (port, &s->evtchn_pending[0]) &&
- !synch_test_and_set_bit(port>>5, &s->evtchn_pending_sel) )
+ !synch_test_and_set_bit(port>>5, &vcpu_info->evtchn_pending_sel) )
{
- s->vcpu_data[0].evtchn_upcall_pending = 1;
- if ( !s->vcpu_data[0].evtchn_upcall_mask )
+ vcpu_info->evtchn_upcall_pending = 1;
+ if ( !vcpu_info->evtchn_upcall_mask )
force_evtchn_callback();
}
}
diff --git a/linux-2.6.10-xen-sparse/include/asm-xen/hypervisor.h b/linux-2.6.10-xen-sparse/include/asm-xen/hypervisor.h
index ef755a4e7d..e54caa1b99 100644
--- a/linux-2.6.10-xen-sparse/include/asm-xen/hypervisor.h
+++ b/linux-2.6.10-xen-sparse/include/asm-xen/hypervisor.h
@@ -48,6 +48,10 @@ union xen_start_info_union
extern union xen_start_info_union xen_start_info_union;
#define xen_start_info (xen_start_info_union.xen_start_info)
+/* arch/xen/kernel/evtchn.c */
+/* Force a proper event-channel callback from Xen. */
+void force_evtchn_callback(void);
+
/* arch/xen/kernel/process.c */
void xen_cpu_idle (void);
@@ -63,8 +67,6 @@ void lgdt_finish(void);
* be MACHINE addresses.
*/
-extern unsigned int mmu_update_queue_idx;
-
void queue_l1_entry_update(pte_t *ptr, unsigned long val);
void queue_l2_entry_update(pmd_t *ptr, unsigned long val);
void queue_pt_switch(unsigned long ptr);
@@ -89,12 +91,28 @@ void xen_set_ldt(unsigned long ptr, unsigned long bytes);
void xen_machphys_update(unsigned long mfn, unsigned long pfn);
void _flush_page_update_queue(void);
-static inline int flush_page_update_queue(void)
-{
- unsigned int idx = mmu_update_queue_idx;
- if ( idx != 0 ) _flush_page_update_queue();
- return idx;
-}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+/*
+** XXX SMH: 2.4 doesn't have percpu.h (or support SMP guests) so just
+** include sufficient #defines to allow the below to build.
+*/
+#define DEFINE_PER_CPU(type, name) \
+ __typeof__(type) per_cpu__##name
+
+#define per_cpu(var, cpu) (*((void)cpu, &per_cpu__##var))
+#define __get_cpu_var(var) per_cpu__##var
+#define DECLARE_PER_CPU(type, name) extern __typeof__(type) per_cpu__##name
+
+#define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(per_cpu__##var)
+#define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(per_cpu__##var)
+#endif /* linux < 2.6.0 */
+
+#define flush_page_update_queue() do { \
+ DECLARE_PER_CPU(unsigned int, mmu_update_queue_idx); \
+ if (per_cpu(mmu_update_queue_idx, smp_processor_id())) \
+ _flush_page_update_queue(); \
+} while (0)
#define xen_flush_page_update_queue() (_flush_page_update_queue())
#define XEN_flush_page_update_queue() (_flush_page_update_queue())
void MULTICALL_flush_page_update_queue(void);
@@ -553,4 +571,20 @@ HYPERVISOR_vm_assist(
return ret;
}
+static inline int
+HYPERVISOR_boot_vcpu(
+ unsigned long vcpu, full_execution_context_t *ctxt)
+{
+ int ret;
+ unsigned long ign1, ign2;
+
+ __asm__ __volatile__ (
+ TRAP_INSTR
+ : "=a" (ret), "=b" (ign1), "=c" (ign2)
+ : "0" (__HYPERVISOR_boot_vcpu), "1" (vcpu), "2" (ctxt)
+ : "memory");
+
+ return ret;
+}
+
#endif /* __HYPERVISOR_H__ */
diff --git a/linux-2.6.10-xen-sparse/include/asm-xen/multicall.h b/linux-2.6.10-xen-sparse/include/asm-xen/multicall.h
index ca169b57b9..1f03675df0 100644
--- a/linux-2.6.10-xen-sparse/include/asm-xen/multicall.h
+++ b/linux-2.6.10-xen-sparse/include/asm-xen/multicall.h
@@ -30,78 +30,86 @@
#include <asm-xen/hypervisor.h>
-extern multicall_entry_t multicall_list[];
-extern int nr_multicall_ents;
+DECLARE_PER_CPU(multicall_entry_t, multicall_list[]);
+DECLARE_PER_CPU(int, nr_multicall_ents);
static inline void queue_multicall0(unsigned long op)
{
- int i = nr_multicall_ents;
- multicall_list[i].op = op;
- nr_multicall_ents = i+1;
+ int cpu = smp_processor_id();
+ int i = per_cpu(nr_multicall_ents, cpu);
+ per_cpu(multicall_list[i], cpu).op = op;
+ per_cpu(nr_multicall_ents, cpu) = i+1;
}
static inline void queue_multicall1(unsigned long op, unsigned long arg1)
{
- int i = nr_multicall_ents;
- multicall_list[i].op = op;
- multicall_list[i].args[0] = arg1;
- nr_multicall_ents = i+1;
+ int cpu = smp_processor_id();
+ int i = per_cpu(nr_multicall_ents, cpu);
+ per_cpu(multicall_list[i], cpu).op = op;
+ per_cpu(multicall_list[i], cpu).args[0] = arg1;
+ per_cpu(nr_multicall_ents, cpu) = i+1;
}
static inline void queue_multicall2(
unsigned long op, unsigned long arg1, unsigned long arg2)
{
- int i = nr_multicall_ents;
- multicall_list[i].op = op;
- multicall_list[i].args[0] = arg1;
- multicall_list[i].args[1] = arg2;
- nr_multicall_ents = i+1;
+ int cpu = smp_processor_id();
+ int i = per_cpu(nr_multicall_ents, cpu);
+ per_cpu(multicall_list[i], cpu).op = op;
+ per_cpu(multicall_list[i], cpu).args[0] = arg1;
+ per_cpu(multicall_list[i], cpu).args[1] = arg2;
+ per_cpu(nr_multicall_ents, cpu) = i+1;
}
static inline void queue_multicall3(
unsigned long op, unsigned long arg1, unsigned long arg2,
unsigned long arg3)
{
- int i = nr_multicall_ents;
- multicall_list[i].op = op;
- multicall_list[i].args[0] = arg1;
- multicall_list[i].args[1] = arg2;
- multicall_list[i].args[2] = arg3;
- nr_multicall_ents = i+1;
+ int cpu = smp_processor_id();
+ int i = per_cpu(nr_multicall_ents, cpu);
+ per_cpu(multicall_list[i], cpu).op = op;
+ per_cpu(multicall_list[i], cpu).args[0] = arg1;
+ per_cpu(multicall_list[i], cpu).args[1] = arg2;
+ per_cpu(multicall_list[i], cpu).args[2] = arg3;
+ per_cpu(nr_multicall_ents, cpu) = i+1;
}
static inline void queue_multicall4(
unsigned long op, unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4)
{
- int i = nr_multicall_ents;
- multicall_list[i].op = op;
- multicall_list[i].args[0] = arg1;
- multicall_list[i].args[1] = arg2;
- multicall_list[i].args[2] = arg3;
- multicall_list[i].args[3] = arg4;
- nr_multicall_ents = i+1;
+ int cpu = smp_processor_id();
+ int i = per_cpu(nr_multicall_ents, cpu);
+ per_cpu(multicall_list[i], cpu).op = op;
+ per_cpu(multicall_list[i], cpu).args[0] = arg1;
+ per_cpu(multicall_list[i], cpu).args[1] = arg2;
+ per_cpu(multicall_list[i], cpu).args[2] = arg3;
+ per_cpu(multicall_list[i], cpu).args[3] = arg4;
+ per_cpu(nr_multicall_ents, cpu) = i+1;
}
static inline void queue_multicall5(
unsigned long op, unsigned long arg1, unsigned long arg2,
unsigned long arg3, unsigned long arg4, unsigned long arg5)
{
- int i = nr_multicall_ents;
- multicall_list[i].op = op;
- multicall_list[i].args[0] = arg1;
- multicall_list[i].args[1] = arg2;
- multicall_list[i].args[2] = arg3;
- multicall_list[i].args[3] = arg4;
- multicall_list[i].args[4] = arg5;
- nr_multicall_ents = i+1;
+ int cpu = smp_processor_id();
+ int i = per_cpu(nr_multicall_ents, cpu);
+ per_cpu(multicall_list[i], cpu).op = op;
+ per_cpu(multicall_list[i], cpu).args[0] = arg1;
+ per_cpu(multicall_list[i], cpu).args[1] = arg2;
+ per_cpu(multicall_list[i], cpu).args[2] = arg3;
+ per_cpu(multicall_list[i], cpu).args[3] = arg4;
+ per_cpu(multicall_list[i], cpu).args[4] = arg5;
+ per_cpu(nr_multicall_ents, cpu) = i+1;
}
static inline void execute_multicall_list(void)
{
- if ( unlikely(nr_multicall_ents == 0) ) return;
- (void)HYPERVISOR_multicall(multicall_list, nr_multicall_ents);
- nr_multicall_ents = 0;
+ int cpu = smp_processor_id();
+ if ( unlikely(per_cpu(nr_multicall_ents, cpu) == 0) ) return;
+ (void)HYPERVISOR_multicall(&per_cpu(multicall_list[0], cpu),
+ per_cpu(nr_multicall_ents, cpu));
+ per_cpu(nr_multicall_ents, cpu) = 0;
}
#endif /* __MULTICALL_H__ */
diff --git a/netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c b/netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c
index 0f275484dd..6eb5331301 100644
--- a/netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c
+++ b/netbsd-2.0-xen-sparse/sys/arch/xen/xen/evtchn.c
@@ -80,7 +80,6 @@ static int irq_bindcount[NR_IRQS];
static int xen_die_handler(void *);
#endif
static int xen_debug_handler(void *);
-static int xen_misdirect_handler(void *);
void
events_default_setup()
@@ -111,10 +110,6 @@ init_events()
event_set_handler(irq, &xen_debug_handler, NULL, IPL_DEBUG);
hypervisor_enable_irq(irq);
- irq = bind_virq_to_irq(VIRQ_MISDIRECT);
- event_set_handler(irq, &xen_misdirect_handler, NULL, IPL_DIE);
- hypervisor_enable_irq(irq);
-
/* This needs to be done early, but after the IRQ subsystem is
* alive. */
ctrl_if_init();
@@ -370,13 +365,3 @@ xen_debug_handler(void *arg)
printf("debug event\n");
return 0;
}
-
-static int
-xen_misdirect_handler(void *arg)
-{
-#if 0
- char *msg = "misdirect\n";
- (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(msg), msg);
-#endif
- return 0;
-}
diff --git a/patches/linux-2.6.9/drm.patch b/patches/linux-2.6.9/drm.patch
deleted file mode 100644
index f39d5cb3d0..0000000000
--- a/patches/linux-2.6.9/drm.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -ur linux-2.6.9/drivers/char/drm/ati_pcigart.h linux-2.6.9-new/drivers/char/drm/ati_pcigart.h
---- linux-2.6.9/drivers/char/drm/ati_pcigart.h 2004-10-18 22:55:07.000000000 +0100
-+++ linux-2.6.9-new/drivers/char/drm/ati_pcigart.h 2004-11-28 19:42:41.000000000 +0000
-@@ -158,7 +158,7 @@
- ret = 1;
-
- #if defined(__i386__) || defined(__x86_64__)
-- asm volatile ( "wbinvd" ::: "memory" );
-+ wbinvd();
- #else
- mb();
- #endif
diff --git a/patches/linux-2.6.9/nettel.patch b/patches/linux-2.6.9/nettel.patch
deleted file mode 100644
index e8dd94a33a..0000000000
--- a/patches/linux-2.6.9/nettel.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-diff -ur linux-2.6.9/drivers/mtd/maps/nettel.c linux-2.6.9-new/drivers/mtd/maps/nettel.c
---- linux-2.6.9/drivers/mtd/maps/nettel.c 2004-10-18 22:53:44.000000000 +0100
-+++ linux-2.6.9-new/drivers/mtd/maps/nettel.c 2004-11-28 19:45:35.000000000 +0000
-@@ -270,7 +270,7 @@
- maxsize = AMD_WINDOW_MAXSIZE;
-
- *amdpar = SC520_PAR(SC520_PAR_BOOTCS, amdaddr, maxsize);
-- __asm__ ("wbinvd");
-+ wbinvd();
-
- nettel_amd_map.phys = amdaddr;
- nettel_amd_map.virt = (unsigned long)
-@@ -382,7 +382,7 @@
- */
- intel1addr = intel0addr + intel0size;
- *intel1par = SC520_PAR(intel1cs, intel1addr, maxsize);
-- __asm__ ("wbinvd");
-+ wbinvd();
-
- maxsize += intel0size;
-
-@@ -408,7 +408,7 @@
- intel1size = intel_mtd->size - intel0size;
- if (intel1size > 0) {
- *intel1par = SC520_PAR(intel1cs, intel1addr, intel1size);
-- __asm__ ("wbinvd");
-+ wbinvd();
- } else {
- *intel1par = 0;
- }
diff --git a/tools/Makefile b/tools/Makefile
index 907260707b..4e590fd30b 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -8,6 +8,8 @@ all:
$(MAKE) -C xentrace
$(MAKE) -C python
$(MAKE) -C xfrd
+ $(MAKE) -C xcs
+ $(MAKE) -C ioemu
install:
$(MAKE) -C check
@@ -19,6 +21,8 @@ install:
$(MAKE) -C python install
$(MAKE) -C xfrd install
$(MAKE) -C sv install
+ $(MAKE) -C xcs install
+ $(MAKE) -C ioemu install
clean:
$(MAKE) -C libxutil clean
@@ -28,4 +32,5 @@ clean:
$(MAKE) -C xentrace clean
$(MAKE) -C python clean
$(MAKE) -C xfrd clean
-
+ $(MAKE) -C xcs clean
+ $(MAKE) -C ioemu clean
diff --git a/tools/examples/Makefile b/tools/examples/Makefile
index 72c1f610eb..ae65b6748f 100644
--- a/tools/examples/Makefile
+++ b/tools/examples/Makefile
@@ -12,6 +12,9 @@ XEN_CONFIG_DIR = /etc/xen
XEN_CONFIGS = xend-config.sxp
XEN_CONFIGS += xmexample1
XEN_CONFIGS += xmexample2
+XEN_CONFIGS += xmexample.vmx
+XEN_CONFIGS += mem-map.sxp
+XEN_CONFIGS += bochsrc
# Xen script dir and scripts to go there.
XEN_SCRIPT_DIR = /etc/xen/scripts
diff --git a/tools/examples/bochsrc b/tools/examples/bochsrc
new file mode 100644
index 0000000000..907c78bae2
--- /dev/null
+++ b/tools/examples/bochsrc
@@ -0,0 +1,19 @@
+#megs: 32
+#romimage: file=$BXSHARE/BIOS-bochs-latest, address=0xf0000
+#vgaromimage: $BXSHARE/VGABIOS-lgpl-latest
+floppya: 1_44=a.img, status=inserted
+floppyb: 1_44=b.img, status=inserted
+#ata0-master: type=disk, path=minibootable.img, cylinders=900, heads=15, spt=17
+# if you don't use absolute paths below, bochs looks under the cwd of xend,
+# which is usually "/"
+ata0-master: type=disk, path=/tmp/min-fc2-i386.img, cylinders=800, heads=4, spt=32
+boot: c
+
+log: /tmp/bochsout.txt
+#debug: action=report
+info: action=report
+error: action=report
+panic: action=ask
+
+mouse: enabled=0
+ips: 1500000
diff --git a/tools/examples/mem-map.sxp b/tools/examples/mem-map.sxp
new file mode 100644
index 0000000000..246b49b92a
--- /dev/null
+++ b/tools/examples/mem-map.sxp
@@ -0,0 +1,10 @@
+(memmap
+ (0000000000000000 000000000009f800 "AddressRangeMemory" WB)
+ (000000000009f800 00000000000a0000 "AddressRangeReserved" UC)
+ (00000000000a0000 00000000000bffff "AddressRangeIO" UC)
+ (00000000000f0000 0000000000100000 "AddressRangeReserved" UC)
+ (0000000000100000 0000000008000000 "AddressRangeMemory" WB)
+ (0000000007fff000 0000000008000000 "AddressRangeShared" WB)
+ (0000000008000000 0000000008003000 "AddressRangeNVS" UC)
+ (0000000008003000 000000000800d000 "AddressRangeACPI" WB)
+ (00000000fec00000 0000000100000000 "AddressRangeIO" UC))
diff --git a/tools/examples/xmexample.vmx b/tools/examples/xmexample.vmx
new file mode 100644
index 0000000000..6e9039584b
--- /dev/null
+++ b/tools/examples/xmexample.vmx
@@ -0,0 +1,93 @@
+# -*- mode: python; -*-
+#============================================================================
+# Python configuration setup for 'xm create'.
+# This script sets the parameters used when a domain is created using 'xm create'.
+# You use a separate script for each domain you want to create, or
+# you can set the parameters for the domain on the xm command line.
+#============================================================================
+
+#----------------------------------------------------------------------------
+# Kernel image file.
+kernel = "/boot/vmlinuz-rhel3-static"
+
+# Optional ramdisk.
+#ramdisk = "/boot/initrd.gz"
+
+# The domain build function. Default is 'linux'.
+builder='vmx'
+#builder='linux'
+#builder='netbsd'
+
+# Initial memory allocation (in megabytes) for the new domain.
+memory = 128
+
+# A name for your domain. All domains must have different names.
+name = "ExampleVMXDomain"
+
+# Which CPU to start domain on?
+#cpu = -1 # leave to Xen to pick
+
+#----------------------------------------------------------------------------
+# Define network interfaces.
+
+# Number of network interfaces. Default is 1.
+#nics=1
+nics=0
+
+# Optionally define mac and/or bridge for the network interfaces.
+# Random MACs are assigned if not given.
+#vif = [ 'mac=aa:00:00:00:00:11, bridge=xen-br0' ]
+
+#----------------------------------------------------------------------------
+# Define the disk devices you want the domain to have access to, and
+# what you want them accessible as.
+# Each disk entry is of the form phy:UNAME,DEV,MODE
+# where UNAME is the device, DEV is the device name the domain will see,
+# and MODE is r for read-only, w for read-write.
+
+#disk = [ 'phy:hda1,hda1,r' ]
+
+#----------------------------------------------------------------------------
+# Set the kernel command line for the new domain.
+# You only need to define the IP parameters and hostname if the domain's
+# IP config doesn't, e.g. in ifcfg-eth0 or via DHCP.
+# You can use 'extra' to set the runlevel and custom environment
+# variables used by custom rc scripts (e.g. VMID=, usr= ).
+
+# Set if you want dhcp to allocate the IP address.
+#dhcp="dhcp"
+# Set netmask.
+#netmask=
+# Set default gateway.
+#gateway=
+# Set the hostname.
+#hostname= "vm%d" % vmid
+
+# Set root device.
+#root = "/dev/ram0"
+root = "/dev/hda1 ro"
+
+# Root device for nfs.
+#root = "/dev/nfs"
+# The nfs server.
+#nfs_server = '169.254.1.0'
+# Root directory on the nfs server.
+#nfs_root = '/full/path/to/root/directory'
+
+# Sets runlevel 4.
+extra = "1"
+
+#----------------------------------------------------------------------------
+# Set according to whether you want the domain restarted when it exits.
+# The default is 'onreboot', which restarts the domain when it shuts down
+# with exit code reboot.
+# Other values are 'always', and 'never'.
+
+#restart = 'onreboot'
+
+#============================================================================
+
+# New stuff
+memmap = '/etc/xen/mem-map.sxp'
+device_model = '/usr/sbin/device-model'
+device_config = '/etc/xen/bochsrc'
diff --git a/tools/examples/xmexample1 b/tools/examples/xmexample1
index cdf4b6c824..b7b7dd437c 100644
--- a/tools/examples/xmexample1
+++ b/tools/examples/xmexample1
@@ -25,6 +25,9 @@ name = "ExampleDomain"
# Which CPU to start domain on?
#cpu = -1 # leave to Xen to pick
+# Number of Virtual CPUS to use, default is 1
+#vcpus = 1
+
#----------------------------------------------------------------------------
# Define network interfaces.
diff --git a/tools/examples/xmexample2 b/tools/examples/xmexample2
index 61479ca5f0..07a80db366 100644
--- a/tools/examples/xmexample2
+++ b/tools/examples/xmexample2
@@ -55,6 +55,10 @@ name = "VM%d" % vmid
#cpu = -1 # leave to Xen to pick
cpu = vmid # set based on vmid (mod number of CPUs)
+# Number of Virtual CPUS to use, default is 1
+#vcpus = 1
+vcpus = 4 # make your domain a 4-way
+
#----------------------------------------------------------------------------
# Define network interfaces.
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..5b7b9c6f7a
--- /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 0
+
+// Experimental VGA on PCI
+#define BX_PCI_VGA_SUPPORT 1
+
+// limited USB on PCI
+#define BX_PCI_USB_SUPPORT 0
+
+#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..c35c35bf52
--- /dev/null
+++ b/tools/ioemu/include/pc_system.h
@@ -0,0 +1,199 @@
+/////////////////////////////////////////////////////////////////////////
+// $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
+
+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
+
+ // 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..17a85539ce
--- /dev/null
+++ b/tools/ioemu/iodev/cpu.cc
@@ -0,0 +1,317 @@
+/*
+ * 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);
+ }
+ }
+ }
+ }
+ 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) {
+ unsigned long t1, t2;
+
+ /* Wait up to one seconds. */
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000;
+ FD_SET(evtchn_fd, &rfds);
+
+ send_event = 0;
+ rdtscl(t1);
+ retval = select(evtchn_fd+1, &rfds, NULL, NULL, &tv);
+ rdtscl(t2);
+ if (retval == -1) {
+ perror("select");
+ return;
+ }
+ //stime_usec = 1000000 * (1 - tv.tv_sec) - tv.tv_usec;
+ if (t2 > t1)
+ BX_TICKN((t2 - t1) / 2000); // should match ips in bochsrc
+ else
+ BX_TICKN((MAXINT - t1 + t2) / 2000); // should match ips in bochsrc
+ 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_INFO(("%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..763b8b2f7b
--- /dev/null
+++ b/tools/ioemu/iodev/main.cc
@@ -0,0 +1,4066 @@
+/////////////////////////////////////////////////////////////////////////
+// $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[])
+{
+ 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..1b58fe775f
--- /dev/null
+++ b/tools/ioemu/iodev/pc_system.cc
@@ -0,0 +1,556 @@
+/////////////////////////////////////////////////////////////////////////
+// $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
+
+// 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
+
+ // 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..d79c376220
--- /dev/null
+++ b/tools/ioemu/iodev/pic.cc
@@ -0,0 +1,872 @@
+/////////////////////////////////////////////////////////////////////////
+// $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);
+}
+
+ 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..cfdb1263ef
--- /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);
+
+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..fc913b1334
--- /dev/null
+++ b/tools/ioemu/iodev/pit82c54.cc
@@ -0,0 +1,893 @@
+/////////////////////////////////////////////////////////////////////////
+// $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;
+ }
+
+ 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;
+ 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;
+ 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..bae2c2b8ac
--- /dev/null
+++ b/tools/ioemu/iodev/pit82c54.h
@@ -0,0 +1,134 @@
+/////////////////////////////////////////////////////////////////////////
+// $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"
+
+
+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);
+
+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..ae09b3e26b
--- /dev/null
+++ b/tools/ioemu/iodev/pit_wrap.cc
@@ -0,0 +1,438 @@
+////////////////////////////////////////////////////////////////////////
+// $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));
+ }
+
+ if ((BX_PIT_THIS s.timer.read_OUT(0))==1) {
+ DEV_pic_raise_irq(0);
+ } else {
+ DEV_pic_lower_irq(0);
+ }
+
+ 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) {
+ DEV_pic_raise_irq(0);
+ prev_timer0_out=1;
+ }
+ } else {
+ if ((BX_PIT_THIS s.timer.read_OUT(0))==0) {
+ DEV_pic_lower_irq(0);
+ 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..a69591dc1d
--- /dev/null
+++ b/tools/ioemu/memory/misc_mem.cc
@@ -0,0 +1,443 @@
+/////////////////////////////////////////////////////////////////////////
+// $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]);
+
+ /* Initialize shared page */
+ memset(shared_page, 0, PAGE_SIZE);
+}
+#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::
+
diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
index 770b400326..7ef744aa95 100644
--- a/tools/libxc/Makefile
+++ b/tools/libxc/Makefile
@@ -12,7 +12,7 @@ INSTALL_PROG = $(INSTALL) -m0755
INSTALL_DATA = $(INSTALL) -m0644
INSTALL_DIR = $(INSTALL) -d -m0755
-MAJOR = 2.0
+MAJOR = 3.0
MINOR = 0
CC = gcc
@@ -37,6 +37,7 @@ SRCS += xc_misc.c
SRCS += xc_physdev.c
SRCS += xc_private.c
SRCS += xc_rrobin.c
+SRCS += xc_vmx_build.c
CFLAGS += -Wall
CFLAGS += -Werror
diff --git a/tools/libxc/linux_boot_params.h b/tools/libxc/linux_boot_params.h
new file mode 100644
index 0000000000..9b0b25cef9
--- /dev/null
+++ b/tools/libxc/linux_boot_params.h
@@ -0,0 +1,165 @@
+#ifndef __LINUX_BOOT_PARAMS_H__
+#define __LINUX_BOOT_PARAMS_H__
+
+#include <asm/types.h>
+
+#define E820MAX 32
+
+struct mem_map {
+ int nr_map;
+ struct entry {
+ unsigned long long addr; /* start of memory segment */
+ unsigned long long size; /* size of memory segment */
+ unsigned long type; /* type of memory segment */
+#define E820_RAM 1
+#define E820_RESERVED 2
+#define E820_ACPI 3 /* usable as RAM once ACPI tables have been read */
+#define E820_NVS 4
+#define E820_IO 16
+#define E820_SHARED 17
+
+ unsigned long caching_attr; /* used by hypervisor */
+#define MEMMAP_UC 0
+#define MEMMAP_WC 1
+#define MEMMAP_WT 4
+#define MEMMAP_WP 5
+#define MEMMAP_WB 6
+
+ }map[E820MAX];
+};
+
+struct e820entry {
+ unsigned long long addr; /* start of memory segment */
+ unsigned long long size; /* size of memory segment */
+ unsigned long type; /* type of memory segment */
+};
+
+struct e820map {
+ int nr_map;
+ struct e820entry map[E820MAX];
+};
+
+struct drive_info_struct { __u8 dummy[32]; };
+
+struct sys_desc_table {
+ __u16 length;
+ __u8 table[318];
+};
+
+struct screen_info {
+ unsigned char orig_x; /* 0x00 */
+ unsigned char orig_y; /* 0x01 */
+ unsigned short dontuse1; /* 0x02 -- EXT_MEM_K sits here */
+ unsigned short orig_video_page; /* 0x04 */
+ unsigned char orig_video_mode; /* 0x06 */
+ unsigned char orig_video_cols; /* 0x07 */
+ unsigned short unused2; /* 0x08 */
+ unsigned short orig_video_ega_bx; /* 0x0a */
+ unsigned short unused3; /* 0x0c */
+ unsigned char orig_video_lines; /* 0x0e */
+ unsigned char orig_video_isVGA; /* 0x0f */
+ unsigned short orig_video_points; /* 0x10 */
+
+ /* VESA graphic mode -- linear frame buffer */
+ unsigned short lfb_width; /* 0x12 */
+ unsigned short lfb_height; /* 0x14 */
+ unsigned short lfb_depth; /* 0x16 */
+ unsigned long lfb_base; /* 0x18 */
+ unsigned long lfb_size; /* 0x1c */
+ unsigned short dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */
+ unsigned short lfb_linelength; /* 0x24 */
+ unsigned char red_size; /* 0x26 */
+ unsigned char red_pos; /* 0x27 */
+ unsigned char green_size; /* 0x28 */
+ unsigned char green_pos; /* 0x29 */
+ unsigned char blue_size; /* 0x2a */
+ unsigned char blue_pos; /* 0x2b */
+ unsigned char rsvd_size; /* 0x2c */
+ unsigned char rsvd_pos; /* 0x2d */
+ unsigned short vesapm_seg; /* 0x2e */
+ unsigned short vesapm_off; /* 0x30 */
+ unsigned short pages; /* 0x32 */
+ /* 0x34 -- 0x3f reserved for future expansion */
+};
+
+struct screen_info_overlap {
+ __u8 reserved1[2]; /* 0x00 */
+ __u16 ext_mem_k; /* 0x02 */
+ __u8 reserved2[0x20 - 0x04]; /* 0x04 */
+ __u16 cl_magic; /* 0x20 */
+#define CL_MAGIC_VALUE 0xA33F
+ __u16 cl_offset; /* 0x22 */
+ __u8 reserved3[0x40 - 0x24]; /* 0x24 */
+};
+
+
+struct apm_bios_info {
+ __u16 version;
+ __u16 cseg;
+ __u32 offset;
+ __u16 cseg_16;
+ __u16 dseg;
+ __u16 flags;
+ __u16 cseg_len;
+ __u16 cseg_16_len;
+ __u16 dseg_len;
+};
+
+struct linux_boot_params {
+ union { /* 0x00 */
+ struct screen_info info;
+ struct screen_info_overlap overlap;
+ } screen;
+
+ struct apm_bios_info apm_bios_info; /* 0x40 */
+ __u8 reserved4[0x80 - 0x54]; /* 0x54 */
+ struct drive_info_struct drive_info; /* 0x80 */
+ struct sys_desc_table sys_desc_table; /* 0xa0 */
+ __u32 alt_mem_k; /* 0x1e0 */
+ __u8 reserved5[4]; /* 0x1e4 */
+ __u8 e820_map_nr; /* 0x1e8 */
+ __u8 reserved6[8]; /* 0x1e9 */
+ __u8 setup_sects; /* 0x1f1 */
+ __u16 mount_root_rdonly; /* 0x1f2 */
+ __u16 syssize; /* 0x1f4 */
+ __u16 swapdev; /* 0x1f6 */
+ __u16 ramdisk_flags; /* 0x1f8 */
+#define RAMDISK_IMAGE_START_MASK 0x07FF
+#define RAMDISK_PROMPT_FLAG 0x8000
+#define RAMDISK_LOAD_FLAG 0x4000
+ __u16 vid_mode; /* 0x1fa */
+ __u16 root_dev; /* 0x1fc */
+ __u8 reserved9[1]; /* 0x1fe */
+ __u8 aux_device_info; /* 0x1ff */
+ /* 2.00+ */
+ __u8 reserved10[2]; /* 0x200 */
+ __u8 header_magic[4]; /* 0x202 */
+ __u16 protocol_version; /* 0x206 */
+ __u8 reserved11[8]; /* 0x208 */
+ __u8 loader_type; /* 0x210 */
+#define LOADER_TYPE_LOADLIN 1
+#define LOADER_TYPE_BOOTSECT_LOADER 2
+#define LOADER_TYPE_SYSLINUX 3
+#define LOADER_TYPE_ETHERBOOT 4
+#define LOADER_TYPE_UNKNOWN 0xFF
+ __u8 loader_flags; /* 0x211 */
+ __u8 reserved12[2]; /* 0x212 */
+ __u32 code32_start; /* 0x214 */
+ __u32 initrd_start; /* 0x218 */
+ __u32 initrd_size; /* 0x21c */
+ __u8 reserved13[4]; /* 0x220 */
+ /* 2.01+ */
+ __u16 heap_end_ptr; /* 0x224 */
+ __u8 reserved14[2]; /* 0x226 */
+ /* 2.02+ */
+ __u32 cmd_line_ptr; /* 0x228 */
+ /* 2.03+ */
+ __u32 ramdisk_max; /* 0x22c */
+ __u8 reserved15[0x2d0 - 0x230]; /* 0x230 */
+ struct e820entry e820_map[E820MAX]; /* 0x2d0 */
+ __u64 shared_info; /* 0x550 */
+ __u8 padding[0x800 - 0x558]; /* 0x558 */
+ __u8 cmd_line[0x800]; /* 0x800 */
+} __attribute__((packed));
+
+#endif /* __LINUX_BOOT_PARAMS_H__ */
diff --git a/tools/libxc/xc.h b/tools/libxc/xc.h
index c4440d9838..81d7b2ed3f 100644
--- a/tools/libxc/xc.h
+++ b/tools/libxc/xc.h
@@ -10,6 +10,7 @@
#define __XC_H__
#include <stdint.h>
+
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
@@ -23,7 +24,6 @@ typedef int64_t s64;
#include <xen/dom0_ops.h>
#include <xen/event_channel.h>
#include <xen/sched_ctl.h>
-#include <xen/io/domain_controller.h>
/*\
* INITIALIZATION FUNCTIONS
@@ -142,13 +142,15 @@ int xc_domain_getinfo(int xc_handle,
*/
int xc_domain_getfullinfo(int xc_handle,
u32 domid,
+ u32 vcpu,
xc_domaininfo_t *info,
full_execution_context_t *ctxt);
int xc_domain_setcpuweight(int xc_handle,
u32 domid,
float weight);
long long xc_domain_get_cpu_usage(int xc_handle,
- domid_t domid);
+ domid_t domid,
+ int vcpu);
typedef dom0_shadow_control_stats_t xc_shadow_control_stats_t;
@@ -195,7 +197,8 @@ int xc_linux_build(int xc_handle,
const char *ramdisk_name,
const char *cmdline,
unsigned int control_evtchn,
- unsigned long flags);
+ unsigned long flags,
+ unsigned int vcpus);
int
xc_plan9_build (int xc_handle,
@@ -205,6 +208,17 @@ xc_plan9_build (int xc_handle,
unsigned int control_evtchn,
unsigned long flags);
+struct mem_map;
+int xc_vmx_build(int xc_handle,
+ u32 domid,
+ int memsize,
+ const char *image_name,
+ struct mem_map *memmap,
+ const char *ramdisk_name,
+ const char *cmdline,
+ unsigned int control_evtchn,
+ unsigned long flags);
+
int xc_bvtsched_global_set(int xc_handle,
unsigned long ctx_allow);
@@ -378,4 +392,7 @@ void *xc_map_foreign_range(int xc_handle, u32 dom,
void *xc_map_foreign_batch(int xc_handle, u32 dom, int prot,
unsigned long *arr, int num );
+int xc_get_pfn_list(int xc_handle, u32 domid, unsigned long *pfn_buf,
+ unsigned long max_pfns);
+
#endif /* __XC_H__ */
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index 67168910e9..7104ea1a48 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -69,6 +69,7 @@ int xc_domain_pincpu(int xc_handle,
dom0_op_t op;
op.cmd = DOM0_PINCPUDOMAIN;
op.u.pincpudomain.domain = (domid_t)domid;
+ op.u.pincpudomain.exec_domain = 0;
op.u.pincpudomain.cpu = cpu;
return do_dom0_op(xc_handle, &op);
}
@@ -87,6 +88,7 @@ int xc_domain_getinfo(int xc_handle,
{
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t)next_domid;
+ op.u.getdomaininfo.exec_domain = 0; // FIX ME?!?
op.u.getdomaininfo.ctxt = NULL; /* no exec context info, thanks. */
if ( do_dom0_op(xc_handle, &op) < 0 )
break;
@@ -120,6 +122,7 @@ int xc_domain_getinfo(int xc_handle,
int xc_domain_getfullinfo(int xc_handle,
u32 domid,
+ u32 vcpu,
xc_domaininfo_t *info,
full_execution_context_t *ctxt)
{
@@ -128,6 +131,7 @@ int xc_domain_getfullinfo(int xc_handle,
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.exec_domain = (u16)vcpu;
op.u.getdomaininfo.ctxt = ctxt;
rc = do_dom0_op(xc_handle, &op);
diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c
index cc4c0f4561..dd903751a9 100644
--- a/tools/libxc/xc_linux_build.c
+++ b/tools/libxc/xc_linux_build.c
@@ -41,52 +41,6 @@ loadelfsymtab(
char *elfbase, int xch, u32 dom, unsigned long *parray,
struct domain_setup_info *dsi);
-static long get_tot_pages(int xc_handle, u32 domid)
-{
- dom0_op_t op;
- op.cmd = DOM0_GETDOMAININFO;
- op.u.getdomaininfo.domain = (domid_t)domid;
- op.u.getdomaininfo.ctxt = NULL;
- return (do_dom0_op(xc_handle, &op) < 0) ?
- -1 : op.u.getdomaininfo.tot_pages;
-}
-
-static int get_pfn_list(int xc_handle,
- u32 domid,
- unsigned long *pfn_buf,
- unsigned long max_pfns)
-{
- dom0_op_t op;
- int ret;
- op.cmd = DOM0_GETMEMLIST;
- op.u.getmemlist.domain = (domid_t)domid;
- op.u.getmemlist.max_pfns = max_pfns;
- op.u.getmemlist.buffer = pfn_buf;
-
- if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
- return -1;
-
- ret = do_dom0_op(xc_handle, &op);
-
- (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
-
- return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
-}
-
-static int copy_to_domain_page(int xc_handle,
- u32 domid,
- unsigned long dst_pfn,
- void *src_page)
-{
- void *vaddr = xc_map_foreign_range(
- xc_handle, domid, PAGE_SIZE, PROT_WRITE, dst_pfn);
- if ( vaddr == NULL )
- return -1;
- memcpy(vaddr, src_page, PAGE_SIZE);
- munmap(vaddr, PAGE_SIZE);
- return 0;
-}
-
static int setup_guestos(int xc_handle,
u32 dom,
char *image, unsigned long image_size,
@@ -97,7 +51,8 @@ static int setup_guestos(int xc_handle,
const char *cmdline,
unsigned long shared_info_frame,
unsigned int control_evtchn,
- unsigned long flags)
+ unsigned long flags,
+ unsigned int vcpus)
{
l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
l2_pgentry_t *vl2tab=NULL, *vl2e=NULL;
@@ -204,7 +159,7 @@ static int setup_guestos(int xc_handle,
goto error_out;
}
- if ( get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages )
+ if ( xc_get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages )
{
PERROR("Could not get the page frame list");
goto error_out;
@@ -227,7 +182,7 @@ static int setup_guestos(int xc_handle,
PERROR("Error reading initrd image, could not");
goto error_out;
}
- copy_to_domain_page(xc_handle, dom,
+ xc_copy_to_domain_page(xc_handle, dom,
page_array[i>>PAGE_SHIFT], page);
}
}
@@ -335,6 +290,10 @@ static int setup_guestos(int xc_handle,
/* Mask all upcalls... */
for ( i = 0; i < MAX_VIRT_CPUS; i++ )
shared_info->vcpu_data[i].evtchn_upcall_mask = 1;
+
+ shared_info->n_vcpu = vcpus;
+ printf(" VCPUS: %d\n", shared_info->n_vcpu);
+
munmap(shared_info, PAGE_SIZE);
/* Send the page update requests down to the hypervisor. */
@@ -357,76 +316,14 @@ static int setup_guestos(int xc_handle,
return -1;
}
-static unsigned long get_filesz(int fd)
-{
- u16 sig;
- u32 _sz = 0;
- unsigned long sz;
-
- lseek(fd, 0, SEEK_SET);
- read(fd, &sig, sizeof(sig));
- sz = lseek(fd, 0, SEEK_END);
- if ( sig == 0x8b1f ) /* GZIP signature? */
- {
- lseek(fd, -4, SEEK_END);
- read(fd, &_sz, 4);
- sz = _sz;
- }
- lseek(fd, 0, SEEK_SET);
-
- return sz;
-}
-
-static char *read_kernel_image(const char *filename, unsigned long *size)
-{
- int kernel_fd = -1;
- gzFile kernel_gfd = NULL;
- char *image = NULL;
- unsigned int bytes;
-
- if ( (kernel_fd = open(filename, O_RDONLY)) < 0 )
- {
- PERROR("Could not open kernel image");
- goto out;
- }
-
- *size = get_filesz(kernel_fd);
-
- if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
- {
- PERROR("Could not allocate decompression state for state file");
- goto out;
- }
-
- if ( (image = malloc(*size)) == NULL )
- {
- PERROR("Could not allocate memory for kernel image");
- goto out;
- }
-
- if ( (bytes = gzread(kernel_gfd, image, *size)) != *size )
- {
- PERROR("Error reading kernel image, could not"
- " read the whole image (%d != %ld).", bytes, *size);
- free(image);
- image = NULL;
- }
-
- out:
- if ( kernel_gfd != NULL )
- gzclose(kernel_gfd);
- else if ( kernel_fd >= 0 )
- close(kernel_fd);
- return image;
-}
-
int xc_linux_build(int xc_handle,
u32 domid,
const char *image_name,
const char *ramdisk_name,
const char *cmdline,
unsigned int control_evtchn,
- unsigned long flags)
+ unsigned long flags,
+ unsigned int vcpus)
{
dom0_op_t launch_op, op;
int initrd_fd = -1;
@@ -438,13 +335,13 @@ int xc_linux_build(int xc_handle,
unsigned long image_size, initrd_size=0;
unsigned long vstartinfo_start, vkern_entry;
- if ( (nr_pages = get_tot_pages(xc_handle, domid)) < 0 )
+ if ( (nr_pages = xc_get_tot_pages(xc_handle, domid)) < 0 )
{
PERROR("Could not find total pages for domain");
goto error_out;
}
- if ( (image = read_kernel_image(image_name, &image_size)) == NULL )
+ if ( (image = xc_read_kernel_image(image_name, &image_size)) == NULL )
goto error_out;
if ( (ramdisk_name != NULL) && (strlen(ramdisk_name) != 0) )
@@ -455,7 +352,7 @@ int xc_linux_build(int xc_handle,
goto error_out;
}
- initrd_size = get_filesz(initrd_fd);
+ initrd_size = xc_get_filesz(initrd_fd);
if ( (initrd_gfd = gzdopen(initrd_fd, "rb")) == NULL )
{
@@ -472,6 +369,7 @@ int xc_linux_build(int xc_handle,
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.exec_domain = 0;
op.u.getdomaininfo.ctxt = ctxt;
if ( (do_dom0_op(xc_handle, &op) < 0) ||
((u16)op.u.getdomaininfo.domain != domid) )
@@ -491,7 +389,7 @@ int xc_linux_build(int xc_handle,
&vstartinfo_start, &vkern_entry,
ctxt, cmdline,
op.u.getdomaininfo.shared_info_frame,
- control_evtchn, flags) < 0 )
+ control_evtchn, flags, vcpus) < 0 )
{
ERROR("Error constructing guest OS");
goto error_out;
@@ -740,27 +638,6 @@ loadelfimage(
return 0;
}
-static void
-map_memcpy(
- unsigned long dst, char *src, unsigned long size,
- int xch, u32 dom, unsigned long *parray, unsigned long vstart)
-{
- char *va;
- unsigned long chunksz, done, pa;
-
- for ( done = 0; done < size; done += chunksz )
- {
- pa = dst + done - vstart;
- va = xc_map_foreign_range(
- xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
- chunksz = size - done;
- if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
- chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
- memcpy(va + (pa & (PAGE_SIZE-1)), src + done, chunksz);
- munmap(va, PAGE_SIZE);
- }
-}
-
#define ELFROUND (ELFSIZE / 8)
static int
@@ -811,7 +688,7 @@ loadelfsymtab(
(shdr[h].sh_type == SHT_SYMTAB) )
{
if ( parray != NULL )
- map_memcpy(maxva, elfbase + shdr[h].sh_offset, shdr[h].sh_size,
+ xc_map_memcpy(maxva, elfbase + shdr[h].sh_offset, shdr[h].sh_size,
xch, dom, parray, dsi->v_start);
/* Mangled to be based on ELF header location. */
@@ -843,7 +720,7 @@ loadelfsymtab(
sym_ehdr->e_shstrndx = SHN_UNDEF;
/* Copy total length, crafted ELF header and section header table */
- map_memcpy(symva, p, sizeof(int) + sizeof(Elf_Ehdr) +
+ xc_map_memcpy(symva, p, sizeof(int) + sizeof(Elf_Ehdr) +
ehdr->e_shnum * sizeof(Elf_Shdr), xch, dom, parray,
dsi->v_start);
}
diff --git a/tools/libxc/xc_linux_restore.c b/tools/libxc/xc_linux_restore.c
index 1db39317de..8909878f81 100644
--- a/tools/libxc/xc_linux_restore.c
+++ b/tools/libxc/xc_linux_restore.c
@@ -19,31 +19,6 @@
#define DPRINTF(_f, _a...) ((void)0)
#endif
-static int get_pfn_list(int xc_handle,
- u32 domain_id,
- unsigned long *pfn_buf,
- unsigned long max_pfns)
-{
- dom0_op_t op;
- int ret;
- op.cmd = DOM0_GETMEMLIST;
- op.u.getmemlist.domain = (domid_t)domain_id;
- op.u.getmemlist.max_pfns = max_pfns;
- op.u.getmemlist.buffer = pfn_buf;
-
- if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
- {
- PERROR("Could not lock pfn list buffer");
- return -1;
- }
-
- ret = do_dom0_op(xc_handle, &op);
-
- (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
-
- return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
-}
-
/** Read the vmconfig string from the state input.
* It is stored as a 4-byte count 'n' followed by n bytes.
* The config data is stored in a new string in 'ioctxt->vmconfig',
@@ -94,7 +69,8 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt)
/* The new domain's shared-info frame number. */
unsigned long shared_info_frame;
- unsigned char shared_info[PAGE_SIZE]; /* saved contents from file */
+ unsigned char shared_info_page[PAGE_SIZE]; /* saved contents from file */
+ shared_info_t *shared_info = (shared_info_t *)shared_info_page;
/* A copy of the CPU context of the guest. */
full_execution_context_t ctxt;
@@ -201,6 +177,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt)
/* Get the domain's shared-info frame. */
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t)dom;
+ op.u.getdomaininfo.exec_domain = 0;
op.u.getdomaininfo.ctxt = NULL;
if ( do_dom0_op(xc_handle, &op) < 0 )
{
@@ -219,7 +196,7 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt)
}
/* Build the pfn-to-mfn table. We choose MFN ordering returned by Xen. */
- if ( get_pfn_list(xc_handle, dom, pfn_to_mfn_table, nr_pfns) != nr_pfns )
+ if ( xc_get_pfn_list(xc_handle, dom, pfn_to_mfn_table, nr_pfns) != nr_pfns )
{
xcio_error(ioctxt, "Did not read correct number of frame "
"numbers for new dom");
@@ -525,8 +502,8 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt)
}
}
- if ( xcio_read(ioctxt, &ctxt, sizeof(ctxt)) ||
- xcio_read(ioctxt, shared_info, PAGE_SIZE) )
+ if ( xcio_read(ioctxt, &ctxt, sizeof(ctxt)) ||
+ xcio_read(ioctxt, shared_info_page, PAGE_SIZE) )
{
xcio_error(ioctxt, "Error when reading from state file");
goto out;
@@ -577,9 +554,10 @@ int xc_linux_restore(int xc_handle, XcIOContext *ioctxt)
ctxt.pt_base = pfn_to_mfn_table[pfn] << PAGE_SHIFT;
/* clear any pending events and the selector */
- memset(&(((shared_info_t *)shared_info)->evtchn_pending[0]),
- 0, sizeof (((shared_info_t *)shared_info)->evtchn_pending)+
- sizeof(((shared_info_t *)shared_info)->evtchn_pending_sel));
+ memset(&(shared_info->evtchn_pending[0]), 0,
+ sizeof (shared_info->evtchn_pending));
+ for ( i = 0; i < MAX_VIRT_CPUS; i++ )
+ shared_info->vcpu_data[i].evtchn_pending_sel = 0;
/* Copy saved contents of shared-info page. No checking needed. */
ppage = xc_map_foreign_range(
diff --git a/tools/libxc/xc_linux_save.c b/tools/libxc/xc_linux_save.c
index 6d877c84f0..9d07efe158 100644
--- a/tools/libxc/xc_linux_save.c
+++ b/tools/libxc/xc_linux_save.c
@@ -10,6 +10,7 @@
#include <sys/time.h>
#include "xc_private.h"
#include <xen/linux/suspend.h>
+#include <xen/io/domain_controller.h>
#include <time.h>
#define BATCH_SIZE 1024 /* 1024 pages (4MB) at a time */
@@ -231,8 +232,8 @@ static int print_stats( int xc_handle, u32 domid,
gettimeofday(&wall_now, NULL);
- d0_cpu_now = xc_domain_get_cpu_usage( xc_handle, 0 )/1000;
- d1_cpu_now = xc_domain_get_cpu_usage( xc_handle, domid )/1000;
+ d0_cpu_now = xc_domain_get_cpu_usage( xc_handle, 0, /* FIXME */ 0 )/1000;
+ d1_cpu_now = xc_domain_get_cpu_usage( xc_handle, domid, /* FIXME */ 0 )/1000;
if ( (d0_cpu_now == -1) || (d1_cpu_now == -1) )
printf("ARRHHH!!\n");
@@ -330,7 +331,7 @@ int suspend_and_state(int xc_handle, XcIOContext *ioctxt,
retry:
- if ( xc_domain_getfullinfo(xc_handle, ioctxt->domain, info, ctxt) )
+ if ( xc_domain_getfullinfo(xc_handle, ioctxt->domain, /* FIXME */ 0, info, ctxt) )
{
xcio_error(ioctxt, "Could not get full domain info");
return -1;
@@ -443,7 +444,7 @@ int xc_linux_save(int xc_handle, XcIOContext *ioctxt)
return 1;
}
- if ( xc_domain_getfullinfo( xc_handle, domid, &info, &ctxt) )
+ if ( xc_domain_getfullinfo( xc_handle, domid, /* FIXME */ 0, &info, &ctxt) )
{
xcio_error(ioctxt, "Could not get full domain info");
goto out;
diff --git a/tools/libxc/xc_plan9_build.c b/tools/libxc/xc_plan9_build.c
index 33c9a54914..f319809716 100755
--- a/tools/libxc/xc_plan9_build.c
+++ b/tools/libxc/xc_plan9_build.c
@@ -132,52 +132,6 @@ static int
#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
-static long
-get_tot_pages(int xc_handle, u32 domid)
-{
- dom0_op_t op;
- op.cmd = DOM0_GETDOMAININFO;
- op.u.getdomaininfo.domain = (domid_t) domid;
- op.u.getdomaininfo.ctxt = NULL;
- return (do_dom0_op(xc_handle, &op) < 0) ?
- -1 : op.u.getdomaininfo.tot_pages;
-}
-
-static int
-get_pfn_list(int xc_handle,
- u32 domid, unsigned long *pfn_buf, unsigned long max_pfns)
-{
- dom0_op_t op;
- int ret;
- op.cmd = DOM0_GETMEMLIST;
- op.u.getmemlist.domain = (domid_t) domid;
- op.u.getmemlist.max_pfns = max_pfns;
- op.u.getmemlist.buffer = pfn_buf;
-
- if (mlock(pfn_buf, max_pfns * sizeof (unsigned long)) != 0)
- return -1;
-
- ret = do_dom0_op(xc_handle, &op);
-
- (void) munlock(pfn_buf, max_pfns * sizeof (unsigned long));
-
-#if 0
-#ifdef DEBUG
- DPRINTF(("Ret for get_pfn_list is %d\n", ret));
- if (ret >= 0) {
- int i, j;
- for (i = 0; i < op.u.getmemlist.num_pfns; i += 16) {
- fprintf(stderr, "0x%x: ", i);
- for (j = 0; j < 16; j++)
- fprintf(stderr, "0x%lx ", pfn_buf[i + j]);
- fprintf(stderr, "\n");
- }
- }
-#endif
-#endif
- return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
-}
-
static int
setup_guestos(int xc_handle,
u32 dom,
@@ -216,7 +170,7 @@ setup_guestos(int xc_handle,
goto error_out;
}
- if (get_pfn_list(xc_handle, dom, cpage_array, tot_pages) != tot_pages) {
+ if (xc_get_pfn_list(xc_handle, dom, cpage_array, tot_pages) != tot_pages) {
PERROR("Could not get the page frame list");
goto error_out;
}
@@ -487,11 +441,11 @@ xc_plan9_build(int xc_handle,
full_execution_context_t st_ctxt, *ctxt = &st_ctxt;
unsigned long virt_startinfo_addr;
- if ((tot_pages = get_tot_pages(xc_handle, domid)) < 0) {
+ if ((tot_pages = xc_get_tot_pages(xc_handle, domid)) < 0) {
PERROR("Could not find total pages for domain");
return 1;
}
- DPRINTF(("get_tot_pages returns %ld pages\n", tot_pages));
+ DPRINTF(("xc_get_tot_pages returns %ld pages\n", tot_pages));
kernel_fd = open(image_name, O_RDONLY);
if (kernel_fd < 0) {
@@ -505,7 +459,7 @@ xc_plan9_build(int xc_handle,
return 1;
}
- DPRINTF(("get_tot_pages returns %ld pages\n", tot_pages));
+ DPRINTF(("xc_get_tot_pages returns %ld pages\n", tot_pages));
if (mlock(&st_ctxt, sizeof (st_ctxt))) {
PERROR("Unable to mlock ctxt");
return 1;
@@ -513,13 +467,14 @@ xc_plan9_build(int xc_handle,
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t) domid;
+ op.u.getdomaininfo.exec_domain = 0;
op.u.getdomaininfo.ctxt = ctxt;
if ((do_dom0_op(xc_handle, &op) < 0) ||
((u32) op.u.getdomaininfo.domain != domid)) {
PERROR("Could not get info on domain");
goto error_out;
}
- DPRINTF(("get_tot_pages returns %ld pages\n", tot_pages));
+ DPRINTF(("xc_get_tot_pages returns %ld pages\n", tot_pages));
if (!(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED)
|| (op.u.getdomaininfo.ctxt->pt_base != 0)) {
@@ -527,7 +482,7 @@ xc_plan9_build(int xc_handle,
goto error_out;
}
- DPRINTF(("get_tot_pages returns %ld pages\n", tot_pages));
+ DPRINTF(("xc_get_tot_pages returns %ld pages\n", tot_pages));
if (setup_guestos(xc_handle, domid, kernel_gfd, tot_pages,
&virt_startinfo_addr,
&load_addr, &st_ctxt, cmdline,
diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c
index e4316e6994..65aa1085e0 100644
--- a/tools/libxc/xc_private.c
+++ b/tools/libxc/xc_private.c
@@ -4,6 +4,7 @@
* Helper functions for the rest of the library.
*/
+#include <zlib.h>
#include "xc_private.h"
void *xc_map_foreign_batch(int xc_handle, u32 dom, int prot,
@@ -159,12 +160,13 @@ int finish_mmu_updates(int xc_handle, mmu_t *mmu)
}
-long long xc_domain_get_cpu_usage( int xc_handle, domid_t domid )
+long long xc_domain_get_cpu_usage( int xc_handle, domid_t domid, int vcpu )
{
dom0_op_t op;
op.cmd = DOM0_GETDOMAININFO;
op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.exec_domain = (u16)vcpu;
op.u.getdomaininfo.ctxt = NULL;
if ( (do_dom0_op(xc_handle, &op) < 0) ||
((u16)op.u.getdomaininfo.domain != domid) )
@@ -201,5 +203,151 @@ unsigned long xc_get_m2p_start_mfn ( int xc_handle )
return mfn;
}
+int xc_get_pfn_list(int xc_handle,
+ u32 domid,
+ unsigned long *pfn_buf,
+ unsigned long max_pfns)
+{
+ dom0_op_t op;
+ int ret;
+ op.cmd = DOM0_GETMEMLIST;
+ op.u.getmemlist.domain = (domid_t)domid;
+ op.u.getmemlist.max_pfns = max_pfns;
+ op.u.getmemlist.buffer = pfn_buf;
+
+
+ if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
+ {
+ PERROR("Could not lock pfn list buffer");
+ return -1;
+ }
+
+ ret = do_dom0_op(xc_handle, &op);
+
+ (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
+
+#if 0
+#ifdef DEBUG
+ DPRINTF(("Ret for xc_get_pfn_list is %d\n", ret));
+ if (ret >= 0) {
+ int i, j;
+ for (i = 0; i < op.u.getmemlist.num_pfns; i += 16) {
+ fprintf(stderr, "0x%x: ", i);
+ for (j = 0; j < 16; j++)
+ fprintf(stderr, "0x%lx ", pfn_buf[i + j]);
+ fprintf(stderr, "\n");
+ }
+ }
+#endif
+#endif
+
+ return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
+}
+
+long xc_get_tot_pages(int xc_handle, u32 domid)
+{
+ dom0_op_t op;
+ op.cmd = DOM0_GETDOMAININFO;
+ op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.exec_domain = 0;
+ op.u.getdomaininfo.ctxt = NULL;
+ return (do_dom0_op(xc_handle, &op) < 0) ?
+ -1 : op.u.getdomaininfo.tot_pages;
+}
+
+int xc_copy_to_domain_page(int xc_handle,
+ u32 domid,
+ unsigned long dst_pfn,
+ void *src_page)
+{
+ void *vaddr = xc_map_foreign_range(
+ xc_handle, domid, PAGE_SIZE, PROT_WRITE, dst_pfn);
+ if ( vaddr == NULL )
+ return -1;
+ memcpy(vaddr, src_page, PAGE_SIZE);
+ munmap(vaddr, PAGE_SIZE);
+ return 0;
+}
+
+unsigned long xc_get_filesz(int fd)
+{
+ u16 sig;
+ u32 _sz = 0;
+ unsigned long sz;
+
+ lseek(fd, 0, SEEK_SET);
+ read(fd, &sig, sizeof(sig));
+ sz = lseek(fd, 0, SEEK_END);
+ if ( sig == 0x8b1f ) /* GZIP signature? */
+ {
+ lseek(fd, -4, SEEK_END);
+ read(fd, &_sz, 4);
+ sz = _sz;
+ }
+ lseek(fd, 0, SEEK_SET);
+
+ return sz;
+}
+char *xc_read_kernel_image(const char *filename, unsigned long *size)
+{
+ int kernel_fd = -1;
+ gzFile kernel_gfd = NULL;
+ char *image = NULL;
+ unsigned int bytes;
+ if ( (kernel_fd = open(filename, O_RDONLY)) < 0 )
+ {
+ PERROR("Could not open kernel image");
+ goto out;
+ }
+
+ *size = xc_get_filesz(kernel_fd);
+
+ if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
+ {
+ PERROR("Could not allocate decompression state for state file");
+ goto out;
+ }
+
+ if ( (image = malloc(*size)) == NULL )
+ {
+ PERROR("Could not allocate memory for kernel image");
+ goto out;
+ }
+
+ if ( (bytes = gzread(kernel_gfd, image, *size)) != *size )
+ {
+ PERROR("Error reading kernel image, could not"
+ " read the whole image (%d != %ld).", bytes, *size);
+ free(image);
+ image = NULL;
+ }
+
+ out:
+ if ( kernel_gfd != NULL )
+ gzclose(kernel_gfd);
+ else if ( kernel_fd >= 0 )
+ close(kernel_fd);
+ return image;
+}
+
+void xc_map_memcpy(unsigned long dst, char *src, unsigned long size,
+ int xch, u32 dom, unsigned long *parray,
+ unsigned long vstart)
+{
+ char *va;
+ unsigned long chunksz, done, pa;
+
+ for ( done = 0; done < size; done += chunksz )
+ {
+ pa = dst + done - vstart;
+ va = xc_map_foreign_range(
+ xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
+ chunksz = size - done;
+ if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
+ chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
+ memcpy(va + (pa & (PAGE_SIZE-1)), src + done, chunksz);
+ munmap(va, PAGE_SIZE);
+ }
+}
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index c05ae491d9..0aed21274e 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -189,4 +189,17 @@ typedef struct mfn_mapper {
unsigned long xc_get_m2p_start_mfn ( int xc_handle );
+long xc_get_tot_pages(int xc_handle, u32 domid);
+
+int xc_copy_to_domain_page(int xc_handle, u32 domid,
+ unsigned long dst_pfn, void *src_page);
+
+unsigned long xc_get_filesz(int fd);
+
+char *xc_read_kernel_image(const char *filename, unsigned long *size);
+
+void xc_map_memcpy(unsigned long dst, char *src, unsigned long size,
+ int xch, u32 dom, unsigned long *parray,
+ unsigned long vstart);
+
#endif /* __XC_PRIVATE_H__ */
diff --git a/tools/libxc/xc_vmx_build.c b/tools/libxc/xc_vmx_build.c
new file mode 100644
index 0000000000..aaae52f0c5
--- /dev/null
+++ b/tools/libxc/xc_vmx_build.c
@@ -0,0 +1,802 @@
+/******************************************************************************
+ * xc_vmx_build.c
+ */
+
+#include "xc_private.h"
+#define ELFSIZE 32
+#include "xc_elf.h"
+#include <stdlib.h>
+#include <zlib.h>
+#include "linux_boot_params.h"
+
+#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
+#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+
+#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
+#define round_pgdown(_p) ((_p)&PAGE_MASK)
+
+#define LINUX_BOOT_PARAMS_ADDR 0x00090000
+#define LINUX_KERNEL_ENTR_ADDR 0x00100000
+#define LINUX_PAGE_OFFSET 0xC0000000
+
+struct domain_setup_info
+{
+ unsigned long v_start;
+ unsigned long v_end;
+ unsigned long v_kernstart;
+ unsigned long v_kernend;
+ unsigned long v_kernentry;
+
+ unsigned int use_writable_pagetables;
+ unsigned int load_bsd_symtab;
+
+ unsigned long symtab_addr;
+ unsigned long symtab_len;
+};
+
+static int
+parseelfimage(
+ char *elfbase, unsigned long elfsize, struct domain_setup_info *dsi);
+static int
+loadelfimage(
+ char *elfbase, int xch, u32 dom, unsigned long *parray,
+ unsigned long vstart);
+static int
+loadelfsymtab(
+ char *elfbase, int xch, u32 dom, unsigned long *parray,
+ struct domain_setup_info *dsi);
+
+static void build_e820map(struct mem_map *mem_mapp, unsigned long mem_size)
+{
+ int nr_map = 0;
+
+ /* XXX: Doesn't work for > 4GB yet */
+ mem_mapp->map[0].addr = 0x0;
+ mem_mapp->map[0].size = 0x9F800;
+ mem_mapp->map[0].type = E820_RAM;
+ mem_mapp->map[0].caching_attr = MEMMAP_WB;
+ nr_map++;
+
+ mem_mapp->map[1].addr = 0x9F800;
+ mem_mapp->map[1].size = 0x800;
+ mem_mapp->map[1].type = E820_RESERVED;
+ mem_mapp->map[1].caching_attr = MEMMAP_UC;
+ nr_map++;
+
+ mem_mapp->map[2].addr = 0xA0000;
+ mem_mapp->map[2].size = 0x20000;
+ mem_mapp->map[2].type = E820_IO;
+ mem_mapp->map[2].caching_attr = MEMMAP_UC;
+ nr_map++;
+
+ mem_mapp->map[3].addr = 0xF0000;
+ mem_mapp->map[3].size = 0x10000;
+ mem_mapp->map[3].type = E820_RESERVED;
+ mem_mapp->map[3].caching_attr = MEMMAP_UC;
+ nr_map++;
+
+ mem_mapp->map[4].addr = 0x100000;
+ mem_mapp->map[4].size = mem_size - 0x100000 - PAGE_SIZE;
+ mem_mapp->map[4].type = E820_RAM;
+ mem_mapp->map[4].caching_attr = MEMMAP_WB;
+ nr_map++;
+
+ mem_mapp->map[5].addr = mem_size - PAGE_SIZE;
+ mem_mapp->map[5].size = PAGE_SIZE;
+ mem_mapp->map[5].type = E820_SHARED;
+ mem_mapp->map[5].caching_attr = MEMMAP_WB;
+ nr_map++;
+
+ mem_mapp->map[6].addr = mem_size;
+ mem_mapp->map[6].size = 0x3 * PAGE_SIZE;
+ mem_mapp->map[6].type = E820_NVS;
+ mem_mapp->map[6].caching_attr = MEMMAP_UC;
+ nr_map++;
+
+ mem_mapp->map[7].addr = mem_size + 0x3 * PAGE_SIZE;
+ mem_mapp->map[7].size = 0xA * PAGE_SIZE;
+ mem_mapp->map[7].type = E820_ACPI;
+ mem_mapp->map[7].caching_attr = MEMMAP_WB;
+ nr_map++;
+
+ mem_mapp->map[8].addr = 0xFEC00000;
+ mem_mapp->map[8].size = 0x1400000;
+ mem_mapp->map[8].type = E820_IO;
+ mem_mapp->map[8].caching_attr = MEMMAP_UC;
+ nr_map++;
+
+ mem_mapp->nr_map = nr_map;
+}
+
+static int setup_guestos(int xc_handle,
+ u32 dom, int memsize,
+ char *image, unsigned long image_size,
+ gzFile initrd_gfd, unsigned long initrd_len,
+ unsigned long nr_pages,
+ full_execution_context_t *ctxt,
+ const char *cmdline,
+ unsigned long shared_info_frame,
+ unsigned int control_evtchn,
+ unsigned long flags,
+ struct mem_map * mem_mapp)
+{
+ l1_pgentry_t *vl1tab=NULL, *vl1e=NULL;
+ l2_pgentry_t *vl2tab=NULL, *vl2e=NULL;
+ unsigned long *page_array = NULL;
+ unsigned long l2tab;
+ unsigned long l1tab;
+ unsigned long count, i;
+ shared_info_t *shared_info;
+ struct linux_boot_params * boot_paramsp;
+ __u16 * boot_gdtp;
+ mmu_t *mmu = NULL;
+ int rc;
+
+ unsigned long nr_pt_pages;
+ unsigned long ppt_alloc;
+
+ struct domain_setup_info dsi;
+ unsigned long vinitrd_start;
+ unsigned long vinitrd_end;
+ unsigned long vboot_params_start;
+ unsigned long vboot_params_end;
+ unsigned long vboot_gdt_start;
+ unsigned long vboot_gdt_end;
+ unsigned long vpt_start;
+ unsigned long vpt_end;
+ unsigned long v_end;
+
+ memset(&dsi, 0, sizeof(struct domain_setup_info));
+
+ rc = parseelfimage(image, image_size, &dsi);
+ if ( rc != 0 )
+ goto error_out;
+
+ if (dsi.use_writable_pagetables)
+ xc_domain_setvmassist(xc_handle, dom, VMASST_CMD_enable,
+ VMASST_TYPE_writable_pagetables);
+
+ if (dsi.load_bsd_symtab)
+ loadelfsymtab(image, xc_handle, dom, NULL, &dsi);
+
+ if ( (dsi.v_start & (PAGE_SIZE-1)) != 0 )
+ {
+ PERROR("Guest OS must load to a page boundary.\n");
+ goto error_out;
+ }
+
+ /*
+ * Why do we need this? The number of page-table frames depends on the
+ * size of the bootstrap address space. But the size of the address space
+ * depends on the number of page-table frames (since each one is mapped
+ * read-only). We have a pair of simultaneous equations in two unknowns,
+ * which we solve by exhaustive search.
+ */
+ vboot_params_start = LINUX_BOOT_PARAMS_ADDR;
+ vboot_params_end = vboot_params_start + PAGE_SIZE;
+ vboot_gdt_start = vboot_params_end;
+ vboot_gdt_end = vboot_gdt_start + PAGE_SIZE;
+
+ /* memsize is in megabytes */
+ v_end = memsize << 20;
+ vinitrd_end = v_end - PAGE_SIZE; /* leaving the top 4k untouched for IO requests page use */
+ vinitrd_start = vinitrd_end - initrd_len;
+ vinitrd_start = vinitrd_start & (~(PAGE_SIZE - 1));
+
+ if(initrd_len == 0)
+ vinitrd_start = vinitrd_end = 0;
+
+ nr_pt_pages = 1 + ((memsize + 3) >> 2);
+ vpt_start = v_end;
+ vpt_end = vpt_start + (nr_pt_pages * PAGE_SIZE);
+
+ printf("VIRTUAL MEMORY ARRANGEMENT:\n"
+ " Boot_params: %08lx->%08lx\n"
+ " boot_gdt: %08lx->%08lx\n"
+ " Loaded kernel: %08lx->%08lx\n"
+ " Init. ramdisk: %08lx->%08lx\n"
+ " Page tables: %08lx->%08lx\n"
+ " TOTAL: %08lx->%08lx\n",
+ vboot_params_start, vboot_params_end,
+ vboot_gdt_start, vboot_gdt_end,
+ dsi.v_kernstart, dsi.v_kernend,
+ vinitrd_start, vinitrd_end,
+ vpt_start, vpt_end,
+ dsi.v_start, v_end);
+ printf(" ENTRY ADDRESS: %08lx\n", dsi.v_kernentry);
+ printf(" INITRD LENGTH: %08lx\n", initrd_len);
+
+ if ( (v_end - dsi.v_start) > (nr_pages * PAGE_SIZE) )
+ {
+ printf("Initial guest OS requires too much space\n"
+ "(%luMB is greater than %luMB limit)\n",
+ (v_end-dsi.v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
+ goto error_out;
+ }
+
+ if ( (page_array = malloc(nr_pages * sizeof(unsigned long))) == NULL )
+ {
+ PERROR("Could not allocate memory");
+ goto error_out;
+ }
+
+ if ( xc_get_pfn_list(xc_handle, dom, page_array, nr_pages) != nr_pages )
+ {
+ PERROR("Could not get the page frame list");
+ goto error_out;
+ }
+
+ loadelfimage(image, xc_handle, dom, page_array, dsi.v_start);
+
+ if (dsi.load_bsd_symtab)
+ loadelfsymtab(image, xc_handle, dom, page_array, &dsi);
+
+ /* Load the initial ramdisk image. */
+ if ( initrd_len != 0 )
+ {
+ for ( i = (vinitrd_start - dsi.v_start);
+ i < (vinitrd_end - dsi.v_start); i += PAGE_SIZE )
+ {
+ char page[PAGE_SIZE];
+ if ( gzread(initrd_gfd, page, PAGE_SIZE) == -1 )
+ {
+ PERROR("Error reading initrd image, could not");
+ goto error_out;
+ }
+ xc_copy_to_domain_page(xc_handle, dom,
+ page_array[i>>PAGE_SHIFT], page);
+ }
+ }
+
+ if ( (mmu = init_mmu_updates(xc_handle, dom)) == NULL )
+ goto error_out;
+
+ /* First allocate page for page dir. */
+ ppt_alloc = (vpt_start - dsi.v_start) >> PAGE_SHIFT;
+ l2tab = page_array[ppt_alloc++] << PAGE_SHIFT;
+ ctxt->pt_base = l2tab;
+
+ /* Initialise the page tables. */
+ if ( (vl2tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
+ PROT_READ|PROT_WRITE,
+ l2tab >> PAGE_SHIFT)) == NULL )
+ goto error_out;
+ memset(vl2tab, 0, PAGE_SIZE);
+ vl2e = &vl2tab[l2_table_offset(dsi.v_start)];
+ for ( count = 0; count < ((v_end-dsi.v_start)>>PAGE_SHIFT); count++ )
+ {
+ if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 )
+ {
+ l1tab = page_array[ppt_alloc++] << PAGE_SHIFT;
+ if ( vl1tab != NULL )
+ munmap(vl1tab, PAGE_SIZE);
+ if ( (vl1tab = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
+ PROT_READ|PROT_WRITE,
+ l1tab >> PAGE_SHIFT)) == NULL )
+ {
+ munmap(vl2tab, PAGE_SIZE);
+ goto error_out;
+ }
+ memset(vl1tab, 0, PAGE_SIZE);
+ vl1e = &vl1tab[l1_table_offset(dsi.v_start + (count<<PAGE_SHIFT))];
+ *vl2e++ = l1tab | L2_PROT;
+ }
+
+ *vl1e = (page_array[count] << PAGE_SHIFT) | L1_PROT;
+ vl1e++;
+ }
+ munmap(vl1tab, PAGE_SIZE);
+ munmap(vl2tab, PAGE_SIZE);
+
+ /*
+ * Pin down l2tab addr as page dir page - causes hypervisor to provide
+ * correct protection for the page
+ */
+ if ( add_mmu_update(xc_handle, mmu,
+ l2tab | MMU_EXTENDED_COMMAND, MMUEXT_PIN_L2_TABLE) )
+ goto error_out;
+
+ boot_paramsp = xc_map_foreign_range(
+ xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
+ page_array[(vboot_params_start-dsi.v_start)>>PAGE_SHIFT]);
+ memset(boot_paramsp, 0, sizeof(*boot_paramsp));
+
+ strncpy(boot_paramsp->cmd_line, cmdline, 0x800);
+ boot_paramsp->cmd_line[0x800-1] = '\0';
+ boot_paramsp->cmd_line_ptr = ((unsigned long) vboot_params_start) + offsetof(struct linux_boot_params, cmd_line);
+
+ boot_paramsp->setup_sects = 0;
+ boot_paramsp->mount_root_rdonly = 1;
+ boot_paramsp->swapdev = 0x0;
+ boot_paramsp->ramdisk_flags = 0x0;
+ boot_paramsp->root_dev = 0x0; /* We must tell kernel root dev by kernel command line. */
+
+ /* we don't have a ps/2 mouse now.
+ * 0xAA means a aux mouse is there.
+ * See detect_auxiliary_port() in pc_keyb.c.
+ */
+ boot_paramsp->aux_device_info = 0x0;
+
+ boot_paramsp->header_magic[0] = 0x48; /* "H" */
+ boot_paramsp->header_magic[1] = 0x64; /* "d" */
+ boot_paramsp->header_magic[2] = 0x72; /* "r" */
+ boot_paramsp->header_magic[3] = 0x53; /* "S" */
+
+ boot_paramsp->protocol_version = 0x0203; /* 2.03 */
+ boot_paramsp->loader_type = 0x71; /* GRUB */
+ boot_paramsp->loader_flags = 0x1; /* loaded high */
+ boot_paramsp->code32_start = LINUX_KERNEL_ENTR_ADDR; /* 1MB */
+ boot_paramsp->initrd_start = vinitrd_start;
+ boot_paramsp->initrd_size = initrd_len;
+
+ i = ((memsize - 1) << 10) - 4;
+ boot_paramsp->alt_mem_k = i; /* alt_mem_k */
+ boot_paramsp->screen.overlap.ext_mem_k = i & 0xFFFF; /* ext_mem_k */
+
+ /*
+ * Stuff SCREAN_INFO
+ */
+ boot_paramsp->screen.info.orig_x = 0;
+ boot_paramsp->screen.info.orig_y = 0;
+ boot_paramsp->screen.info.orig_video_page = 8;
+ boot_paramsp->screen.info.orig_video_mode = 3;
+ boot_paramsp->screen.info.orig_video_cols = 80;
+ boot_paramsp->screen.info.orig_video_ega_bx = 0;
+ boot_paramsp->screen.info.orig_video_lines = 25;
+ boot_paramsp->screen.info.orig_video_isVGA = 1;
+ boot_paramsp->screen.info.orig_video_points = 0x0010;
+
+ /* seems we may NOT stuff boot_paramsp->apm_bios_info */
+ /* seems we may NOT stuff boot_paramsp->drive_info */
+ /* seems we may NOT stuff boot_paramsp->sys_desc_table */
+ *((unsigned short *) &boot_paramsp->drive_info.dummy[0]) = 800;
+ boot_paramsp->drive_info.dummy[2] = 4;
+ boot_paramsp->drive_info.dummy[14] = 32;
+
+ /* memsize is in megabytes */
+ build_e820map(mem_mapp, memsize << 20);
+ boot_paramsp->e820_map_nr = mem_mapp->nr_map;
+ for (i=0; i<mem_mapp->nr_map; i++) {
+ boot_paramsp->e820_map[i].addr = mem_mapp->map[i].addr;
+ boot_paramsp->e820_map[i].size = mem_mapp->map[i].size;
+ boot_paramsp->e820_map[i].type = mem_mapp->map[i].type;
+ }
+ munmap(boot_paramsp, PAGE_SIZE);
+
+ boot_gdtp = xc_map_foreign_range(
+ xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE,
+ page_array[(vboot_gdt_start-dsi.v_start)>>PAGE_SHIFT]);
+ memset(boot_gdtp, 0, PAGE_SIZE);
+ boot_gdtp[12*4 + 0] = boot_gdtp[13*4 + 0] = 0xffff; /* limit */
+ boot_gdtp[12*4 + 1] = boot_gdtp[13*4 + 1] = 0x0000; /* base */
+ boot_gdtp[12*4 + 2] = 0x9a00; boot_gdtp[13*4 + 2] = 0x9200; /* perms */
+ boot_gdtp[12*4 + 3] = boot_gdtp[13*4 + 3] = 0x00cf; /* granu + top of limit */
+ munmap(boot_gdtp, PAGE_SIZE);
+
+ /* shared_info page starts its life empty. */
+ shared_info = xc_map_foreign_range(
+ xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, shared_info_frame);
+ memset(shared_info, 0, sizeof(shared_info_t));
+ /* Mask all upcalls... */
+ for ( i = 0; i < MAX_VIRT_CPUS; i++ )
+ shared_info->vcpu_data[i].evtchn_upcall_mask = 1;
+ munmap(shared_info, PAGE_SIZE);
+
+ /* Send the page update requests down to the hypervisor. */
+ if ( finish_mmu_updates(xc_handle, mmu) )
+ goto error_out;
+
+ free(mmu);
+ free(page_array);
+
+ /*
+ * Initial register values:
+ */
+ ctxt->cpu_ctxt.ds = 0x68;
+ ctxt->cpu_ctxt.es = 0x0;
+ ctxt->cpu_ctxt.fs = 0x0;
+ ctxt->cpu_ctxt.gs = 0x0;
+ ctxt->cpu_ctxt.ss = 0x68;
+ ctxt->cpu_ctxt.cs = 0x60;
+ ctxt->cpu_ctxt.eip = dsi.v_kernentry;
+ ctxt->cpu_ctxt.edx = vboot_gdt_start;
+ ctxt->cpu_ctxt.eax = 0x800;
+ ctxt->cpu_ctxt.esp = vboot_gdt_end;
+ ctxt->cpu_ctxt.ebx = 0; /* startup_32 expects this to be 0 to signal boot cpu */
+ ctxt->cpu_ctxt.ecx = mem_mapp->nr_map;
+ ctxt->cpu_ctxt.esi = vboot_params_start;
+ ctxt->cpu_ctxt.edi = vboot_params_start + 0x2d0;
+
+ ctxt->cpu_ctxt.eflags = (1<<2);
+
+ return 0;
+
+ error_out:
+ if ( mmu != NULL )
+ free(mmu);
+ if ( page_array != NULL )
+ free(page_array);
+ return -1;
+}
+
+
+#define VMX_FEATURE_FLAG 0x20
+
+int vmx_identify(void)
+{
+ int eax, ecx;
+
+ __asm__ __volatile__ ("cpuid"
+ : "=a" (eax), "=c" (ecx)
+ : "0" (1)
+ : "bx", "dx");
+ if (!(ecx & VMX_FEATURE_FLAG)) {
+ return -1;
+ }
+ return 0;
+}
+
+int xc_vmx_build(int xc_handle,
+ u32 domid,
+ int memsize,
+ const char *image_name,
+ struct mem_map *mem_mapp,
+ const char *ramdisk_name,
+ const char *cmdline,
+ unsigned int control_evtchn,
+ unsigned long flags)
+{
+ dom0_op_t launch_op, op;
+ int initrd_fd = -1;
+ gzFile initrd_gfd = NULL;
+ int rc, i;
+ full_execution_context_t st_ctxt, *ctxt = &st_ctxt;
+ unsigned long nr_pages;
+ char *image = NULL;
+ unsigned long image_size, initrd_size=0;
+
+ if ( vmx_identify() < 0 )
+ {
+ PERROR("CPU doesn't support VMX Extensions");
+ goto error_out;
+ }
+
+ if ( (nr_pages = xc_get_tot_pages(xc_handle, domid)) < 0 )
+ {
+ PERROR("Could not find total pages for domain");
+ goto error_out;
+ }
+
+ if ( (image = xc_read_kernel_image(image_name, &image_size)) == NULL )
+ goto error_out;
+
+ if ( (ramdisk_name != NULL) && (strlen(ramdisk_name) != 0) )
+ {
+ if ( (initrd_fd = open(ramdisk_name, O_RDONLY)) < 0 )
+ {
+ PERROR("Could not open the initial ramdisk image");
+ goto error_out;
+ }
+
+ initrd_size = xc_get_filesz(initrd_fd);
+
+ if ( (initrd_gfd = gzdopen(initrd_fd, "rb")) == NULL )
+ {
+ PERROR("Could not allocate decompression state for initrd");
+ goto error_out;
+ }
+ }
+
+ if ( mlock(&st_ctxt, sizeof(st_ctxt) ) )
+ {
+ PERROR("Unable to mlock ctxt");
+ return 1;
+ }
+
+ op.cmd = DOM0_GETDOMAININFO;
+ op.u.getdomaininfo.domain = (domid_t)domid;
+ op.u.getdomaininfo.exec_domain = 0;
+ op.u.getdomaininfo.ctxt = ctxt;
+ if ( (do_dom0_op(xc_handle, &op) < 0) ||
+ ((u16)op.u.getdomaininfo.domain != domid) )
+ {
+ PERROR("Could not get info on domain");
+ goto error_out;
+ }
+ if ( !(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED) ||
+ (ctxt->pt_base != 0) )
+ {
+ ERROR("Domain is already constructed");
+ goto error_out;
+ }
+
+ if ( setup_guestos(xc_handle, domid, memsize, image, image_size,
+ initrd_gfd, initrd_size, nr_pages,
+ ctxt, cmdline,
+ op.u.getdomaininfo.shared_info_frame,
+ control_evtchn, flags, mem_mapp) < 0 )
+ {
+ ERROR("Error constructing guest OS");
+ goto error_out;
+ }
+
+ if ( initrd_fd >= 0 )
+ close(initrd_fd);
+ if ( initrd_gfd )
+ gzclose(initrd_gfd);
+ if ( image != NULL )
+ free(image);
+
+ ctxt->flags = ECF_VMX_GUEST;
+ /* FPU is set up to default initial state. */
+ memset(ctxt->fpu_ctxt, 0, sizeof(ctxt->fpu_ctxt));
+
+ /* Virtual IDT is empty at start-of-day. */
+ for ( i = 0; i < 256; i++ )
+ {
+ ctxt->trap_ctxt[i].vector = i;
+ ctxt->trap_ctxt[i].cs = FLAT_GUESTOS_CS;
+ }
+ ctxt->fast_trap_idx = 0;
+
+ /* No LDT. */
+ ctxt->ldt_ents = 0;
+
+ /* Use the default Xen-provided GDT. */
+ ctxt->gdt_ents = 0;
+
+ /* Ring 1 stack is the initial stack. */
+/*
+ ctxt->guestos_ss = FLAT_GUESTOS_DS;
+ ctxt->guestos_esp = vstartinfo_start;
+*/
+ /* No debugging. */
+ memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
+
+ /* No callback handlers. */
+ ctxt->event_callback_cs = FLAT_GUESTOS_CS;
+ ctxt->event_callback_eip = 0;
+ ctxt->failsafe_callback_cs = FLAT_GUESTOS_CS;
+ ctxt->failsafe_callback_eip = 0;
+
+ memset( &launch_op, 0, sizeof(launch_op) );
+
+ launch_op.u.builddomain.domain = (domid_t)domid;
+ launch_op.u.builddomain.ctxt = ctxt;
+
+ launch_op.cmd = DOM0_BUILDDOMAIN;
+ rc = do_dom0_op(xc_handle, &launch_op);
+ return rc;
+
+ error_out:
+ if ( initrd_gfd != NULL )
+ gzclose(initrd_gfd);
+ else if ( initrd_fd >= 0 )
+ close(initrd_fd);
+ if ( image != NULL )
+ free(image);
+
+ return -1;
+}
+
+static inline int is_loadable_phdr(Elf_Phdr *phdr)
+{
+ return ((phdr->p_type == PT_LOAD) &&
+ ((phdr->p_flags & (PF_W|PF_X)) != 0));
+}
+
+static int parseelfimage(char *elfbase,
+ unsigned long elfsize,
+ struct domain_setup_info *dsi)
+{
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
+ Elf_Phdr *phdr;
+ Elf_Shdr *shdr;
+ unsigned long kernstart = ~0UL, kernend=0UL;
+ char *shstrtab;
+ int h;
+
+ if ( !IS_ELF(*ehdr) )
+ {
+ ERROR("Kernel image does not have an ELF header.");
+ return -EINVAL;
+ }
+
+ if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize )
+ {
+ ERROR("ELF program headers extend beyond end of image.");
+ return -EINVAL;
+ }
+
+ if ( (ehdr->e_shoff + (ehdr->e_shnum * ehdr->e_shentsize)) > elfsize )
+ {
+ ERROR("ELF section headers extend beyond end of image.");
+ return -EINVAL;
+ }
+
+ /* Find the section-header strings table. */
+ if ( ehdr->e_shstrndx == SHN_UNDEF )
+ {
+ ERROR("ELF image has no section-header strings table (shstrtab).");
+ return -EINVAL;
+ }
+ shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff +
+ (ehdr->e_shstrndx*ehdr->e_shentsize));
+ shstrtab = elfbase + shdr->sh_offset;
+
+ for ( h = 0; h < ehdr->e_phnum; h++ )
+ {
+ phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
+ if ( !is_loadable_phdr(phdr) )
+ continue;
+ if ( phdr->p_vaddr < kernstart )
+ kernstart = phdr->p_vaddr;
+ if ( (phdr->p_vaddr + phdr->p_memsz) > kernend )
+ kernend = phdr->p_vaddr + phdr->p_memsz;
+ }
+
+ if ( (kernstart > kernend) ||
+ (ehdr->e_entry < kernstart) ||
+ (ehdr->e_entry > kernend) )
+ {
+ ERROR("Malformed ELF image.");
+ return -EINVAL;
+ }
+
+ dsi->v_start = 0x00000000;
+ dsi->use_writable_pagetables = 0;
+ dsi->load_bsd_symtab = 0;
+
+ dsi->v_kernstart = kernstart - LINUX_PAGE_OFFSET;
+ dsi->v_kernend = kernend - LINUX_PAGE_OFFSET;
+ dsi->v_kernentry = LINUX_KERNEL_ENTR_ADDR;
+
+ dsi->v_end = dsi->v_kernend;
+
+ return 0;
+}
+
+static int
+loadelfimage(
+ char *elfbase, int xch, u32 dom, unsigned long *parray,
+ unsigned long vstart)
+{
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
+ Elf_Phdr *phdr;
+ int h;
+
+ char *va;
+ unsigned long pa, done, chunksz;
+
+ for ( h = 0; h < ehdr->e_phnum; h++ )
+ {
+ phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
+ if ( !is_loadable_phdr(phdr) )
+ continue;
+
+ for ( done = 0; done < phdr->p_filesz; done += chunksz )
+ {
+ pa = (phdr->p_vaddr + done) - vstart - LINUX_PAGE_OFFSET;
+ va = xc_map_foreign_range(
+ xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
+ chunksz = phdr->p_filesz - done;
+ if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
+ chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
+ memcpy(va + (pa & (PAGE_SIZE-1)),
+ elfbase + phdr->p_offset + done, chunksz);
+ munmap(va, PAGE_SIZE);
+ }
+
+ for ( ; done < phdr->p_memsz; done += chunksz )
+ {
+ pa = (phdr->p_vaddr + done) - vstart - LINUX_PAGE_OFFSET;
+ va = xc_map_foreign_range(
+ xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
+ chunksz = phdr->p_memsz - done;
+ if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
+ chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
+ memset(va + (pa & (PAGE_SIZE-1)), 0, chunksz);
+ munmap(va, PAGE_SIZE);
+ }
+ }
+
+ return 0;
+}
+
+
+#define ELFROUND (ELFSIZE / 8)
+
+static int
+loadelfsymtab(
+ char *elfbase, int xch, u32 dom, unsigned long *parray,
+ struct domain_setup_info *dsi)
+{
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase, *sym_ehdr;
+ Elf_Shdr *shdr;
+ unsigned long maxva, symva;
+ char *p;
+ int h, i;
+
+ p = malloc(sizeof(int) + sizeof(Elf_Ehdr) +
+ ehdr->e_shnum * sizeof(Elf_Shdr));
+ if (p == NULL)
+ return 0;
+
+ maxva = (dsi->v_kernend + ELFROUND - 1) & ~(ELFROUND - 1);
+ symva = maxva;
+ maxva += sizeof(int);
+ dsi->symtab_addr = maxva;
+ dsi->symtab_len = 0;
+ maxva += sizeof(Elf_Ehdr) + ehdr->e_shnum * sizeof(Elf_Shdr);
+ maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
+
+ shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
+ memcpy(shdr, elfbase + ehdr->e_shoff, ehdr->e_shnum * sizeof(Elf_Shdr));
+
+ for ( h = 0; h < ehdr->e_shnum; h++ )
+ {
+ if ( shdr[h].sh_type == SHT_STRTAB )
+ {
+ /* Look for a strtab @i linked to symtab @h. */
+ for ( i = 0; i < ehdr->e_shnum; i++ )
+ if ( (shdr[i].sh_type == SHT_SYMTAB) &&
+ (shdr[i].sh_link == h) )
+ break;
+ /* Skip symtab @h if we found no corresponding strtab @i. */
+ if ( i == ehdr->e_shnum )
+ {
+ shdr[h].sh_offset = 0;
+ continue;
+ }
+ }
+
+ if ( (shdr[h].sh_type == SHT_STRTAB) ||
+ (shdr[h].sh_type == SHT_SYMTAB) )
+ {
+ if ( parray != NULL )
+ xc_map_memcpy(maxva, elfbase + shdr[h].sh_offset, shdr[h].sh_size,
+ xch, dom, parray, dsi->v_start);
+
+ /* Mangled to be based on ELF header location. */
+ shdr[h].sh_offset = maxva - dsi->symtab_addr;
+
+ dsi->symtab_len += shdr[h].sh_size;
+ maxva += shdr[h].sh_size;
+ maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
+ }
+
+ shdr[h].sh_name = 0; /* Name is NULL. */
+ }
+
+ if ( dsi->symtab_len == 0 )
+ {
+ dsi->symtab_addr = 0;
+ goto out;
+ }
+
+ if ( parray != NULL )
+ {
+ *(int *)p = maxva - dsi->symtab_addr;
+ sym_ehdr = (Elf_Ehdr *)(p + sizeof(int));
+ memcpy(sym_ehdr, ehdr, sizeof(Elf_Ehdr));
+ sym_ehdr->e_phoff = 0;
+ sym_ehdr->e_shoff = sizeof(Elf_Ehdr);
+ sym_ehdr->e_phentsize = 0;
+ sym_ehdr->e_phnum = 0;
+ sym_ehdr->e_shstrndx = SHN_UNDEF;
+
+ /* Copy total length, crafted ELF header and section header table */
+ xc_map_memcpy(symva, p, sizeof(int) + sizeof(Elf_Ehdr) +
+ ehdr->e_shnum * sizeof(Elf_Shdr), xch, dom, parray,
+ dsi->v_start);
+ }
+
+ dsi->symtab_len = maxva - dsi->symtab_addr;
+ dsi->v_end = round_pgup(maxva);
+
+ out:
+ if ( p != NULL )
+ free(p);
+
+ return 0;
+}
diff --git a/tools/libxutil/Makefile b/tools/libxutil/Makefile
index 595cd97e83..5c6c37eeef 100644
--- a/tools/libxutil/Makefile
+++ b/tools/libxutil/Makefile
@@ -41,7 +41,7 @@ CFLAGS += -Wall -Werror -O3 -fno-strict-aliasing
CFLAGS += -Wp,-MD,.$(@F).d
DEPS = .*.d
-MAJOR := 2.0
+MAJOR := 3.0
MINOR := 0
LIB := libxutil.so
LIB += libxutil.so.$(MAJOR)
diff --git a/tools/misc/xend b/tools/misc/xend
index d19a4868f6..5c9757ec23 100644
--- a/tools/misc/xend
+++ b/tools/misc/xend
@@ -21,6 +21,12 @@
"""
import os
import sys
+import socket
+import time
+
+XCS_PORT = 1633
+XCS_EXEC = "/usr/sbin/xcs"
+XCS_LOGFILE = "/var/log/xcs.log"
# Default install path for Xen binary packages.
sys.path = [ '/usr/lib/python' ] + sys.path
@@ -89,6 +95,18 @@ def check_user():
msg("Xend must be run as root.")
hline()
raise CheckError("invalid user")
+
+def xcs_running():
+ """ See if the control switch is running.
+ """
+ ret = 1
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ try:
+ s.connect( ("127.0.0.1", XCS_PORT) )
+ except:
+ ret = 0
+ s.close()
+ return (ret)
def main():
try:
@@ -97,6 +115,31 @@ def main():
check_user()
except CheckError:
sys.exit(1)
+
+ if (not xcs_running()):
+ if os.fork():
+ time.sleep(1) # let xcs start
+ else:
+ try:
+ logfile = os.open(XCS_LOGFILE,
+ os.O_WRONLY|os.O_APPEND|os.O_CREAT)
+ os.close(1)
+ os.dup(logfile)
+ os.close(2)
+ os.dup(logfile)
+ os.close(logfile)
+ os.execlp(XCS_EXEC, XCS_EXEC)
+ except:
+ hline()
+ msg("Tried to start xcs, but failed. Is it installed?")
+ hline()
+ raise CheckError("couldn't start xcs")
+ if (not xcs_running()):
+ hline()
+ msg("Failed to start the control interface switch.")
+ hline()
+ raise CheckError("xcs not running")
+
daemon = SrvDaemon.instance()
if not sys.argv[1:]:
print 'usage: %s {start|stop|restart}' % sys.argv[0]
diff --git a/tools/python/setup.py b/tools/python/setup.py
index 99069d0be4..81536989ee 100644
--- a/tools/python/setup.py
+++ b/tools/python/setup.py
@@ -10,6 +10,7 @@ extra_compile_args = [ "-fno-strict-aliasing", "-Wall", "-Werror" ]
include_dirs = [ XEN_ROOT + "/tools/python/xen/lowlevel/xu",
XEN_ROOT + "/tools/libxc",
XEN_ROOT + "/tools/libxutil",
+ XEN_ROOT + "/tools/xcs",
]
library_dirs = [ XEN_ROOT + "/tools/libxc",
diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c
index d2b7da0eba..543a2cd380 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -16,6 +16,7 @@
#include <arpa/inet.h>
#include "xc_private.h"
#include "gzip_stream.h"
+#include "linux_boot_params.h"
/* Needed for Python versions earlier than 2.3. */
#ifndef PyMODINIT_FUNC
@@ -347,19 +348,19 @@ static PyObject *pyxc_linux_build(PyObject *self,
u32 dom;
char *image, *ramdisk = NULL, *cmdline = "";
- int control_evtchn, flags = 0;
+ int control_evtchn, flags = 0, vcpus = 1;
static char *kwd_list[] = { "dom", "control_evtchn",
- "image", "ramdisk", "cmdline", "flags",
+ "image", "ramdisk", "cmdline", "flags", "vcpus",
NULL };
- if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssi", kwd_list,
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|ssii", kwd_list,
&dom, &control_evtchn,
- &image, &ramdisk, &cmdline, &flags) )
+ &image, &ramdisk, &cmdline, &flags, &vcpus) )
return NULL;
if ( xc_linux_build(xc->xc_handle, dom, image,
- ramdisk, cmdline, control_evtchn, flags) != 0 )
+ ramdisk, cmdline, control_evtchn, flags, vcpus) != 0 )
return PyErr_SetFromErrno(xc_error);
Py_INCREF(zero);
@@ -393,6 +394,90 @@ static PyObject *pyxc_plan9_build(PyObject *self,
return zero;
}
+static PyObject *pyxc_vmx_build(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+
+ u32 dom;
+ char *image, *ramdisk = NULL, *cmdline = "";
+ PyObject *memmap;
+ int control_evtchn, flags = 0;
+ int numItems, i;
+ int memsize;
+ struct mem_map mem_map;
+
+ static char *kwd_list[] = { "dom", "control_evtchn",
+ "memsize",
+ "image", "memmap",
+ "ramdisk", "cmdline", "flags",
+ NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iiisO!|ssi", kwd_list,
+ &dom, &control_evtchn,
+ &memsize,
+ &image, &PyList_Type, &memmap,
+ &ramdisk, &cmdline, &flags) )
+ return NULL;
+
+ memset(&mem_map, 0, sizeof(mem_map));
+ /* Parse memmap */
+
+ /* get the number of lines passed to us */
+ numItems = PyList_Size(memmap) - 1; /* removing the line
+ containing "memmap" */
+ printf ("numItems: %d\n", numItems);
+ mem_map.nr_map = numItems;
+
+
+ /* should raise an error here. */
+ if (numItems < 0) return NULL; /* Not a list */
+
+
+ /* iterate over items of the list, grabbing ranges and parsing them */
+ for (i = 1; i <= numItems; i++) { // skip over "memmap"
+ PyObject *item, *f1, *f2, *f3, *f4;
+ int numFields;
+ unsigned long lf1, lf2, lf3, lf4;
+ char *sf1, *sf2;
+
+ /* grab the string object from the next element of the list */
+ item = PyList_GetItem(memmap, i); /* Can't fail */
+
+ /* get the number of lines passed to us */
+ numFields = PyList_Size(item);
+
+ if (numFields != 4)
+ return NULL;
+
+ f1 = PyList_GetItem(item, 0);
+ f2 = PyList_GetItem(item, 1);
+ f3 = PyList_GetItem(item, 2);
+ f4 = PyList_GetItem(item, 3);
+
+ /* Convert objects to strings/longs */
+ sf1 = PyString_AsString(f1);
+ sf2 = PyString_AsString(f2);
+ lf3 = PyLong_AsLong(f3);
+ lf4 = PyLong_AsLong(f4);
+ sscanf(sf1, "%lx", &lf1);
+ sscanf(sf2, "%lx", &lf2);
+
+ mem_map.map[i-1].addr = lf1;
+ mem_map.map[i-1].size = lf2 - lf1;
+ mem_map.map[i-1].type = lf3;
+ mem_map.map[i-1].caching_attr = lf4;
+ }
+
+ if ( xc_vmx_build(xc->xc_handle, dom, memsize, image, &mem_map,
+ ramdisk, cmdline, control_evtchn, flags) != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
static PyObject *pyxc_bvtsched_global_set(PyObject *self,
PyObject *args,
PyObject *kwds)
@@ -941,6 +1026,18 @@ static PyMethodDef pyxc_methods[] = {
" image [str]: Name of kernel image file. May be gzipped.\n"
" ramdisk [str, n/a]: Name of ramdisk file, if any.\n"
" cmdline [str, n/a]: Kernel parameters, if any.\n\n"
+ " vcpus [int, 1]: Number of Virtual CPUS in domain.\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "vmx_build",
+ (PyCFunction)pyxc_vmx_build,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Build a new Linux guest OS.\n"
+ " dom [int]: Identifier of domain to build into.\n"
+ " image [str]: Name of kernel image file. May be gzipped.\n"
+ " memmap [str]: Memory map.\n\n"
+ " ramdisk [str, n/a]: Name of ramdisk file, if any.\n"
+ " cmdline [str, n/a]: Kernel parameters, if any.\n\n"
"Returns: [int] 0 on success; -1 on error.\n" },
{ "bvtsched_global_set",
diff --git a/tools/python/xen/lowlevel/xu/xu.c b/tools/python/xen/lowlevel/xu/xu.c
index 9a67693683..12f27d63db 100644
--- a/tools/python/xen/lowlevel/xu/xu.c
+++ b/tools/python/xen/lowlevel/xu/xu.c
@@ -59,6 +59,7 @@
/* Set the close-on-exec flag on a file descriptor. Doesn't currently bother
* to check for errors. */
+/*
static void set_cloexec(int fd)
{
int flags = fcntl(fd, F_GETFD, 0);
@@ -69,7 +70,183 @@ static void set_cloexec(int fd)
flags |= FD_CLOEXEC;
fcntl(fd, F_SETFD, flags);
}
+*/
+/*
+ * *********************** XCS INTERFACE ***********************
+ */
+
+#include <arpa/inet.h>
+#include <xcs_proto.h>
+
+static int xcs_ctrl_fd = -1; /* control connection to the xcs server. */
+static int xcs_data_fd = -1; /* data connection to the xcs server. */
+static u32 xcs_session_id = 0;
+static int xcs_ctrl_send(xcs_msg_t *msg);
+static int xcs_ctrl_read(xcs_msg_t *msg);
+static int xcs_data_send(xcs_msg_t *msg);
+static int xcs_data_read(xcs_msg_t *msg);
+
+static int xcs_connect(char *ip, short port)
+{
+ struct sockaddr_in addr;
+ int ret, flags;
+ xcs_msg_t msg;
+
+ if (xcs_data_fd != -1) /* already connected */
+ return 0;
+
+ xcs_ctrl_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (xcs_ctrl_fd < 0)
+ {
+ printf("error creating xcs socket!\n");
+ goto fail;
+ }
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = inet_addr(ip);
+ memset(&(addr.sin_zero), '\0', 8);
+
+ ret = connect(xcs_ctrl_fd, (struct sockaddr *)&addr,
+ sizeof(struct sockaddr));
+ if (ret < 0)
+ {
+ printf("error connecting to xcs(ctrl)! (%d)\n", errno);
+ goto ctrl_fd_fail;
+ }
+
+ //set_cloexec(xcs_ctrl_fd);
+
+ msg.type = XCS_CONNECT_CTRL;
+ msg.u.connect.session_id = xcs_session_id;
+ xcs_ctrl_send(&msg);
+ xcs_ctrl_read(&msg); /* TODO: timeout + error! */
+
+ if (msg.result != XCS_RSLT_OK)
+ {
+ printf("error connecting xcs control channel!\n");
+ goto ctrl_fd_fail;
+ }
+ xcs_session_id = msg.u.connect.session_id;
+
+ /* now the data connection. */
+ xcs_data_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (xcs_data_fd < 0)
+ {
+ printf("error creating xcs data socket!\n");
+ goto ctrl_fd_fail;
+ }
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = inet_addr(ip);
+ memset(&(addr.sin_zero), '\0', 8);
+
+ ret = connect(xcs_data_fd, (struct sockaddr *)&addr,
+ sizeof(struct sockaddr));
+ if (ret < 0)
+ {
+ printf("error connecting to xcs(data)! (%d)\n", errno);
+ goto data_fd_fail;
+ }
+
+ //set_cloexec(xcs_data_fd);
+ msg.type = XCS_CONNECT_DATA;
+ msg.u.connect.session_id = xcs_session_id;
+ xcs_data_send(&msg);
+ xcs_data_read(&msg); /* TODO: timeout + error! */
+
+ if (msg.result != XCS_RSLT_OK)
+ {
+ printf("error connecting xcs control channel!\n");
+ goto ctrl_fd_fail;
+ }
+
+ if ( ((flags = fcntl(xcs_data_fd, F_GETFL, 0)) < 0) ||
+ (fcntl(xcs_data_fd, F_SETFL, flags | O_NONBLOCK) < 0) )
+ {
+ printf("Unable to set non-blocking status on data socket.");
+ goto data_fd_fail;
+ }
+
+ return 0;
+
+data_fd_fail:
+ close(xcs_data_fd);
+ xcs_data_fd = -1;
+
+ctrl_fd_fail:
+ close(xcs_ctrl_fd);
+ xcs_ctrl_fd = -1;
+
+fail:
+ return -1;
+
+}
+
+static void xcs_disconnect(void)
+{
+ close(xcs_data_fd);
+ xcs_data_fd = -1;
+ close(xcs_ctrl_fd);
+ xcs_ctrl_fd = -1;
+}
+
+static int xcs_ctrl_read(xcs_msg_t *msg)
+{
+ int ret;
+
+ ret = read(xcs_ctrl_fd, msg, sizeof(xcs_msg_t));
+ return ret;
+}
+
+static int xcs_ctrl_send(xcs_msg_t *msg)
+{
+ int ret;
+
+ ret = send(xcs_ctrl_fd, msg, sizeof(xcs_msg_t), 0);
+ return ret;
+}
+
+static int xcs_data_read(xcs_msg_t *msg)
+{
+ int ret;
+
+ ret = read(xcs_data_fd, msg, sizeof(xcs_msg_t));
+ return ret;
+}
+
+static int xcs_data_send(xcs_msg_t *msg)
+{
+ int ret;
+
+ ret = send(xcs_data_fd, msg, sizeof(xcs_msg_t), 0);
+ return ret;
+}
+
+
+typedef struct kme_st {
+ xcs_msg_t msg;
+ struct kme_st *next;
+} xcs_msg_ent_t;
+
+
+#define XCS_RING_SIZE 64
+static xcs_msg_ent_t *req_ring[64];
+static unsigned req_prod = 0;
+static unsigned req_cons = 0;
+
+static xcs_msg_ent_t *rsp_ring[64];
+static unsigned rsp_prod = 0;
+static unsigned rsp_cons = 0;
+
+#define REQ_RING_ENT(_idx) (req_ring[(_idx) % XCS_RING_SIZE])
+#define RSP_RING_ENT(_idx) (rsp_ring[(_idx) % XCS_RING_SIZE])
+#define REQ_RING_FULL ( req_prod - req_cons == XCS_RING_SIZE )
+#define RSP_RING_FULL ( rsp_prod - rsp_cons == XCS_RING_SIZE )
+#define REQ_RING_EMPTY ( req_prod == req_cons )
+#define RSP_RING_EMPTY ( rsp_prod == rsp_cons )
/*
* *********************** NOTIFIER ***********************
*/
@@ -81,81 +258,136 @@ typedef struct {
static PyObject *xu_notifier_read(PyObject *self, PyObject *args)
{
- xu_notifier_object *xun = (xu_notifier_object *)self;
- u16 v;
- int bytes;
+ xcs_msg_ent_t *ent;
+ int ret;
if ( !PyArg_ParseTuple(args, "") )
return NULL;
-
- while ( (bytes = read(xun->evtchn_fd, &v, sizeof(v))) == -1 )
+
+ while ((!REQ_RING_FULL) && (!RSP_RING_FULL))
{
- if ( errno == EINTR )
+ ent = (xcs_msg_ent_t *)malloc(sizeof(xcs_msg_ent_t));
+ ret = xcs_data_read(&ent->msg);
+
+ if (ret == -1)
+ {
+ free(ent);
+ if ( errno == EINTR )
+ continue;
+ if ( errno == EAGAIN )
+ break;
+ return PyErr_SetFromErrno(PyExc_IOError);
+ }
+
+ switch (ent->msg.type)
+ {
+ case XCS_REQUEST:
+ REQ_RING_ENT(req_prod) = ent;
+ req_prod++;
continue;
- if ( errno == EAGAIN )
- goto none;
- return PyErr_SetFromErrno(PyExc_IOError);
+
+ case XCS_RESPONSE:
+ RSP_RING_ENT(rsp_prod) = ent;
+ rsp_prod++;
+ continue;
+
+ case XCS_VIRQ:
+ ret = ent->msg.u.control.local_port;
+ free(ent);
+ return PyInt_FromLong(ret);
+
+ default:
+ /*printf("Throwing away xcs msg type: %u\n", ent->msg.type);*/
+ free(ent);
+ }
+ }
+
+ if (!REQ_RING_EMPTY)
+ {
+ return PyInt_FromLong(REQ_RING_ENT(req_cons)->msg.u.control.local_port);
+ }
+
+ if (!RSP_RING_EMPTY)
+ {
+ return PyInt_FromLong(RSP_RING_ENT(rsp_cons)->msg.u.control.local_port);
}
- if ( bytes == sizeof(v) )
- return PyInt_FromLong(v);
-
- none:
Py_INCREF(Py_None);
return Py_None;
}
+/* this is now a NOOP */
static PyObject *xu_notifier_unmask(PyObject *self, PyObject *args)
{
- xu_notifier_object *xun = (xu_notifier_object *)self;
- u16 v;
- int idx;
-
- if ( !PyArg_ParseTuple(args, "i", &idx) )
- return NULL;
-
- v = (u16)idx;
-
- (void)write(xun->evtchn_fd, &v, sizeof(v));
-
Py_INCREF(Py_None);
return Py_None;
}
+/* this is now a NOOP */
static PyObject *xu_notifier_bind(PyObject *self, PyObject *args)
{
- xu_notifier_object *xun = (xu_notifier_object *)self;
- int idx;
-
- if ( !PyArg_ParseTuple(args, "i", &idx) )
- return NULL;
-
- if ( ioctl(xun->evtchn_fd, EVTCHN_BIND, idx) != 0 )
- return PyErr_SetFromErrno(PyExc_IOError);
-
Py_INCREF(Py_None);
return Py_None;
}
-static PyObject *xu_notifier_unbind(PyObject *self, PyObject *args)
+static PyObject *xu_notifier_bind_virq(PyObject *self,
+ PyObject *args, PyObject *kwds)
{
- xu_notifier_object *xun = (xu_notifier_object *)self;
- int idx;
+ int virq;
+ xcs_msg_t kmsg;
- if ( !PyArg_ParseTuple(args, "i", &idx) )
+ static char *kwd_list[] = { "virq", NULL };
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &virq) )
return NULL;
+
+ kmsg.type = XCS_VIRQ_BIND;
+ kmsg.u.virq.virq = virq;
+ xcs_ctrl_send(&kmsg);
+ xcs_ctrl_read(&kmsg);
+
+ if ( kmsg.result != XCS_RSLT_OK )
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return PyInt_FromLong(kmsg.u.virq.port);
+}
- if ( ioctl(xun->evtchn_fd, EVTCHN_UNBIND, idx) != 0 )
- return PyErr_SetFromErrno(PyExc_IOError);
+static PyObject *xu_notifier_virq_send(PyObject *self,
+ PyObject *args, PyObject *kwds)
+{
+ int port;
+ xcs_msg_t kmsg;
+ static char *kwd_list[] = { "port", NULL };
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &port) )
+ return NULL;
+
+ kmsg.type = XCS_VIRQ;
+ kmsg.u.control.local_port = port;
+ xcs_ctrl_send(&kmsg);
+ xcs_ctrl_read(&kmsg);
+
+ if ( kmsg.result != XCS_RSLT_OK )
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ return PyInt_FromLong(kmsg.u.virq.port);
+}
+
+/* this is now a NOOP */
+static PyObject *xu_notifier_unbind(PyObject *self, PyObject *args)
+{
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *xu_notifier_fileno(PyObject *self, PyObject *args)
{
- xu_notifier_object *xun = (xu_notifier_object *)self;
- return PyInt_FromLong(xun->evtchn_fd);
+ return PyInt_FromLong(xcs_data_fd);
}
static PyMethodDef xu_notifier_methods[] = {
@@ -178,6 +410,18 @@ static PyMethodDef xu_notifier_methods[] = {
(PyCFunction)xu_notifier_unbind,
METH_VARARGS,
"No longer get notifications for a @port.\n" },
+
+ { "bind_virq",
+ (PyCFunction)xu_notifier_bind_virq,
+ METH_VARARGS | METH_KEYWORDS,
+ "Get notifications for a virq.\n"
+ " virq [int]: VIRQ to bind.\n\n" },
+
+ { "virq_send",
+ (PyCFunction)xu_notifier_virq_send,
+ METH_VARARGS | METH_KEYWORDS,
+ "Fire a virq notification.\n"
+ " port [int]: port that VIRQ is bound to.\n\n" },
{ "fileno",
(PyCFunction)xu_notifier_fileno,
@@ -189,35 +433,22 @@ static PyMethodDef xu_notifier_methods[] = {
staticforward PyTypeObject xu_notifier_type;
+/* connect to xcs if we aren't already, and return a dummy object. */
static PyObject *xu_notifier_new(PyObject *self, PyObject *args)
{
xu_notifier_object *xun;
- struct stat st;
+ int i;
if ( !PyArg_ParseTuple(args, "") )
return NULL;
xun = PyObject_New(xu_notifier_object, &xu_notifier_type);
- /* Make sure any existing device file links to correct device. */
- if ( (lstat(EVTCHN_DEV_NAME, &st) != 0) ||
- !S_ISCHR(st.st_mode) ||
- (st.st_rdev != makedev(EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR)) )
- (void)unlink(EVTCHN_DEV_NAME);
-
- reopen:
- xun->evtchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR);
- if ( xun->evtchn_fd == -1 )
- {
- if ( (errno == ENOENT) &&
- ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
- (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600,
- makedev(EVTCHN_DEV_MAJOR,EVTCHN_DEV_MINOR)) == 0) )
- goto reopen;
- PyObject_Del((PyObject *)xun);
- return PyErr_SetFromErrno(PyExc_IOError);
- }
- set_cloexec(xun->evtchn_fd);
+ for (i = 0; i < XCS_RING_SIZE; i++)
+ REQ_RING_ENT(i) = RSP_RING_ENT(i) = NULL;
+
+ (void)xcs_connect("127.0.0.1", XCS_TCP_PORT);
+
return (PyObject *)xun;
}
@@ -229,8 +460,7 @@ static PyObject *xu_notifier_getattr(PyObject *obj, char *name)
static void xu_notifier_dealloc(PyObject *self)
{
- xu_notifier_object *xun = (xu_notifier_object *)self;
- (void)close(xun->evtchn_fd);
+ xcs_disconnect();
PyObject_Del(self);
}
@@ -287,6 +517,24 @@ static PyTypeObject xu_notifier_type = {
PyDict_SetItemString(dict, #_field, obj); \
} while ( 0 )
+#define PSTR2CHAR(_struct, _field) \
+ do { \
+ PyObject *obj; \
+ if ( (obj = PyDict_GetItemString(payload, #_field)) != NULL ) \
+ { \
+ if ( PyString_Check(obj) ) \
+ { \
+ char *buffer = PyString_AsString(obj); \
+ \
+ strcpy(((_struct *)&xum->msg.msg[0])->_field, \
+ buffer); \
+ /* Should complain about length - think later */ \
+ dict_items_parsed++; \
+ } \
+ } \
+ xum->msg.length = sizeof(_struct); \
+ } while ( 0 )
+
typedef struct {
PyObject_HEAD;
control_msg_t msg;
@@ -478,6 +726,52 @@ static PyObject *xu_message_get_payload(PyObject *self, PyObject *args)
case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS):
C2P(netif_be_driver_status_t, status, Int, Long);
return dict;
+ case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED):
+ C2P(usbif_fe_interface_status_changed_t, status, Int, Long);
+ C2P(usbif_fe_interface_status_changed_t, evtchn, Int, Long);
+ C2P(usbif_fe_interface_status_changed_t, domid, Int, Long);
+ C2P(usbif_fe_interface_status_changed_t, bandwidth, Int, Long);
+ C2P(usbif_fe_interface_status_changed_t, num_ports, Int, Long);
+ return dict;
+ case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_DRIVER_STATUS_CHANGED):
+ C2P(usbif_fe_driver_status_changed_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_CONNECT):
+ C2P(usbif_fe_interface_connect_t, shmem_frame, Int, Long);
+ return dict;
+ case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_DISCONNECT):
+ return dict;
+ case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_CREATE):
+ C2P(usbif_be_create_t, domid, Int, Long);
+ C2P(usbif_be_create_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_DESTROY):
+ C2P(usbif_be_destroy_t, domid, Int, Long);
+ C2P(usbif_be_destroy_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_CONNECT):
+ C2P(usbif_be_connect_t, domid, Int, Long);
+ C2P(usbif_be_connect_t, shmem_frame, Int, Long);
+ C2P(usbif_be_connect_t, evtchn, Int, Long);
+ C2P(usbif_be_connect_t, bandwidth, Int, Long);
+ C2P(usbif_be_connect_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_DISCONNECT):
+ C2P(usbif_be_disconnect_t, domid, Int, Long);
+ C2P(usbif_be_disconnect_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_DRIVER_STATUS_CHANGED):
+ C2P(usbif_be_driver_status_changed_t, status, Int, Long);
+ return dict;
+ case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_CLAIM_PORT):
+ C2P(usbif_be_claim_port_t, domid, Int, Long);
+ C2P(usbif_be_claim_port_t, usbif_port, Int, Long);
+ C2P(usbif_be_claim_port_t, status, Int, Long);
+ C2P(usbif_be_claim_port_t, path, String, String);
+ return dict;
+ case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_RELEASE_PORT):
+ C2P(usbif_be_release_port_t, path, String, String);
+ return dict;
case TYPE(CMSG_MEM_REQUEST, CMSG_MEM_REQUEST_SET):
C2P(mem_request_t, target, Int, Long);
C2P(mem_request_t, status, Int, Long);
@@ -623,6 +917,12 @@ static PyObject *xu_message_new(PyObject *self, PyObject *args)
P2C(netif_be_create_t, mac[3], u8);
P2C(netif_be_create_t, mac[4], u8);
P2C(netif_be_create_t, mac[5], u8);
+ P2C(netif_be_create_t, be_mac[0], u8);
+ P2C(netif_be_create_t, be_mac[1], u8);
+ P2C(netif_be_create_t, be_mac[2], u8);
+ P2C(netif_be_create_t, be_mac[3], u8);
+ P2C(netif_be_create_t, be_mac[4], u8);
+ P2C(netif_be_create_t, be_mac[5], u8);
break;
case TYPE(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY):
P2C(netif_be_destroy_t, domid, u32);
@@ -647,6 +947,53 @@ static PyObject *xu_message_new(PyObject *self, PyObject *args)
P2C(mem_request_t, target, u32);
P2C(mem_request_t, status, u32);
break;
+ case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED):
+ P2C(usbif_fe_interface_status_changed_t, status, u32);
+ P2C(usbif_fe_interface_status_changed_t, evtchn, u16);
+ P2C(usbif_fe_interface_status_changed_t, domid, domid_t);
+ P2C(usbif_fe_interface_status_changed_t, bandwidth, u32);
+ P2C(usbif_fe_interface_status_changed_t, num_ports, u32);
+ break;
+ case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_DRIVER_STATUS_CHANGED):
+ P2C(usbif_fe_driver_status_changed_t, status, u32);
+ break;
+ case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_CONNECT):
+ P2C(usbif_fe_interface_connect_t, shmem_frame, memory_t);
+ break;
+ case TYPE(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_DISCONNECT):
+ break;
+ case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_CREATE):
+ P2C(usbif_be_create_t, domid, domid_t);
+ P2C(usbif_be_create_t, status, u32);
+ break;
+ case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_DESTROY):
+ P2C(usbif_be_destroy_t, domid, domid_t);
+ P2C(usbif_be_destroy_t, status, u32);
+ break;
+ case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_CONNECT):
+ P2C(usbif_be_connect_t, domid, domid_t);
+ P2C(usbif_be_connect_t, shmem_frame, memory_t);
+ P2C(usbif_be_connect_t, evtchn, u32);
+ P2C(usbif_be_connect_t, bandwidth, u32);
+ P2C(usbif_be_connect_t, status, u32);
+ break;
+ case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_DISCONNECT):
+ P2C(usbif_be_disconnect_t, domid, domid_t);
+ P2C(usbif_be_disconnect_t, status, u32);
+ break;
+ case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_DRIVER_STATUS_CHANGED):
+ P2C(usbif_be_driver_status_changed_t, status, u32);
+ break;
+ case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_CLAIM_PORT):
+ P2C(usbif_be_claim_port_t, domid, domid_t);
+ P2C(usbif_be_claim_port_t, usbif_port, u32);
+ P2C(usbif_be_claim_port_t, status, u32);
+ PSTR2CHAR(usbif_be_claim_port_t, path);
+ printf("dict items parsed = %d", dict_items_parsed);
+ break;
+ case TYPE(CMSG_USBIF_BE, CMSG_USBIF_BE_RELEASE_PORT):
+ PSTR2CHAR(usbif_be_release_port_t, path);
+ break;
}
if ( dict_items_parsed != PyDict_Size(payload) )
@@ -696,43 +1043,20 @@ static PyTypeObject xu_message_type = {
* *********************** PORT ***********************
*/
-static control_if_t *map_control_interface(int fd, unsigned long pfn,
- u32 dom)
-{
- char *vaddr = xc_map_foreign_range( fd, dom, PAGE_SIZE,
- PROT_READ|PROT_WRITE, pfn );
- if ( vaddr == NULL )
- return NULL;
- return (control_if_t *)(vaddr + 2048);
-}
-static void unmap_control_interface(int fd, control_if_t *c)
-{
- char *vaddr = (char *)c - 2048;
- (void)munmap(vaddr, PAGE_SIZE);
-}
-
typedef struct xu_port_object {
PyObject_HEAD;
int xc_handle;
int connected;
u32 remote_dom;
int local_port, remote_port;
- control_if_t *interface;
- CONTROL_RING_IDX tx_req_cons, tx_resp_prod;
- CONTROL_RING_IDX rx_req_prod, rx_resp_cons;
+ struct xu_port_object *fix_next;
} xu_port_object;
static PyObject *port_error;
+/* now a NOOP */
static PyObject *xu_port_notify(PyObject *self, PyObject *args)
{
- xu_port_object *xup = (xu_port_object *)self;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- (void)xc_evtchn_send(xup->xc_handle, xup->local_port);
-
Py_INCREF(Py_None);
return Py_None;
}
@@ -741,39 +1065,47 @@ static PyObject *xu_port_read_request(PyObject *self, PyObject *args)
{
xu_port_object *xup = (xu_port_object *)self;
xu_message_object *xum;
- CONTROL_RING_IDX c = xup->tx_req_cons;
- control_if_t *cif = xup->interface;
control_msg_t *cmsg;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- if ( (c == cif->tx_req_prod) ||
- ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) )
- {
- PyErr_SetString(port_error, "no request to read");
- return NULL;
+ unsigned i;
+ xcs_msg_ent_t *ent = NULL;
+
+ for ( i = req_cons; (i != req_prod); i++ ) {
+ ent = REQ_RING_ENT(i);
+ if (ent == NULL)
+ continue;
+ if (ent->msg.u.control.remote_dom == xup->remote_dom)
+ break;
}
+
+ if ((ent == NULL) ||
+ (ent->msg.u.control.remote_dom != xup->remote_dom))
+ goto none;
- /* Need to ensure we see the request, despite seeing the index update.*/
- rmb();
-
- cmsg = &cif->tx_ring[MASK_CONTROL_IDX(c)];
+ cmsg = &ent->msg.u.control.msg;
xum = PyObject_New(xu_message_object, &xu_message_type);
memcpy(&xum->msg, cmsg, sizeof(*cmsg));
if ( xum->msg.length > sizeof(xum->msg.msg) )
xum->msg.length = sizeof(xum->msg.msg);
- xup->tx_req_cons++;
+ free(ent);
+
+ /* remove the entry from the ring and advance the consumer if possible */
+ REQ_RING_ENT(i) = NULL;
+ while ( (REQ_RING_ENT(req_cons) == NULL) && (!REQ_RING_EMPTY) )
+ req_cons++;
+
return (PyObject *)xum;
+
+none:
+ Py_INCREF(Py_None);
+ return Py_None;
+
}
static PyObject *xu_port_write_request(PyObject *self, PyObject *args)
{
xu_port_object *xup = (xu_port_object *)self;
xu_message_object *xum;
- CONTROL_RING_IDX p = xup->rx_req_prod;
- control_if_t *cif = xup->interface;
- control_msg_t *cmsg;
+ xcs_msg_t kmsg;
if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) )
return NULL;
@@ -784,18 +1116,11 @@ static PyObject *xu_port_write_request(PyObject *self, PyObject *args)
return NULL;
}
- if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) )
- {
- PyErr_SetString(port_error, "no space to write request");
- return NULL;
- }
-
- cmsg = &cif->rx_ring[MASK_CONTROL_IDX(p)];
- memcpy(cmsg, &xum->msg, sizeof(*cmsg));
-
- wmb();
- xup->rx_req_prod = cif->rx_req_prod = p + 1;
-
+ kmsg.type = XCS_REQUEST;
+ kmsg.u.control.remote_dom = xup->remote_dom;
+ memcpy(&kmsg.u.control.msg, &xum->msg, sizeof(control_msg_t));
+ xcs_data_send(&kmsg);
+
Py_INCREF(Py_None);
return Py_None;
}
@@ -804,38 +1129,47 @@ static PyObject *xu_port_read_response(PyObject *self, PyObject *args)
{
xu_port_object *xup = (xu_port_object *)self;
xu_message_object *xum;
- CONTROL_RING_IDX c = xup->rx_resp_cons;
- control_if_t *cif = xup->interface;
control_msg_t *cmsg;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
-
- if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) )
- {
- PyErr_SetString(port_error, "no response to read");
- return NULL;
+ unsigned i;
+ xcs_msg_ent_t *ent = NULL;
+
+ for ( i = rsp_cons; (i != rsp_prod); i++ ) {
+ ent = RSP_RING_ENT(i);
+ if (ent == NULL)
+ continue;
+ if (ent->msg.u.control.remote_dom == xup->remote_dom)
+ break;
}
+
+ if ((ent == NULL) ||
+ (ent->msg.u.control.remote_dom != xup->remote_dom))
+ goto none;
- /* Need to ensure we see the response, despite seeing the index update.*/
- rmb();
-
- cmsg = &cif->rx_ring[MASK_CONTROL_IDX(c)];
+ cmsg = &ent->msg.u.control.msg;
xum = PyObject_New(xu_message_object, &xu_message_type);
memcpy(&xum->msg, cmsg, sizeof(*cmsg));
if ( xum->msg.length > sizeof(xum->msg.msg) )
xum->msg.length = sizeof(xum->msg.msg);
- xup->rx_resp_cons++;
+ free(ent);
+
+ /* remove the entry from the ring and advance the consumer if possible */
+ RSP_RING_ENT(i) = NULL;
+ while ( (RSP_RING_ENT(rsp_cons) == NULL) && (!RSP_RING_EMPTY) )
+ rsp_cons++;
+
return (PyObject *)xum;
+
+none:
+ Py_INCREF(Py_None);
+ return Py_None;
+
}
static PyObject *xu_port_write_response(PyObject *self, PyObject *args)
{
xu_port_object *xup = (xu_port_object *)self;
xu_message_object *xum;
- CONTROL_RING_IDX p = xup->tx_resp_prod;
- control_if_t *cif = xup->interface;
- control_msg_t *cmsg;
+ xcs_msg_t kmsg;
if ( !PyArg_ParseTuple(args, "O", (PyObject **)&xum) )
return NULL;
@@ -846,17 +1180,10 @@ static PyObject *xu_port_write_response(PyObject *self, PyObject *args)
return NULL;
}
- if ( p == xup->tx_req_cons )
- {
- PyErr_SetString(port_error, "no space to write response");
- return NULL;
- }
-
- cmsg = &cif->tx_ring[MASK_CONTROL_IDX(p)];
- memcpy(cmsg, &xum->msg, sizeof(*cmsg));
-
- wmb();
- xup->tx_resp_prod = cif->tx_resp_prod = p + 1;
+ kmsg.type = XCS_RESPONSE;
+ kmsg.u.control.remote_dom = xup->remote_dom;
+ memcpy(&kmsg.u.control.msg, &xum->msg, sizeof(control_msg_t));
+ xcs_data_send(&kmsg);
Py_INCREF(Py_None);
return Py_None;
@@ -864,133 +1191,131 @@ static PyObject *xu_port_write_response(PyObject *self, PyObject *args)
static PyObject *xu_port_request_to_read(PyObject *self, PyObject *args)
{
- xu_port_object *xup = (xu_port_object *)self;
- CONTROL_RING_IDX c = xup->tx_req_cons;
- control_if_t *cif = xup->interface;
-
+ xu_port_object *xup = (xu_port_object *)self;
+ xcs_msg_ent_t *ent;
+ int found = 0;
+ unsigned i;
+
if ( !PyArg_ParseTuple(args, "") )
return NULL;
- if ( (c == cif->tx_req_prod) ||
- ((c - xup->tx_resp_prod) == CONTROL_RING_SIZE) )
- return PyInt_FromLong(0);
-
- return PyInt_FromLong(1);
+ for ( i = req_cons; (i != req_prod); i++ ) {
+ ent = REQ_RING_ENT(i);
+ if (ent == NULL)
+ continue;
+ if (ent->msg.u.control.remote_dom == xup->remote_dom) {
+ found = 1;
+ break;
+ }
+ }
+
+ return PyInt_FromLong(found);
}
static PyObject *xu_port_space_to_write_request(PyObject *self, PyObject *args)
{
- xu_port_object *xup = (xu_port_object *)self;
- CONTROL_RING_IDX p = xup->rx_req_prod;
-
if ( !PyArg_ParseTuple(args, "") )
return NULL;
- if ( ((p - xup->rx_resp_cons) == CONTROL_RING_SIZE) )
- return PyInt_FromLong(0);
-
return PyInt_FromLong(1);
}
static PyObject *xu_port_response_to_read(PyObject *self, PyObject *args)
{
- xu_port_object *xup = (xu_port_object *)self;
- CONTROL_RING_IDX c = xup->rx_resp_cons;
- control_if_t *cif = xup->interface;
-
+ xu_port_object *xup = (xu_port_object *)self;
+ xcs_msg_ent_t *ent;
+ int found = 0;
+ unsigned i;
+
if ( !PyArg_ParseTuple(args, "") )
return NULL;
- if ( (c == cif->rx_resp_prod) || (c == xup->rx_req_prod) )
- return PyInt_FromLong(0);
-
- return PyInt_FromLong(1);
+ for ( i = rsp_cons; (i != rsp_prod); i++ ) {
+ ent = RSP_RING_ENT(i);
+ if (ent == NULL)
+ continue;
+ if (ent->msg.u.control.remote_dom == xup->remote_dom) {
+ found = 1;
+ break;
+ }
+ }
+
+ return PyInt_FromLong(found);
}
static PyObject *xu_port_space_to_write_response(
PyObject *self, PyObject *args)
{
- xu_port_object *xup = (xu_port_object *)self;
- CONTROL_RING_IDX p = xup->tx_resp_prod;
-
if ( !PyArg_ParseTuple(args, "") )
return NULL;
- if ( p == xup->tx_req_cons )
- return PyInt_FromLong(0);
-
return PyInt_FromLong(1);
}
-static int __xu_port_connect(xu_port_object *xup)
+/* NOOP */
+static PyObject *xu_port_connect(PyObject *self, PyObject *args)
{
- xc_dominfo_t info;
-
- if ( xup->connected )
- {
- return 0;
- }
-
- if ( (xc_domain_getinfo(xup->xc_handle, xup->remote_dom, 1, &info) != 1) ||
- (info.domid != xup->remote_dom) )
- {
- PyErr_SetString(port_error, "Failed to obtain domain status");
- return -1;
- }
-
- xup->interface =
- map_control_interface(xup->xc_handle, info.shared_info_frame,
- xup->remote_dom);
-
- if ( xup->interface == NULL )
- {
- PyErr_SetString(port_error, "Failed to map domain control interface");
- return -1;
- }
-
- /* Synchronise ring indexes. */
- xup->tx_resp_prod = xup->interface->tx_resp_prod;
- xup->tx_req_cons = xup->interface->tx_resp_prod;
- xup->rx_req_prod = xup->interface->rx_req_prod;
- xup->rx_resp_cons = xup->interface->rx_resp_prod;
-
- xup->connected = 1;
-
- return 0;
+ Py_INCREF(Py_None);
+ return Py_None;
}
-static void __xu_port_disconnect(xu_port_object *xup)
+/* NOOP */
+static PyObject *xu_port_disconnect(PyObject *self, PyObject *args)
{
- if ( xup->connected )
- unmap_control_interface(xup->xc_handle, xup->interface);
- xup->connected = 0;
+ Py_INCREF(Py_None);
+ return Py_None;
}
-static PyObject *xu_port_connect(PyObject *self, PyObject *args)
+static PyObject *xu_port_register(PyObject *self, PyObject *args,
+ PyObject *kwds)
{
- xu_port_object *xup = (xu_port_object *)self;
-
- if ( !PyArg_ParseTuple(args, "") )
- return NULL;
+ int type;
+ xcs_msg_t msg;
+ xu_port_object *xup = (xu_port_object *)self;
+ static char *kwd_list[] = { "type", NULL };
- if ( __xu_port_connect(xup) != 0 )
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list,
+ &type) )
return NULL;
-
- Py_INCREF(Py_None);
- return Py_None;
+
+ msg.type = XCS_MSG_BIND;
+ msg.u.bind.port = xup->local_port;
+ msg.u.bind.type = type;
+ xcs_ctrl_send(&msg);
+ xcs_ctrl_read(&msg);
+
+ if (msg.result != XCS_RSLT_OK)
+ {
+ return PyInt_FromLong(0);
+ }
+
+ return PyInt_FromLong(1);
}
-static PyObject *xu_port_disconnect(PyObject *self, PyObject *args)
+static PyObject *xu_port_deregister(PyObject *self, PyObject *args,
+ PyObject *kwds)
{
- xu_port_object *xup = (xu_port_object *)self;
+ int type;
+ xcs_msg_t msg;
+ xu_port_object *xup = (xu_port_object *)self;
+ static char *kwd_list[] = { "type", NULL };
- if ( !PyArg_ParseTuple(args, "") )
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list,
+ &type) )
return NULL;
-
- __xu_port_disconnect(xup);
-
- Py_INCREF(Py_None);
- return Py_None;
+
+ msg.type = XCS_MSG_UNBIND;
+ msg.u.bind.port = xup->local_port;
+ msg.u.bind.type = type;
+ xcs_ctrl_send(&msg);
+ xcs_ctrl_read(&msg);
+
+ if (msg.result != XCS_RSLT_OK)
+ {
+ return PyInt_FromLong(0);
+ }
+
+ return PyInt_FromLong(1);
}
static PyMethodDef xu_port_methods[] = {
@@ -1038,6 +1363,16 @@ static PyMethodDef xu_port_methods[] = {
(PyCFunction)xu_port_space_to_write_response,
METH_VARARGS,
"Returns TRUE if there is space to write a response message.\n" },
+
+ { "register",
+ (PyCFunction)xu_port_register,
+ METH_VARARGS | METH_KEYWORDS,
+ "Register to receive a type of message on this channel.\n" },
+
+ { "deregister",
+ (PyCFunction)xu_port_deregister,
+ METH_VARARGS | METH_KEYWORDS,
+ "Stop receiving a type of message on this port.\n" },
{ "connect",
(PyCFunction)xu_port_connect,
@@ -1059,6 +1394,7 @@ static PyObject *xu_port_new(PyObject *self, PyObject *args, PyObject *kwds)
xu_port_object *xup;
u32 dom;
int port1 = 0, port2 = 0;
+ xcs_msg_t kmsg;
static char *kwd_list[] = { "dom", "local_port", "remote_port", NULL };
@@ -1070,51 +1406,26 @@ static PyObject *xu_port_new(PyObject *self, PyObject *args, PyObject *kwds)
xup->connected = 0;
xup->remote_dom = dom;
-
- if ( (xup->xc_handle = xc_interface_open()) == -1 )
- {
- PyErr_SetString(port_error, "Could not open Xen control interface");
+
+ kmsg.type = XCS_CIF_NEW_CC;
+ kmsg.u.interface.dom = xup->remote_dom;
+ kmsg.u.interface.local_port = port1;
+ kmsg.u.interface.remote_port = port2;
+ xcs_ctrl_send(&kmsg);
+ xcs_ctrl_read(&kmsg);
+
+ if ( kmsg.result != XCS_RSLT_OK )
goto fail1;
- }
-
- if ( dom == 0 )
- {
- /*
- * The control-interface event channel for DOM0 is already set up.
- * We use an ioctl to discover the port at our end of the channel.
- */
- port1 = ioctl(xup->xc_handle, IOCTL_PRIVCMD_INITDOMAIN_EVTCHN, NULL);
- port2 = -1; /* We don't need the remote end of the DOM0 link. */
- if ( port1 < 0 )
- {
- PyErr_SetString(port_error, "Could not open channel to DOM0");
- goto fail2;
- }
- }
- else if ( xc_evtchn_bind_interdomain(xup->xc_handle,
- DOMID_SELF, dom,
- &port1, &port2) != 0 )
- {
- PyErr_SetString(port_error, "Could not open channel to domain");
- goto fail2;
- }
-
- xup->local_port = port1;
- xup->remote_port = port2;
-
- if ( __xu_port_connect(xup) != 0 )
- goto fail3;
-
+
+ xup->local_port = kmsg.u.interface.local_port;
+ xup->remote_port = kmsg.u.interface.remote_port;
+ xup->connected = 1;
+
return (PyObject *)xup;
-
- fail3:
- if ( dom != 0 )
- (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, port1);
- fail2:
- (void)xc_interface_close(xup->xc_handle);
+
fail1:
PyObject_Del((PyObject *)xup);
- return NULL;
+ return NULL;
}
static PyObject *xu_port_getattr(PyObject *obj, char *name)
@@ -1131,11 +1442,20 @@ static PyObject *xu_port_getattr(PyObject *obj, char *name)
static void xu_port_dealloc(PyObject *self)
{
+
xu_port_object *xup = (xu_port_object *)self;
- __xu_port_disconnect(xup);
+ xcs_msg_t kmsg;
+
if ( xup->remote_dom != 0 )
- (void)xc_evtchn_close(xup->xc_handle, DOMID_SELF, xup->local_port);
- (void)xc_interface_close(xup->xc_handle);
+ {
+ kmsg.type = XCS_CIF_FREE_CC;
+ kmsg.u.interface.dom = xup->remote_dom;
+ kmsg.u.interface.local_port = xup->local_port;
+ kmsg.u.interface.remote_port = xup->remote_port;
+ xcs_ctrl_send(&kmsg);
+ xcs_ctrl_read(&kmsg);
+ }
+
PyObject_Del(self);
}
diff --git a/tools/python/xen/util/memmap.py b/tools/python/xen/util/memmap.py
new file mode 100644
index 0000000000..2899a87535
--- /dev/null
+++ b/tools/python/xen/util/memmap.py
@@ -0,0 +1,41 @@
+mem_caching_attr = {
+ 'UC' : 0,
+ 'WC' : 1,
+ 'WT' : 4,
+ 'WP' : 5,
+ 'WB' : 6,
+ };
+
+e820_mem_type = {
+ 'AddressRangeMemory' : 1,
+ 'AddressRangeReserved' : 2,
+ 'AddressRangeACPI' : 3,
+ 'AddressRangeNVS' : 4,
+ 'AddressRangeIO' : 16,
+ 'AddressRangeShared' : 17,
+};
+
+MT_COL = 2
+MA_COL = 3
+
+def strmap(row):
+ if (type(row) != type([])):
+ return row
+ row[MT_COL] = e820_mem_type[row[MT_COL]]
+ row[MA_COL] = mem_caching_attr[row[MA_COL]]
+ return row
+
+def memmap_parse(memmap):
+ return map(strmap, memmap)
+
+if __name__ == '__main__':
+ memmap = [ 'memmap',
+ [ '1', '2', 'AddressRangeMemory', 'UC'],
+ [ '1', '2', 'AddressRangeReserved', 'UC'],
+ [ '1', '2', 'AddressRangeACPI', 'WB'],
+ [ '1', '2', 'AddressRangeNVS', 'WB'],
+ [ '1', '2', 'AddressRangeIO', 'WB'],
+ [ '1', '2', 'AddressRangeShared', 'WB']]
+ print memmap_parse(memmap);
+
+
diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py
index 05647c83ab..22a0a8b282 100644
--- a/tools/python/xen/xend/XendDomainInfo.py
+++ b/tools/python/xen/xend/XendDomainInfo.py
@@ -20,6 +20,7 @@ from twisted.internet import defer
import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
import xen.util.ip
from xen.util.ip import _readline, _readlines
+from xen.xend.server import channel
import sxp
@@ -319,6 +320,9 @@ class XendDomainInfo:
self.restart_time = None
self.console_port = None
self.savedinfo = None
+ self.image_handler = None
+ self.is_vmx = 0
+ self.vcpus = 1
def setdom(self, dom):
"""Set the domain id.
@@ -446,7 +450,13 @@ class XendDomainInfo:
cpu = sxp.child_value(config, 'cpu')
if self.recreate and self.dom and cpu is not None:
xc.domain_pincpu(self.dom, int(cpu))
+ try:
+ image = sxp.child_value(self.config, 'image')
+ self.vcpus = int(sxp.child_value(image, 'vcpus'))
+ except:
+ raise VmError('invalid vcpus value')
+ self.find_image_handler()
self.init_domain()
self.configure_console()
self.configure_backends()
@@ -463,7 +473,7 @@ class XendDomainInfo:
raise
return deferred
- def construct_image(self):
+ def find_image_handler(self):
"""Construct the boot image for the domain.
@return vm
@@ -474,10 +484,17 @@ class XendDomainInfo:
image_name = sxp.name(image)
if image_name is None:
raise VmError('missing image name')
+ if image_name == "vmx":
+ self.is_vmx = 1
image_handler = get_image_handler(image_name)
if image_handler is None:
raise VmError('unknown image type: ' + image_name)
- image_handler(self, image)
+ self.image_handler = image_handler
+ return self
+
+ def construct_image(self):
+ image = sxp.child_value(self.config, 'image')
+ self.image_handler(self, image)
return self
def config_devices(self, name):
@@ -650,6 +667,7 @@ class XendDomainInfo:
"""
self.release_vifs()
self.release_vbds()
+ self.release_usbifs()
self.devices = {}
self.device_index = {}
@@ -674,6 +692,15 @@ class XendDomainInfo:
log.debug("Destroying vbds for domain %d", self.dom)
ctrl.destroy()
+ def release_usbifs(self):
+ """Release vm virtual USB devices (usbifs).
+ """
+ if self.dom is None: return
+ ctrl = xend.usbif_get(self.dom)
+ if ctrl:
+ log.debug("Destroying usbifs for domain %d", self.dom)
+ ctrl.destroy()
+
def show(self):
"""Print virtual machine info.
"""
@@ -712,7 +739,8 @@ class XendDomainInfo:
except:
raise VmError('invalid cpu')
cpu_weight = self.cpu_weight
- dom = xc.domain_create(dom= dom, mem_kb= memory * 1024,
+ memory = memory * 1024 + self.pgtable_size(memory)
+ dom = xc.domain_create(dom= dom, mem_kb= memory,
cpu= cpu, cpu_weight= cpu_weight)
if dom <= 0:
raise VmError('Creating domain failed: name=%s memory=%d'
@@ -720,7 +748,7 @@ class XendDomainInfo:
log.debug('init_domain> Created domain=%d name=%s memory=%d', dom, name, memory)
self.setdom(dom)
- def build_domain(self, ostype, kernel, ramdisk, cmdline):
+ def build_domain(self, ostype, kernel, ramdisk, cmdline, memmap):
"""Build the domain boot image.
"""
if self.recreate or self.restore: return
@@ -735,17 +763,29 @@ class XendDomainInfo:
flags = 0
if self.netif_backend: flags |= SIF_NET_BE_DOMAIN
if self.blkif_backend: flags |= SIF_BLK_BE_DOMAIN
- err = buildfn(dom = dom,
- image = kernel,
- control_evtchn = self.console.getRemotePort(),
- cmdline = cmdline,
- ramdisk = ramdisk,
- flags = flags)
+ if ostype == "vmx":
+ err = buildfn(dom = dom,
+ image = kernel,
+ control_evtchn = 0,
+ memsize = self.memory,
+ memmap = memmap,
+ cmdline = cmdline,
+ ramdisk = ramdisk,
+ flags = flags)
+ else:
+ log.warning('building dom with %d vcpus', self.vcpus)
+ err = buildfn(dom = dom,
+ image = kernel,
+ control_evtchn = self.console.getRemotePort(),
+ cmdline = cmdline,
+ ramdisk = ramdisk,
+ flags = flags,
+ vcpus = self.vcpus)
if err != 0:
raise VmError('Building domain failed: type=%s dom=%d err=%d'
% (ostype, dom, err))
- def create_domain(self, ostype, kernel, ramdisk, cmdline):
+ def create_domain(self, ostype, kernel, ramdisk, cmdline, memmap=''):
"""Create a domain. Builds the image but does not configure it.
@param ostype: OS type
@@ -760,7 +800,7 @@ class XendDomainInfo:
else:
self.console = xendConsole.console_create(
self.dom, console_port=self.console_port)
- self.build_domain(ostype, kernel, ramdisk, cmdline)
+ self.build_domain(ostype, kernel, ramdisk, cmdline, memmap)
self.image = kernel
self.ramdisk = ramdisk
self.cmdline = cmdline
@@ -804,6 +844,18 @@ class XendDomainInfo:
index[dev_name] = dev_index + 1
deferred = defer.DeferredList(dlist, fireOnOneErrback=1)
deferred.addErrback(dlist_err)
+ if self.is_vmx:
+ device_model = sxp.child_value(self.config, 'device_model')
+ device_config = sxp.child_value(self.config, 'device_config')
+ memory = sxp.child_value(self.config, "memory")
+ # Create an event channel
+ device_channel = channel.eventChannel(0, self.dom)
+ # Fork and exec device_model -f device_config <port>
+ os.system(device_model
+ + " -f %s" % device_config
+ + " -d %d" % self.dom
+ + " -p %d" % device_channel['port1']
+ + " -m %s &" % memory)
return deferred
def device_create(self, dev_config):
@@ -963,6 +1015,8 @@ class XendDomainInfo:
self.blkif_backend = 1
elif name == 'netif':
self.netif_backend = 1
+ elif name == 'usbif':
+ self.usbif_backend = 1
else:
raise VmError('invalid backend type:' + str(name))
@@ -1041,6 +1095,18 @@ class XendDomainInfo:
d.addErrback(dlist_err)
return d
+ def pgtable_size(self, memory):
+ """Return the size of memory needed for 1:1 page tables for physical
+ mode.
+
+ @param memory: size in MB
+ @return size in KB
+ """
+ if self.is_vmx:
+ # Logic x86-32 specific.
+ # 1 page for the PGD + 1 pte page for 4MB of memory (rounded)
+ return (1 + ((memory + 3) >> 2)) * 4
+ return 0
def vm_image_linux(vm, image):
"""Create a VM for a linux image.
@@ -1091,7 +1157,32 @@ def vm_image_plan9(vm, image):
vm.create_domain("plan9", kernel, ramdisk, cmdline)
return vm
-
+def vm_image_vmx(vm, image):
+ """Create a VM for the VMX environment.
+
+ @param name: vm name
+ @param memory: vm memory
+ @param image: image config
+ @return: vm
+ """
+ kernel = sxp.child_value(image, "kernel")
+ cmdline = ""
+ ip = sxp.child_value(image, "ip", "dhcp")
+ if ip:
+ cmdline += " ip=" + ip
+ root = sxp.child_value(image, "root")
+ if root:
+ cmdline += " root=" + root
+ args = sxp.child_value(image, "args")
+ if args:
+ cmdline += " " + args
+ ramdisk = sxp.child_value(image, "ramdisk", '')
+ memmap = sxp.child_value(vm.config, "memmap", '')
+ memmap = sxp.parse(open(memmap))[0]
+ from xen.util.memmap import memmap_parse
+ memmap = memmap_parse(memmap)
+ vm.create_domain("vmx", kernel, ramdisk, cmdline, memmap)
+ return vm
def vm_dev_vif(vm, val, index, change=0):
"""Create a virtual network interface (vif).
@@ -1117,6 +1208,23 @@ def vm_dev_vif(vm, val, index, change=0):
defer.addCallback(cbok)
return defer
+def vm_dev_usb(vm, val, index):
+ """Attach the relevant physical ports to the domains' USB interface.
+
+ @param vm: virtual machine
+ @param val: USB interface config
+ @param index: USB interface index
+ @return: deferred
+ """
+ ctrl = xend.usbif_create(vm.dom, recreate=vm.recreate)
+ log.debug("Creating USB interface dom=%d", vm.dom)
+ defer = ctrl.attachDevice(val, recreate=vm.recreate)
+ def cbok(path):
+ vm.add_device('usb', val[1][1])
+ return path
+ defer.addCallback(cbok)
+ return defer
+
def vm_dev_vbd(vm, val, index, change=0):
"""Create a virtual block device (vbd).
@@ -1215,11 +1323,13 @@ def vm_field_maxmem(vm, config, val, index):
# Register image handlers.
add_image_handler('linux', vm_image_linux)
add_image_handler('plan9', vm_image_plan9)
+add_image_handler('vmx', vm_image_vmx)
# Register device handlers.
add_device_handler('vif', vm_dev_vif)
add_device_handler('vbd', vm_dev_vbd)
add_device_handler('pci', vm_dev_pci)
+add_device_handler('usb', vm_dev_usb)
# Ignore the fields we already handle.
add_config_handler('name', vm_field_ignore)
@@ -1230,6 +1340,7 @@ add_config_handler('console', vm_field_ignore)
add_config_handler('image', vm_field_ignore)
add_config_handler('device', vm_field_ignore)
add_config_handler('backend', vm_field_ignore)
+add_config_handler('vcpus', vm_field_ignore)
# Register other config handlers.
add_config_handler('maxmem', vm_field_maxmem)
diff --git a/tools/python/xen/xend/server/SrvDaemon.py b/tools/python/xen/xend/server/SrvDaemon.py
index 338d6e4d4a..860848ace7 100644
--- a/tools/python/xen/xend/server/SrvDaemon.py
+++ b/tools/python/xen/xend/server/SrvDaemon.py
@@ -40,6 +40,7 @@ from xen.util.ip import _readline, _readlines
import channel
import blkif
import netif
+import usbif
import console
import domain
from params import *
@@ -118,9 +119,9 @@ class NotifierPort(abstract.FileDescriptor):
if hasattr(self, 'protocol'):
self.protocol.doStop()
self.connected = 0
- #self.notifier.close() # Not implemented.
- os.close(self.fileno())
- del self.notifier
+ #self.notifier.close() # (this said:) Not implemented.
+ #os.close(self.fileno()) # But yes it is...
+ del self.notifier # ...as _dealloc!
if hasattr(self, 'd'):
self.d.callback(None)
del self.d
@@ -261,6 +262,7 @@ class EventProtocol(protocol.Protocol):
val += self.daemon.consoles()
val += self.daemon.blkifs()
val += self.daemon.netifs()
+ val += self.daemon.usbifs()
return val
def op_sys_subscribe(self, name, v):
@@ -617,6 +619,7 @@ class Daemon:
self.domainCF = domain.DomainControllerFactory()
self.blkifCF = blkif.BlkifControllerFactory()
self.netifCF = netif.NetifControllerFactory()
+ self.usbifCF = usbif.UsbifControllerFactory()
self.consoleCF = console.ConsoleControllerFactory()
def listenEvent(self):
@@ -683,6 +686,15 @@ class Daemon:
def netif_get(self, dom):
return self.netifCF.getControllerByDom(dom)
+ def usbif_create(self, dom, recreate=0):
+ return self.usbifCF.getController(dom)
+
+ def usbifs(self):
+ return [ x.sxpr() for x in self.usbifCF.getControllers() ]
+
+ def usbif_get(self, dom):
+ return self.usbifCF.getControllerByDom(dom)
+
def console_create(self, dom, console_port=None):
"""Create a console for a domain.
"""
diff --git a/tools/python/xen/xend/server/SrvUsbif.py b/tools/python/xen/xend/server/SrvUsbif.py
new file mode 100644
index 0000000000..bdd57524ce
--- /dev/null
+++ b/tools/python/xen/xend/server/SrvUsbif.py
@@ -0,0 +1,249 @@
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+from twisted.protocols import http
+
+from xen.xend import sxp
+from xen.xend import XendDomain
+from xen.xend import XendConsole
+from xen.xend import PrettyPrint
+from xen.xend.Args import FormFn
+
+from SrvDir import SrvDir
+
+class SrvDomain(SrvDir):
+ """Service managing a single domain.
+ """
+
+ def __init__(self, dom):
+ SrvDir.__init__(self)
+ self.dom = dom
+ self.xd = XendDomain.instance()
+ self.xconsole = XendConsole.instance()
+
+ def op_configure(self, op, req):
+ """Configure an existing domain.
+ Configure is unusual in that it requires a domain id,
+ not a domain name.
+ """
+ fn = FormFn(self.xd.domain_configure,
+ [['dom', 'int'],
+ ['config', 'sxpr']])
+ deferred = fn(req.args, {'dom': self.dom.dom})
+ deferred.addErrback(self._op_configure_err, req)
+ return deferred
+
+ def _op_configure_err(self, err, req):
+ req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err))
+ return str(err)
+
+ def op_unpause(self, op, req):
+ val = self.xd.domain_unpause(self.dom.name)
+ return val
+
+ def op_pause(self, op, req):
+ val = self.xd.domain_pause(self.dom.name)
+ return val
+
+ def op_shutdown(self, op, req):
+ fn = FormFn(self.xd.domain_shutdown,
+ [['dom', 'str'],
+ ['reason', 'str']])
+ val = fn(req.args, {'dom': self.dom.id})
+ req.setResponseCode(http.ACCEPTED)
+ req.setHeader("Location", "%s/.." % req.prePathURL())
+ return val
+
+ def op_destroy(self, op, req):
+ fn = FormFn(self.xd.domain_destroy,
+ [['dom', 'str'],
+ ['reason', 'str']])
+ val = fn(req.args, {'dom': self.dom.id})
+ req.setHeader("Location", "%s/.." % req.prePathURL())
+ return val
+
+ def op_save(self, op, req):
+ fn = FormFn(self.xd.domain_save,
+ [['dom', 'str'],
+ ['file', 'str']])
+ deferred = fn(req.args, {'dom': self.dom.id})
+ deferred.addCallback(self._op_save_cb, req)
+ deferred.addErrback(self._op_save_err, req)
+ return deferred
+
+ def _op_save_cb(self, val, req):
+ return 0
+
+ def _op_save_err(self, err, req):
+ req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err))
+ return str(err)
+
+ def op_migrate(self, op, req):
+ fn = FormFn(self.xd.domain_migrate,
+ [['dom', 'str'],
+ ['destination', 'str'],
+ ['live', 'int']])
+ deferred = fn(req.args, {'dom': self.dom.id})
+ print 'op_migrate>', deferred
+ deferred.addCallback(self._op_migrate_cb, req)
+ deferred.addErrback(self._op_migrate_err, req)
+ return deferred
+
+ def _op_migrate_cb(self, info, req):
+ print '_op_migrate_cb>', info, req
+ #req.setResponseCode(http.ACCEPTED)
+ host = info.dst_host
+ port = info.dst_port
+ dom = info.dst_dom
+ url = "http://%s:%d/xend/domain/%d" % (host, port, dom)
+ req.setHeader("Location", url)
+ print '_op_migrate_cb> url=', url
+ return url
+
+ def _op_migrate_err(self, err, req):
+ print '_op_migrate_err>', err, req
+ req.setResponseCode(http.BAD_REQUEST, "Error: "+ str(err))
+ return str(err)
+
+ def op_pincpu(self, op, req):
+ fn = FormFn(self.xd.domain_pincpu,
+ [['dom', 'str'],
+ ['cpu', 'int']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_cpu_bvt_set(self, op, req):
+ fn = FormFn(self.xd.domain_cpu_bvt_set,
+ [['dom', 'str'],
+ ['mcuadv', 'int'],
+ ['warpback', 'int'],
+ ['warpvalue', 'int'],
+ ['warpl', 'long'],
+ ['warpu', 'long']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_cpu_fbvt_set(self, op, req):
+ fn = FormFn(self.xd.domain_cpu_fbvt_set,
+ [['dom', 'str'],
+ ['mcuadv', 'int'],
+ ['warp', 'int'],
+ ['warpl', 'int'],
+ ['warpu', 'int']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_cpu_atropos_set(self, op, req):
+ fn = FormFn(self.xd.domain_cpu_atropos_set,
+ [['dom', 'str'],
+ ['period', 'int'],
+ ['slice', 'int'],
+ ['latency', 'int'],
+ ['xtratime', 'int']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_maxmem_set(self, op, req):
+ fn = FormFn(self.xd.domain_maxmem_set,
+ [['dom', 'str'],
+ ['memory', 'int']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_device_create(self, op, req):
+ fn = FormFn(self.xd.domain_device_create,
+ [['dom', 'str'],
+ ['config', 'sxpr']])
+ d = fn(req.args, {'dom': self.dom.id})
+ return d
+
+ def op_device_destroy(self, op, req):
+ fn = FormFn(self.xd.domain_device_destroy,
+ [['dom', 'str'],
+ ['type', 'str'],
+ ['idx', 'str']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_vifs(self, op, req):
+ devs = self.xd.domain_vif_ls(self.dom.id)
+ return [ dev.sxpr() for dev in devs ]
+
+ def op_vif(self, op, req):
+ fn = FormFn(self.xd.domain_vif_get,
+ [['dom', 'str'],
+ ['vif', 'str']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def op_vbds(self, op, req):
+ devs = self.xd.domain_vbd_ls(self.dom.id)
+ return [ dev.sxpr() for dev in devs ]
+
+ def op_vbd(self, op, req):
+ fn = FormFn(self.xd.domain_vbd_get,
+ [['dom', 'str'],
+ ['vbd', 'str']])
+ val = fn(req.args, {'dom': self.dom.id})
+ return val
+
+ def render_POST(self, req):
+ return self.perform(req)
+
+ def render_GET(self, req):
+ op = req.args.get('op')
+ if op and op[0] in ['vifs', 'vif', 'vbds', 'vbd']:
+ return self.perform(req)
+ if self.use_sxp(req):
+ req.setHeader("Content-Type", sxp.mime_type)
+ sxp.show(self.dom.sxpr(), out=req)
+ else:
+ req.write('<html><head></head><body>')
+ self.print_path(req)
+ #self.ls()
+ req.write('<p>%s</p>' % self.dom)
+ if self.dom.console:
+ cinfo = self.dom.console
+ cid = str(cinfo.console_port)
+ #todo: Local xref: need to know server prefix.
+ req.write('<p><a href="/xend/console/%s">Console %s</a></p>'
+ % (cid, cid))
+ req.write('<p><a href="%s">Connect to console</a></p>'
+ % cinfo.uri())
+ if self.dom.config:
+ req.write("<code><pre>")
+ PrettyPrint.prettyprint(self.dom.config, out=req)
+ req.write("</pre></code>")
+ self.form(req)
+ req.write('</body></html>')
+ return ''
+
+ def form(self, req):
+ url = req.prePathURL()
+ req.write('<form method="post" action="%s">' % url)
+ req.write('<input type="submit" name="op" value="unpause">')
+ req.write('<input type="submit" name="op" value="pause">')
+ req.write('</form>')
+
+ req.write('<form method="post" action="%s">' % url)
+ req.write('<input type="submit" name="op" value="destroy">')
+ req.write('<input type="radio" name="reason" value="halt" checked>Halt')
+ req.write('<input type="radio" name="reason" value="reboot">Reboot')
+ req.write('</form>')
+
+ req.write('<form method="post" action="%s">' % url)
+ req.write('<input type="submit" name="op" value="shutdown">')
+ req.write('<input type="radio" name="reason" value="poweroff" checked>Poweroff')
+ req.write('<input type="radio" name="reason" value="halt">Halt')
+ req.write('<input type="radio" name="reason" value="reboot">Reboot')
+ req.write('</form>')
+
+ req.write('<form method="post" action="%s">' % url)
+ req.write('<br><input type="submit" name="op" value="save">')
+ req.write(' To file: <input type="text" name="file">')
+ req.write('</form>')
+
+ req.write('<form method="post" action="%s">' % url)
+ req.write('<br><input type="submit" name="op" value="migrate">')
+ req.write(' To host: <input type="text" name="destination">')
+ req.write('<input type="checkbox" name="live" value="1">Live')
+ req.write('</form>')
diff --git a/tools/python/xen/xend/server/channel.py b/tools/python/xen/xend/server/channel.py
index 127f38f2c0..6dfebe37be 100755
--- a/tools/python/xen/xend/server/channel.py
+++ b/tools/python/xen/xend/server/channel.py
@@ -171,8 +171,10 @@ class VirqChannel(BaseChannel):
"""
BaseChannel.__init__(self, factory)
self.virq = virq
+ self.factory = factory
# Notification port (int).
- self.port = xc.evtchn_bind_virq(virq)
+ #self.port = xc.evtchn_bind_virq(virq)
+ self.port = factory.notifier.bind_virq(virq)
self.idx = self.port
# Clients to call when a virq arrives.
self.clients = []
@@ -208,7 +210,8 @@ class VirqChannel(BaseChannel):
c.virqReceived(self.virq)
def notify(self):
- xc.evtchn_send(self.port)
+ # xc.evtchn_send(self.port)
+ self.factory.notifier.virq_send(self.port)
class Channel(BaseChannel):
@@ -279,6 +282,7 @@ class Channel(BaseChannel):
self.devs.append(dev)
for ty in types:
self.devs_by_type[ty] = dev
+ self.port.register(ty)
def deregisterDevice(self, dev):
"""Remove the registration for a device controller.
@@ -290,6 +294,7 @@ class Channel(BaseChannel):
types = [ ty for (ty, d) in self.devs_by_type.items() if d == dev ]
for ty in types:
del self.devs_by_type[ty]
+ self.port.deregister(ty)
def getDevice(self, type):
"""Get the device controller handling a message type.
diff --git a/tools/python/xen/xend/server/messages.py b/tools/python/xen/xend/server/messages.py
index 35f9db986e..4f9f9119a2 100644
--- a/tools/python/xen/xend/server/messages.py
+++ b/tools/python/xen/xend/server/messages.py
@@ -189,6 +189,70 @@ netif_formats = {
msg_formats.update(netif_formats)
#============================================================================
+# USB interface message types.
+#============================================================================
+
+CMSG_USBIF_BE = 8
+CMSG_USBIF_FE = 9
+
+CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED = 0
+
+CMSG_USBIF_FE_DRIVER_STATUS_CHANGED = 32
+CMSG_USBIF_FE_INTERFACE_CONNECT = 33
+CMSG_USBIF_FE_INTERFACE_DISCONNECT = 34
+
+USBIF_DRIVER_STATUS_DOWN = 0
+USBIF_DRIVER_STATUS_UP = 1
+
+USBIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */
+USBIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */
+USBIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */
+
+CMSG_USBIF_BE_CREATE = 0
+CMSG_USBIF_BE_DESTROY = 1
+CMSG_USBIF_BE_CONNECT = 2
+
+CMSG_USBIF_BE_DISCONNECT = 3
+CMSG_USBIF_BE_CLAIM_PORT = 4
+CMSG_USBIF_BE_RELEASE_PORT = 5
+
+CMSG_USBIF_BE_DRIVER_STATUS_CHANGED = 32
+
+USBIF_BE_STATUS_OKAY = 0
+USBIF_BE_STATUS_ERROR = 1
+
+USBIF_BE_STATUS_INTERFACE_EXISTS = 2
+USBIF_BE_STATUS_INTERFACE_NOT_FOUND = 3
+USBIF_BE_STATUS_INTERFACE_CONNECTED = 4
+USBIF_BE_STATUS_OUT_OF_MEMORY = 7
+USBIF_BE_STATUS_MAPPING_ERROR = 9
+
+usbif_formats = {
+ 'usbif_be_create_t':
+ (CMSG_USBIF_BE, CMSG_USBIF_BE_CREATE),
+ 'usbif_be_destroy_t':
+ (CMSG_USBIF_BE, CMSG_USBIF_BE_DESTROY),
+ 'usbif_be_connect_t':
+ (CMSG_USBIF_BE, CMSG_USBIF_BE_CONNECT),
+ 'usbif_be_disconnect_t':
+ (CMSG_USBIF_BE, CMSG_USBIF_BE_DISCONNECT),
+ 'usbif_be_claim_port_t':
+ (CMSG_USBIF_BE, CMSG_USBIF_BE_CLAIM_PORT),
+ 'usbif_be_release_port_t':
+ (CMSG_USBIF_BE, CMSG_USBIF_BE_RELEASE_PORT),
+ 'usbif_fe_interface_status_changed_t':
+ (CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED),
+ 'usbif_fe_driver_status_changed_t':
+ (CMSG_USBIF_FE, CMSG_USBIF_FE_DRIVER_STATUS_CHANGED),
+ 'usbif_fe_interface_connect_t':
+ (CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_CONNECT),
+ 'usbif_fe_interface_disconnect_t':
+ (CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_DISCONNECT)
+ }
+
+msg_formats.update(usbif_formats)
+
+#============================================================================
# Domain shutdown message types.
#============================================================================
@@ -266,9 +330,9 @@ def packMsg(ty, params):
(major, minor) = msg_formats[ty]
args = {}
for (k, v) in params.items():
- if k == 'mac':
+ if k in ['mac', 'be_mac']:
for i in range(0, 6):
- args['mac[%d]' % i] = v[i]
+ args['%s[%d]' % (k, i)] = v[i]
else:
args[k] = v
msg = xu.message(major, minor, msgid, args)
diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py
index d63c342435..00ad1f138b 100755
--- a/tools/python/xen/xend/server/netif.py
+++ b/tools/python/xen/xend/server/netif.py
@@ -109,7 +109,14 @@ class NetDev(controller.SplitDev):
vmac = sxp.child_value(config, 'mac')
if not vmac: return None
mac = [ int(x, 16) for x in vmac.split(':') ]
- if len(mac) != 6: raise XendError("invalid mac")
+ if len(mac) != 6: raise XendError("invalid mac: %s" % vmac)
+ return mac
+
+ def _get_config_be_mac(self, config):
+ vmac = sxp.child_value(config, 'be_mac')
+ if not vmac: return None
+ mac = [ int(x, 16) for x in vmac.split(':') ]
+ if len(mac) != 6: raise XendError("invalid backend mac: %s" % vmac)
return mac
def _get_config_ipaddr(self, config):
@@ -127,6 +134,7 @@ class NetDev(controller.SplitDev):
return self.reconfigure(config)
self.config = config
self.mac = None
+ self.be_mac = None
self.bridge = None
self.script = None
self.ipaddr = []
@@ -135,6 +143,7 @@ class NetDev(controller.SplitDev):
if mac is None:
raise XendError("invalid mac")
self.mac = mac
+ self.be_mac = self._get_config_be_mac(config)
self.bridge = sxp.child_value(config, 'bridge')
self.script = sxp.child_value(config, 'script')
self.ipaddr = self._get_config_ipaddr(config) or []
@@ -159,6 +168,7 @@ class NetDev(controller.SplitDev):
"""
changes = {}
mac = self._get_config_mac(config)
+ be_mac = self._get_config_be_mac(config)
bridge = sxp.child_value(config, 'bridge')
script = sxp.child_value(config, 'script')
ipaddr = self._get_config_ipaddr(config)
@@ -166,6 +176,8 @@ class NetDev(controller.SplitDev):
backendDomain = str(xd.domain_lookup(sxp.child_value(config, 'backend', '0')).id)
if (mac is not None) and (mac != self.mac):
raise XendError("cannot change mac")
+ if (be_mac is not None) and (be_mac != self.be_mac):
+ raise XendError("cannot change backend mac")
if (backendDomain is not None) and (backendDomain != str(self.backendDomain)):
raise XendError("cannot change backend")
if (bridge is not None) and (bridge != self.bridge):
@@ -190,6 +202,8 @@ class NetDev(controller.SplitDev):
['idx', self.idx],
['vif', vif],
['mac', mac]]
+ if self.be_mac:
+ val.append(['be_mac', self.get_be_mac()])
if self.bridge:
val.append(['bridge', self.bridge])
if self.script:
@@ -214,6 +228,11 @@ class NetDev(controller.SplitDev):
"""
return ':'.join(map(lambda x: "%02x" % x, self.mac))
+ def get_be_mac(self):
+ """Get the backend MAC address as a string.
+ """
+ return ':'.join(map(lambda x: "%02x" % x, self.be_mac))
+
def vifctl_params(self, vmname=None):
"""Get the parameters to pass to vifctl.
"""
@@ -267,6 +286,7 @@ class NetDev(controller.SplitDev):
msg = packMsg('netif_be_create_t',
{ 'domid' : self.controller.dom,
'netif_handle' : self.vif,
+ 'be_mac' : self.be_mac or [0, 0, 0, 0, 0, 0],
'mac' : self.mac })
self.getBackendInterface().writeRequest(msg, response=d)
return d
diff --git a/tools/python/xen/xend/server/usbif.py b/tools/python/xen/xend/server/usbif.py
new file mode 100644
index 0000000000..d90997634b
--- /dev/null
+++ b/tools/python/xen/xend/server/usbif.py
@@ -0,0 +1,368 @@
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+# Copyright (C) 2004 Intel Research Cambridge
+# Copyright (C) 2004 Mark Williamson <mark.williamson@cl.cam.ac.uk>
+"""Support for virtual USB hubs.
+"""
+
+from twisted.internet import defer
+#defer.Deferred.debug = 1
+
+from xen.xend import sxp
+from xen.xend.XendLogging import log
+from xen.xend.XendError import XendError
+
+import channel
+import controller
+from messages import *
+
+class UsbifBackendController(controller.BackendController):
+ """ Handler for the 'back-end' channel to a USB hub domain.
+ Must be connected using connect() before it can be used.
+ Do not create directly - use getBackend() on the UsbifController.
+ """
+
+ def __init__(self, ctrl, dom):
+ controller.BackendController.__init__(self, ctrl, dom)
+ self.connected = 0
+ self.evtchn = None
+ self.addMethod(CMSG_USBIF_BE,
+ CMSG_USBIF_BE_DRIVER_STATUS_CHANGED,
+ self.recv_be_driver_status_changed)
+ self.registerChannel()
+
+ def __str__(self):
+ return '<UsbifBackendController %d>' % (self.dom)
+
+ def recv_be_driver_status_changed(self, msg, req):
+ """Request handler for be_driver_status_changed messages.
+
+ @param msg: message
+ @type msg: xu message
+ @param req: request flag (true if the msg is a request)
+ @type req: bool
+ """
+ val = unpackMsg('usbif_be_driver_status_changed_t', msg)
+ status = val['status']
+
+class UsbifBackendInterface(controller.BackendInterface):
+ """Handler for the 'back-end' channel to a network device driver domain
+ on behalf of a front-end domain.
+
+ Each network device is handled separately, so we add no functionality
+ here.
+ """
+ def __init__(self, ctrl, dom):
+ controller.BackendInterface.__init__(self, ctrl, dom, 0)
+ self.connected = 0
+ self.connecting = False
+
+ def connect(self, recreate=0):
+ """Connect the controller to the usbif control interface.
+
+ @param recreate: true if after xend restart
+ @return: deferred
+ """
+ log.debug("Connecting usbif %s", str(self))
+ if recreate or self.connected or self.connecting:
+ d = defer.succeed(self)
+ else:
+ self.connecting = True
+ d = self.send_be_create()
+ d.addCallback(self.respond_be_create)
+ return d
+
+ def send_be_create(self):
+ d = defer.Deferred()
+ msg = packMsg('usbif_be_create_t',
+ { 'domid' : self.controller.dom })
+ self.writeRequest(msg, response=d)
+ return d
+
+ def respond_be_create(self, msg):
+ val = unpackMsg('usbif_be_create_t', msg)
+ log.debug('>UsbifBackendController>respond_be_create> %s', str(val))
+ self.connected = True
+ return self
+
+ def destroy(self):
+ """Disconnect from the usbif control interface and destroy it.
+ """
+ def cb_destroy(val):
+ self.send_be_destroy()
+ d = defer.Deferred()
+ d.addCallback(cb_destroy)
+ self.send_be_disconnect(response=d)
+
+ def send_be_disconnect(self, response=None):
+ log.debug('>UsbifBackendController>send_be_disconnect> %s', str(self))
+ msg = packMsg('usbif_be_disconnect_t',
+ { 'domid' : self.controller.dom })
+ self.writeRequest(msg, response=response)
+
+ def send_be_destroy(self, response=None):
+ log.debug('>UsbifBackendController>send_be_destroy> %s', str(self))
+ msg = packMsg('usbif_be_destroy_t',
+ { 'domid' : self.controller.dom })
+ self.writeRequest(msg, response=response)
+
+ def send_be_claim_port(self, path):
+ d=defer.Deferred()
+ log.debug(">UsbifBackendController>send_be_claim_port> about to claim port %s" % path)
+ def cb(blah): log.debug(">UsbifBackendController> Claim port completed")
+ d.addCallback(cb)
+ msg = packMsg('usbif_be_claim_port_t',
+ { 'domid' : self.controller.dom,
+ 'path' : path,
+ 'usbif_port' : self.controller.devices[path],
+ 'status' : 0})
+ self.writeRequest(msg, response=d)
+ # No need to add any callbacks, since the guest polls its virtual ports
+ # anyhow, somewhat like a UHCI controller ;-)
+ return d
+
+ def send_be_release_port(self, path):
+ d=defer.Deferred()
+ def cb(blah): log.debug(">UsbifBackendController> Release port completed")
+ d.addCallback(cb)
+ msg = packMsg('usbif_be_release_port_t',
+ { 'domid' : self.controller.dom,
+ 'path' : path })
+ self.writeRequest(msg, response)
+ # No need to add any callbacks, since the guest polls its virtual ports
+ # anyhow, somewhat like a UHCI controller ;-)
+
+ def connectInterface(self, val):
+ self.evtchn = channel.eventChannel(0, self.controller.dom)
+ log.debug(">UsbifBackendController>connectInterface> connecting usbif to event channel %s ports=%d:%d",
+ str(self), self.evtchn['port1'], self.evtchn['port2'])
+ msg = packMsg('usbif_be_connect_t',
+ { 'domid' : self.controller.dom,
+ 'evtchn' : self.evtchn['port1'],
+ 'shmem_frame' : val['shmem_frame'],
+ 'bandwidth' : 500 # XXX fix bandwidth!
+ })
+ d = defer.Deferred()
+ d.addCallback(self.respond_be_connect)
+ self.writeRequest(msg, response=d)
+
+ def respond_be_connect(self, msg):
+ """Response handler for a be_connect message.
+
+ @param msg: message
+ @type msg: xu message
+ """
+ val = unpackMsg('usbif_be_connect_t', msg)
+ log.debug('>UsbifBackendController>respond_be_connect> %s, %s', str(self), str(val))
+ d = defer.Deferred()
+ def cb(blah):
+ log.debug(">UsbifBackendController> Successfully connected USB interface for domain %d" % self.controller.dom)
+ self.controller.claim_ports()
+ d.addCallback(cb)
+ self.send_fe_interface_status_changed(d)
+
+ def send_fe_interface_status_changed(self, response=None):
+ msg = packMsg('usbif_fe_interface_status_changed_t',
+ { 'status' : USBIF_INTERFACE_STATUS_CONNECTED,
+ 'domid' : 0, ## FIXME: should be domid of backend
+ 'evtchn' : self.evtchn['port2'],
+ 'bandwidth' : 500,
+ 'num_ports' : len(self.controller.devices.keys())})
+ self.controller.writeRequest(msg, response=response)
+
+
+class UsbifControllerFactory(controller.SplitControllerFactory):
+ """Factory for creating USB interface controllers.
+ """
+
+ def __init__(self):
+ controller.ControllerFactory.__init__(self)
+ self.backendControllers = {}
+
+ def createController(self, dom, recreate=0):
+ """Create a USB device controller for a domain.
+
+ @param dom: domain
+ @type dom: int
+ @param recreate: if true it's a recreate (after xend restart)
+ @type recreate: bool
+ @return: block device controller
+ @rtype: UsbifController
+ """
+ usbif = self.getControllerByDom(dom)
+ if usbif is None:
+ usbif = UsbifController(self, dom)
+ self.addController(usbif)
+ return usbif
+
+ def getDomainDevices(self, dom):
+ """Get the block devices for a domain.
+
+ @param dom: domain
+ @type dom: int
+ @return: devices
+ @rtype: [device]
+ """
+ usbif = self.getControllerByDom(dom)
+ return (usbif and usbif.getDevices()) or []
+
+ def getDomainDevice(self, dom, vdev):
+ """Get a block device from a domain.
+
+ @param dom: domain
+ @type dom: int
+ @param vdev: device index
+ @type vdev: int
+ @return: device
+ @rtype: device
+ """
+ usbif = self.getControllerByDom(dom)
+ return (usbif and usbif.getDevice(vdev)) or None
+
+ def createBackendInterface(self, ctrl, dom, handle):
+ """Create a network device backend interface.
+
+ @param ctrl: controller
+ @param dom: backend domain
+ @param handle: interface handle
+ @return: backend interface
+ """
+ return UsbifBackendInterface(ctrl, dom)
+
+ def getBackendController(self, dom):
+ """Get the backend controller for a domain, creating
+ if necessary.
+
+ @param dom: backend domain
+ @return: backend controller
+ """
+ b = self.getBackendControllerByDomain(dom)
+ if b is None:
+ b = self.createBackendController(dom)
+ self.backendControllers[b.dom] = b
+ return b
+
+ def createBackendController(self, dom):
+ return UsbifBackendController(self, dom)
+
+class UsbifController(controller.SplitController):
+ """USB device interface controller. Handles all USB devices
+ for a domain.
+ """
+
+ def __init__(self, factory, dom):
+ """Create a USB device controller.
+ Do not call directly - use createController() on the factory instead.
+ """
+ controller.SplitController.__init__(self, factory, dom)
+ self.num_ports = 0
+ self.devices = {}
+ self.addMethod(CMSG_USBIF_FE,
+ CMSG_USBIF_FE_DRIVER_STATUS_CHANGED,
+ self.recv_fe_driver_status_changed)
+ self.addMethod(CMSG_USBIF_FE,
+ CMSG_USBIF_FE_INTERFACE_CONNECT,
+ self.recv_fe_interface_connect)
+ self.registerChannel()
+ try:
+ self.backendDomain = 0 #int(sxp.child_value(config, 'backend', '0')) TODO: configurable backends
+ except:
+ raise XendError('invalid backend domain')
+
+
+ def sxpr(self):
+ val = ['usbif', ['dom', self.dom]]
+ return val
+
+ def createBackend(self, dom, handle):
+ return UsbifBackendController(self, dom, handle)
+
+ def getDevices(self):
+ return self.devices.values()
+
+ def attachDevice(self, path, recreate=0):
+ """Add privileges for a particular device to the domain.
+ @param path: the Linux-style path to the device port
+ """
+ self.devices[path[1][1]] = self.num_ports
+ self.num_ports += 1
+ log.debug(">UsbifController>attachDevice> device: %s, port: %d" %
+ (str(path), self.num_ports ) )
+
+ backend =self.getBackendInterface(self.backendDomain)
+
+ def cb(blah):
+ log.debug(">UsbifController> Backend created")
+ pass
+ d = backend.connect()
+ d.addCallback(cb) # Chaining the claim port operation
+ return d
+
+
+ def removeDevice(self, path):
+ self.delDevice(path)
+ backend = self.getBackendInterface(self.backendDomain)
+ return backend.send_be_release_port(path)
+
+ def delDevice(self, path):
+ if path in self.devices:
+ del self.devices[path]
+
+ def attachPort(self, path, recreate=0):
+ """Attach a device to the specified interface.
+ On success the returned deferred will be called with the device.
+
+ @return: deferred
+ @rtype: Deferred
+ """
+ return self.attachDevice(path)
+
+ def destroy(self):
+ """Destroy the controller and all devices.
+ """
+ log.debug("Destroying usbif domain=%d", self.dom)
+ self.destroyBackends()
+
+ def destroyDevices(self):
+ """Destroy all devices.
+ """
+ for path in self.getDevices():
+ self.removeDevice(path)
+
+ def destroyBackends(self):
+ for backend in self.getBackendInterfaces():
+ backend.destroy()
+
+ def recv_fe_driver_status_changed(self, msg, req):
+ val = unpackMsg('usbif_fe_driver_status_changed_t', msg)
+ log.debug('>UsbifController>recv_fe_driver_status_changed> %s', str(val))
+ # For each backend?
+ msg = packMsg('usbif_fe_interface_status_changed_t',
+ { 'status' : USBIF_INTERFACE_STATUS_DISCONNECTED,
+ 'domid' : 0, ## FIXME: should be domid of backend
+ 'evtchn' : 0 })
+ d = defer.Deferred()
+ d.addCallback(self.disconnected_resp)
+ self.writeRequest(msg)
+
+ def disconnected_resp(self, msg):
+ val = unpackMsg('usbif_fe_interface_status_changed_t', msg)
+ if val['status'] != USBIF_INTERFACE_STATUS_DISCONNECTED:
+ log.error(">UsbifController>disconnected_resp> unexpected status change")
+ else:
+ log.debug(">UsbifController>disconnected_resp> interface disconnected OK")
+
+ def recv_fe_interface_connect(self, msg, req):
+ val = unpackMsg('usbif_fe_interface_status_changed_t', msg)
+ log.debug(">UsbifController>recv_fe_interface_connect> notifying backend")
+ backend = self.getBackendInterfaceByHandle(0)
+ if backend:
+ d = backend.connectInterface(val)
+ else:
+ log.error('>UsbifController>recv_fe_interface_connect> unknown interface')
+
+ def claim_ports(self):
+ backend = self.getBackendInterfaceByHandle(0)
+ for path in self.devices.keys():
+ log.debug(">UsbifController>claim_ports> claiming port... %s" % path)
+ backend.send_be_claim_port(path)
+
diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py
index 03f815eddb..e79e02383c 100644
--- a/tools/python/xen/xm/create.py
+++ b/tools/python/xen/xm/create.py
@@ -109,6 +109,10 @@ gopts.var('cpu', val='CPU',
fn=set_int, default=None,
use="CPU to run the domain on.")
+gopts.var('vcpus', val='VCPUS',
+ fn=set_int, default=1,
+ use="# of Virtual CPUS in domain.")
+
gopts.var('cpu_weight', val='WEIGHT',
fn=set_float, default=None,
use="""Set the new domain's cpu weight.
@@ -147,15 +151,22 @@ gopts.var('pci', val='BUS,DEV,FUNC',
For example '-pci c0,02,1a'.
The option may be repeated to add more than one pci device.""")
+gopts.var('usb', val='PATH',
+ fn=append_value, default=[],
+ use="""Add a physical USB port to a domain, as specified by the path
+ to that port. This option may be repeated to add more than one port.""")
+
gopts.var('ipaddr', val="IPADDR",
fn=append_value, default=[],
use="Add an IP address to the domain.")
-gopts.var('vif', val="mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM",
+gopts.var('vif', val="mac=MAC,be_mac=MAC,bridge=BRIDGE,script=SCRIPT,backend=DOM",
fn=append_value, default=[],
use="""Add a network interface with the given MAC address and bridge.
The vif is configured by calling the given configuration script.
If mac is not specified a random MAC address is used.
+ The MAC address of the backend interface can be selected with be_mac.
+ If not specified then the network backend chooses it's own MAC address.
If bridge is not specified the default bridge is used.
If script is not specified the default script is used.
If backend is not specified the default backend driver domain is used.
@@ -210,6 +221,18 @@ gopts.var('nfs_root', val="PATH",
fn=set_value, default=None,
use="Set the path of the root NFS directory.")
+gopts.var('memmap', val='FILE',
+ fn=set_value, default='',
+ use="Path to memap SXP file.")
+
+gopts.var('device_model', val='FILE',
+ fn=set_value, default='',
+ use="Path to device model program.")
+
+gopts.var('device_config', val='FILE',
+ fn=set_value, default='',
+ use="Path to device model configuration.")
+
def strip(pre, s):
"""Strip prefix 'pre' if present.
"""
@@ -233,7 +256,10 @@ def configure_image(config, vals):
config_image.append(['root', cmdline_root])
if vals.extra:
config_image.append(['args', vals.extra])
+ if vals.vcpus:
+ config_image.append(['vcpus', vals.vcpus])
config.append(['image', config_image ])
+
def configure_disks(config_devs, vals):
"""Create the config for disks (virtual block devices).
@@ -254,6 +280,11 @@ def configure_pci(config_devs, vals):
config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
config_devs.append(['device', config_pci])
+def configure_usb(config_devs, vals):
+ for path in vals.usb:
+ config_usb = ['usb', ['path', path]]
+ config_devs.append(['device', config_usb])
+
def randomMAC():
"""Generate a random MAC address.
@@ -285,18 +316,22 @@ def configure_vifs(config_devs, vals):
mac = d.get('mac')
if not mac:
mac = randomMAC()
+ be_mac = d.get('be_mac')
bridge = d.get('bridge')
script = d.get('script')
backend = d.get('backend')
ip = d.get('ip')
else:
mac = randomMAC()
+ be_mac = None
bridge = None
script = None
backend = None
ip = None
config_vif = ['vif']
config_vif.append(['mac', mac])
+ if be_mac:
+ config_vif.append(['be_mac', be_mac])
if bridge:
config_vif.append(['bridge', bridge])
if script:
@@ -315,6 +350,15 @@ def configure_vfr(config, vals):
config_vfr.append(['vif', ['id', idx], ['ip', ip]])
config.append(config_vfr)
+def configure_vmx(config_devs, vals):
+ """Create the config for VMX devices.
+ """
+ memmap = vals.memmap
+ device_model = vals.device_model
+ device_config = vals.device_config
+ config_devs.append(['memmap', memmap])
+ config_devs.append(['device_model', device_model])
+ config_devs.append(['device_config', device_config])
def make_config(vals):
"""Create the domain configuration.
@@ -343,6 +387,8 @@ def make_config(vals):
configure_disks(config_devs, vals)
configure_pci(config_devs, vals)
configure_vifs(config_devs, vals)
+ configure_usb(config_devs, vals)
+ configure_vmx(config_devs, vals)
config += config_devs
return config
@@ -383,7 +429,7 @@ def preprocess_vifs(opts, vals):
(k, v) = b.strip().split('=', 1)
k = k.strip()
v = v.strip()
- if k not in ['mac', 'bridge', 'script', 'backend', 'ip']:
+ if k not in ['mac', 'be_mac', 'bridge', 'script', 'backend', 'ip']:
opts.err('Invalid vif specifier: ' + vif)
d[k] = v
vifs.append(d)
diff --git a/tools/xcs/Makefile b/tools/xcs/Makefile
new file mode 100644
index 0000000000..b24f81101b
--- /dev/null
+++ b/tools/xcs/Makefile
@@ -0,0 +1,48 @@
+# Makefile for XCS
+# Andrew Warfield, 2004
+
+XEN_ROOT=../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+XCS_INSTALL_DIR = /usr/sbin
+
+INSTALL = install
+INSTALL_PROG = $(INSTALL) -m0755
+INSTALL_DIR = $(INSTALL) -d -m0755
+
+CC = gcc
+CFLAGS = -Wall -Werror -g3 -D _XOPEN_SOURCE=600
+
+CFLAGS += -I $(XEN_XC)
+CFLAGS += -I $(XEN_LIBXC)
+CFLAGS += -I $(XEN_LIBXUTIL)
+
+SRCS :=
+SRCS += ctrl_interface.c
+SRCS += bindings.c
+SRCS += connection.c
+SRCS += evtchn.c
+SRCS += xcs.c
+
+HDRS = $(wildcard *.h)
+OBJS = $(patsubst %.c,%.o,$(SRCS))
+BIN = xcs
+
+all: $(BIN) xcsdump
+
+clean:
+ $(RM) *.a *.so *.o *.rpm $(BIN) ctrl_dump
+
+xcsdump: xcsdump.c
+ $(CC) $(CFLAGS) -o xcsdump xcsdump.c -L$(XEN_LIBXC) -L$(XEN_LIBXUTIL) \
+ ctrl_interface.c evtchn.c -lxc -lxutil
+
+$(BIN): $(OBJS)
+ $(CC) $(CFLAGS) $^ -o $@ -L$(XEN_LIBXC) -L$(XEN_LIBXUTIL) -lxc -lxutil
+
+install: xcs xcsdump
+ $(INSTALL_DIR) -p $(DESTDIR)/$(XCS_INSTALL_DIR)
+ $(INSTALL_DIR) -p $(DESTDIR)/usr/include
+ $(INSTALL_PROG) xcs $(DESTDIR)/$(XCS_INSTALL_DIR)
+ $(INSTALL_PROG) xcsdump $(DESTDIR)/$(XCS_INSTALL_DIR)
+ $(INSTALL_PROG) xcs_proto.h $(DESTDIR)/usr/include
diff --git a/tools/xcs/bindings.c b/tools/xcs/bindings.c
new file mode 100644
index 0000000000..9b09f51568
--- /dev/null
+++ b/tools/xcs/bindings.c
@@ -0,0 +1,179 @@
+/* bindings.c
+ *
+ * Manage subscriptions for the control interface switch.
+ *
+ * (c) 2004, Andrew Warfield
+ *
+ */
+
+/* Interfaces:
+ *
+ * xcs_bind (port, type, connection)
+ * - Register connection to receive messages of this type.
+ * xcs_unbind (port, type, connection)
+ * - Remove an existing registration. (Must be an exact match)
+ * xcs_lookup (port, type)
+ * - Return a list of connections matching a registration.
+ *
+ * - All connections have a connection.bindings list of current bindings.
+ * - (port, type) pairs may be wildcarded with -1.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include "xcs.h"
+
+
+typedef struct binding_ent_st {
+ connection_t *con;
+ struct binding_ent_st *next;
+} binding_ent_t;
+
+#define BINDING_TABLE_SIZE 1024
+
+static binding_ent_t *binding_table[BINDING_TABLE_SIZE];
+
+#define PORT_WILD(_ent) ((_ent)->port == PORT_WILDCARD)
+#define TYPE_WILD(_ent) ((_ent)->type == TYPE_WILDCARD)
+#define FULLY_WILD(_ent) (PORT_WILD(_ent) && TYPE_WILD(_ent))
+
+#define BINDING_HASH(_key) \
+ ((((_key)->port * 11) ^ (_key)->type) % BINDING_TABLE_SIZE)
+
+
+void init_bindings(void)
+{
+ memset(binding_table, 0, sizeof(binding_table));
+}
+
+static int table_add(binding_ent_t *table[],
+ connection_t *con,
+ binding_key_t *key)
+{
+ binding_ent_t **curs, *ent;
+
+ curs = &table[BINDING_HASH(key)];
+
+ while (*curs != NULL) {
+ if ((*curs)->con == con) {
+ DPRINTF("Tried to add an ent that already existed.\n");
+ goto done;
+ }
+ curs = &(*curs)->next;
+ }
+
+ if (connection_add_binding(con, key) != 0)
+ {
+ DPRINTF("couldn't add binding on connection (%lu)\n", con->id);
+ goto fail;
+ }
+ ent = (binding_ent_t *)malloc(sizeof(binding_ent_t));
+ if (ent == 0) {
+ DPRINTF("couldn't alloc binding ent!\n");
+ goto fail;
+ }
+ ent->con = con;
+ ent->next = NULL;
+ *curs = ent;
+
+done:
+ return 0;
+
+fail:
+ return -1;
+}
+
+
+static inline int binding_has_colliding_hashes(connection_t *con,
+ binding_key_t *key)
+{
+ int hash, count = 0;
+ binding_key_ent_t *ent;
+
+ ent = con->bindings;
+ hash = BINDING_HASH(key);
+
+ while (ent != NULL) {
+ if (BINDING_HASH(&ent->key) == hash) count ++;
+ ent = ent->next;
+ }
+
+ return (count > 1);
+}
+static int table_remove(binding_ent_t *table[],
+ connection_t *con,
+ binding_key_t *key)
+{
+ binding_ent_t **curs, *ent;
+
+ if (!binding_has_colliding_hashes(con, key))
+ {
+
+ curs = &table[BINDING_HASH(key)];
+
+ while ((*curs != NULL) && ((*curs)->con != con))
+ curs = &(*curs)->next;
+
+ if (*curs != NULL) {
+ ent = *curs;
+ *curs = (*curs)->next;
+ free(ent);
+ }
+ }
+
+ connection_remove_binding(con, key);
+
+ return 0;
+}
+
+int xcs_bind(connection_t *con, int port, u16 type)
+{
+ binding_key_t key;
+
+ key.port = port;
+ key.type = type;
+
+ return table_add(binding_table, con, &key);
+}
+
+int xcs_unbind(connection_t *con, int port, u16 type)
+{
+ binding_key_t key;
+
+ key.port = port;
+ key.type = type;
+
+ return table_remove(binding_table, con, &key);
+}
+
+
+static void for_each_binding(binding_ent_t *list, binding_key_t *key,
+ void (*f)(connection_t *, void *), void *arg)
+{
+ while (list != NULL)
+ {
+ if (connection_has_binding(list->con, key))
+ f(list->con, arg);
+ list = list->next;
+ }
+}
+
+void xcs_lookup(int port, u16 type, void (*f)(connection_t *, void *),
+ void *arg)
+{
+ binding_key_t key;
+
+ key.port = port; key.type = type;
+ for_each_binding(binding_table[BINDING_HASH(&key)], &key, f, arg);
+
+ key.port = port; key.type = TYPE_WILDCARD;
+ for_each_binding(binding_table[BINDING_HASH(&key)], &key, f, arg);
+
+ key.port = PORT_WILDCARD; key.type = type;
+ for_each_binding(binding_table[BINDING_HASH(&key)], &key, f, arg);
+
+ key.port = PORT_WILDCARD; key.type = TYPE_WILDCARD;
+ for_each_binding(binding_table[BINDING_HASH(&key)], &key, f, arg);
+}
diff --git a/tools/xcs/connection.c b/tools/xcs/connection.c
new file mode 100644
index 0000000000..3b5747de68
--- /dev/null
+++ b/tools/xcs/connection.c
@@ -0,0 +1,157 @@
+/*
+ * connection.c
+ *
+ * State associated with a client connection to xcs.
+ *
+ * Copyright (c) 2004, Andrew Warfield
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xcs.h"
+
+connection_t *connection_list = NULL;
+
+#define CONNECTED(_c) (((_c)->ctrl_fd != -1) || ((_c)->data_fd != -1))
+
+connection_t *get_con_by_session(unsigned long session_id)
+{
+ connection_t **c, *ent = NULL;
+
+ c = &connection_list;
+
+ DPRINTF("looking for id: %lu : %lu\n", session_id, (*c)->id);
+
+ while (*c != NULL)
+ {
+ if ((*c)->id == session_id)
+ return (*c);
+ c = &(*c)->next;
+ }
+
+ return ent;
+}
+
+connection_t *connection_new()
+{
+ connection_t *con;
+
+ con = (connection_t *)malloc(sizeof(connection_t));
+ if (con == NULL)
+ {
+ DPRINTF("couldn't allocate a new connection\n");
+ return NULL;
+ }
+
+ con->bindings = NULL;
+ con->data_fd = -1;
+ con->ctrl_fd = -1;
+
+ /* connections need a unique session id.
+ * - this approach probably gets fixed later, but for the moment
+ * is unique, and clearly identifies a connection.
+ */
+ con->id = (unsigned long)con;
+
+ /* add it to the connection list */
+ con->next = connection_list;
+ connection_list = con;
+
+ return (con);
+}
+
+void connection_free(connection_t *con)
+{
+ /* first free all subscribed bindings: */
+
+ while (con->bindings != NULL)
+ xcs_unbind(con, con->bindings->key.port, con->bindings->key.type);
+
+ /* now free the connection. */
+ free(con);
+}
+
+int connection_add_binding(connection_t *con, binding_key_t *key)
+{
+ binding_key_ent_t *key_ent;
+
+ key_ent = (binding_key_ent_t *)malloc(sizeof(binding_key_ent_t));
+ if (key_ent == NULL)
+ {
+ DPRINTF("couldn't alloc key in connection_add_binding\n");
+ return -1;
+ }
+
+ key_ent->key = *key;
+ key_ent->next = con->bindings;
+ con->bindings = key_ent;
+
+ return 0;
+}
+
+int connection_remove_binding(connection_t *con, binding_key_t *key)
+{
+ binding_key_ent_t *key_ent;
+ binding_key_ent_t **curs = &con->bindings;
+
+ while ((*curs != NULL) && (!BINDING_KEYS_EQUAL(&(*curs)->key, key)))
+ curs = &(*curs)->next;
+
+ if (*curs != NULL) {
+ key_ent = *curs;
+ *curs = (*curs)->next;
+ free(key_ent);
+ }
+
+ return 0;
+}
+
+
+int connection_has_binding(connection_t *con, binding_key_t *key)
+{
+ binding_key_ent_t *ent;
+ int ret = 0;
+
+ ent = con->bindings;
+
+ while (ent != NULL)
+ {
+ if (BINDING_KEYS_EQUAL(key, &ent->key))
+ {
+ ret = 1;
+ break;
+ }
+ ent = ent->next;
+ }
+
+ return ret;
+}
+
+
+void gc_connection_list(void)
+{
+ connection_t **c, *ent = NULL;
+ struct timeval now, delta;
+
+ c = &connection_list;
+ gettimeofday(&now, NULL);
+
+ while ( *c != NULL )
+ {
+ if ( !CONNECTED(*c) )
+ {
+ timersub(&now, &(*c)->disconnect_time, &delta);
+ if ( delta.tv_sec >= XCS_SESSION_TIMEOUT )
+ {
+ DPRINTF(" : Freeing connection %lu after %lds\n",
+ (*c)->id, delta.tv_sec);
+ ent = *c;
+ *c = (*c)->next;
+ connection_free(ent);
+ continue;
+ }
+ }
+ c = &(*c)->next;
+ }
+}
diff --git a/tools/xcs/ctrl_interface.c b/tools/xcs/ctrl_interface.c
new file mode 100644
index 0000000000..0896910cb4
--- /dev/null
+++ b/tools/xcs/ctrl_interface.c
@@ -0,0 +1,269 @@
+/* control_interface.c
+ *
+ * Interfaces to control message rings to VMs.
+ *
+ * Most of this is directly based on the original xu interface to python
+ * written by Keir Fraser.
+ *
+ * (c) 2004, Andrew Warfield
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include "xcs.h"
+
+static int xc_handle = -1;
+
+/* Called at start-of-day when using the control channel interface. */
+int ctrl_chan_init(void)
+{
+ if ( (xc_handle = xc_interface_open()) == -1 )
+ {
+ DPRINTF("Could not open Xen control interface");
+ return -1;
+ }
+
+ return 0;
+}
+
+static control_if_t *map_control_interface(int fd, unsigned long pfn,
+ u32 dom)
+{
+ char *vaddr = xc_map_foreign_range( fd, dom, PAGE_SIZE,
+ PROT_READ|PROT_WRITE, pfn );
+ if ( vaddr == NULL )
+ return NULL;
+ return (control_if_t *)(vaddr + 2048);
+}
+
+static void unmap_control_interface(int fd, control_if_t *c)
+{
+ char *vaddr = (char *)c - 2048;
+ (void)munmap(vaddr, PAGE_SIZE);
+}
+
+int ctrl_chan_notify(control_channel_t *cc)
+{
+ return xc_evtchn_send(xc_handle, cc->local_port);
+}
+
+int ctrl_chan_read_request(control_channel_t *cc, xcs_control_msg_t *dmsg)
+{
+ control_msg_t *smsg;
+ RING_IDX c = cc->tx_ring.req_cons;
+
+ if ( !RING_HAS_UNCONSUMED_REQUESTS(CTRL_RING, &cc->tx_ring) )
+ {
+ DPRINTF("no request to read\n");
+ return -1;
+ }
+
+ rmb(); /* make sure we see the data associated with the request */
+ smsg = RING_GET_REQUEST(CTRL_RING, &cc->tx_ring, c);
+ memcpy(&dmsg->msg, smsg, sizeof(*smsg));
+ if ( dmsg->msg.length > sizeof(dmsg->msg.msg) )
+ dmsg->msg.length = sizeof(dmsg->msg.msg);
+ cc->tx_ring.req_cons++;
+ return 0;
+}
+
+int ctrl_chan_write_request(control_channel_t *cc,
+ xcs_control_msg_t *smsg)
+{
+ control_msg_t *dmsg;
+ RING_IDX p = cc->rx_ring.req_prod_pvt;
+
+ if ( RING_FULL(CTRL_RING, &cc->rx_ring) )
+ {
+ DPRINTF("no space to write request");
+ return -ENOSPC;
+ }
+
+ dmsg = RING_GET_REQUEST(CTRL_RING, &cc->rx_ring, p);
+ memcpy(dmsg, &smsg->msg, sizeof(*dmsg));
+
+ wmb();
+ cc->rx_ring.req_prod_pvt++;
+ RING_PUSH_REQUESTS(CTRL_RING, &cc->rx_ring);
+
+ return 0;
+}
+
+int ctrl_chan_read_response(control_channel_t *cc, xcs_control_msg_t *dmsg)
+{
+ control_msg_t *smsg;
+ RING_IDX c = cc->rx_ring.rsp_cons;
+
+ if ( !RING_HAS_UNCONSUMED_RESPONSES(CTRL_RING, &cc->rx_ring) )
+ {
+ DPRINTF("no response to read");
+ return -1;
+ }
+
+ rmb(); /* make sure we see the data associated with the request */
+ smsg = RING_GET_RESPONSE(CTRL_RING, &cc->rx_ring, c);
+ memcpy(&dmsg->msg, smsg, sizeof(*smsg));
+ if ( dmsg->msg.length > sizeof(dmsg->msg.msg) )
+ dmsg->msg.length = sizeof(dmsg->msg.msg);
+ cc->rx_ring.rsp_cons++;
+ return 0;
+}
+
+int ctrl_chan_write_response(control_channel_t *cc,
+ xcs_control_msg_t *smsg)
+{
+ control_msg_t *dmsg;
+ RING_IDX p = cc->tx_ring.rsp_prod_pvt;
+
+ /* akw: if the ring is synchronous, you should never need this test! */
+ /* (but it was in the original code... ) */
+ if ( cc->tx_ring.req_cons == cc->tx_ring.rsp_prod_pvt )
+ {
+ DPRINTF("no space to write response");
+ return -ENOSPC;
+ }
+
+ dmsg = RING_GET_RESPONSE(CTRL_RING, &cc->tx_ring, p);
+ memcpy(dmsg, &smsg->msg, sizeof(*dmsg));
+
+ wmb();
+ cc->tx_ring.rsp_prod_pvt++;
+ RING_PUSH_RESPONSES(CTRL_RING, &cc->tx_ring);
+
+ return 0;
+}
+
+int ctrl_chan_request_to_read(control_channel_t *cc)
+{
+ return (RING_HAS_UNCONSUMED_REQUESTS(CTRL_RING, &cc->tx_ring));
+}
+
+int ctrl_chan_space_to_write_request(control_channel_t *cc)
+{
+ return (!(RING_FULL(CTRL_RING, &cc->rx_ring)));
+}
+
+int ctrl_chan_response_to_read(control_channel_t *cc)
+{
+ return (RING_HAS_UNCONSUMED_RESPONSES(CTRL_RING, &cc->rx_ring));
+}
+
+int ctrl_chan_space_to_write_response(control_channel_t *cc)
+{
+ /* again, there is something fishy here. */
+ return ( cc->tx_ring.req_cons != cc->tx_ring.rsp_prod_pvt );
+}
+
+int ctrl_chan_connect(control_channel_t *cc)
+{
+ xc_dominfo_t info;
+
+ if ( cc->connected )
+ {
+ return 0;
+ }
+
+ if ( (xc_domain_getinfo(xc_handle, cc->remote_dom, 1, &info) != 1) ||
+ (info.domid != cc->remote_dom) )
+ {
+ DPRINTF("Failed to obtain domain status");
+ return -1;
+ }
+
+ cc->interface =
+ map_control_interface(xc_handle, info.shared_info_frame,
+ cc->remote_dom);
+
+ if ( cc->interface == NULL )
+ {
+ DPRINTF("Failed to map domain control interface");
+ return -1;
+ }
+
+ /* Synchronise ring indexes. */
+ BACK_RING_ATTACH(CTRL_RING, &cc->tx_ring, &cc->interface->tx_ring);
+ FRONT_RING_ATTACH(CTRL_RING, &cc->rx_ring, &cc->interface->rx_ring);
+
+ cc->connected = 1;
+
+ return 0;
+}
+
+void ctrl_chan_disconnect(control_channel_t *cc)
+{
+ if ( cc->connected )
+ unmap_control_interface(xc_handle, cc->interface);
+ cc->connected = 0;
+}
+
+
+control_channel_t *ctrl_chan_new(u32 dom, int local_port, int remote_port)
+{
+ control_channel_t *cc;
+
+ cc = (control_channel_t *)malloc(sizeof(control_channel_t));
+ if ( cc == NULL ) return NULL;
+
+ cc->connected = 0;
+ cc->remote_dom = dom;
+
+ if ( dom == 0 )
+ {
+ /*
+ * The control-interface event channel for DOM0 is already set up.
+ * We use an ioctl to discover the port at our end of the channel.
+ */
+ local_port = ioctl(xc_handle, IOCTL_PRIVCMD_INITDOMAIN_EVTCHN,
+ NULL);
+ remote_port = -1; /* We don't need the remote end of the DOM0 link. */
+ if ( local_port < 0 )
+ {
+ DPRINTF("Could not open channel to DOM0");
+ goto fail;
+ }
+ }
+ else if ( xc_evtchn_bind_interdomain(xc_handle,
+ DOMID_SELF, dom,
+ &local_port, &remote_port) != 0 )
+ {
+ DPRINTF("Could not open channel to domain");
+ goto fail;
+ }
+
+ cc->local_port = local_port;
+ cc->remote_port = remote_port;
+
+ if ( ctrl_chan_connect(cc) != 0 )
+ goto fail;
+
+ return cc;
+
+ fail:
+ if ( dom != 0 )
+ (void)xc_evtchn_close(xc_handle, DOMID_SELF, local_port);
+
+ free(cc);
+
+ return NULL;
+}
+
+void ctrl_chan_free(control_channel_t *cc)
+{
+ ctrl_chan_disconnect(cc);
+ if ( cc->remote_dom != 0 )
+ (void)xc_evtchn_close(xc_handle, DOMID_SELF, cc->local_port);
+ free(cc);
+}
+
+
+/* other libxc commands: */
+
+int ctrl_chan_bind_virq(int virq, int *port)
+{
+ return xc_evtchn_bind_virq(xc_handle, virq, port);
+}
diff --git a/tools/xcs/evtchn.c b/tools/xcs/evtchn.c
new file mode 100644
index 0000000000..a96036db37
--- /dev/null
+++ b/tools/xcs/evtchn.c
@@ -0,0 +1,108 @@
+/* evtchn.c
+ *
+ * Interfaces to event channel driver.
+ *
+ * Most of this is directly based on the original xu interface to python
+ * written by Keir Fraser.
+ *
+ * (c) 2004, Andrew Warfield
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h> /* XOPEN drops makedev, this gets it back. */
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include "xcs.h"
+
+static int evtchn_fd = -1;
+
+/* NB. The following should be kept in sync with the kernel's evtchn driver. */
+#define EVTCHN_DEV_NAME "/dev/xen/evtchn"
+#define EVTCHN_DEV_MAJOR 10
+#define EVTCHN_DEV_MINOR 201
+/* /dev/xen/evtchn ioctls: */
+/* EVTCHN_RESET: Clear and reinit the event buffer. Clear error condition. */
+#define EVTCHN_RESET _IO('E', 1)
+/* EVTCHN_BIND: Bind to teh specified event-channel port. */
+#define EVTCHN_BIND _IO('E', 2)
+/* EVTCHN_UNBIND: Unbind from the specified event-channel port. */
+#define EVTCHN_UNBIND _IO('E', 3)
+
+int evtchn_read()
+{
+ u16 v;
+ int bytes;
+
+ while ( (bytes = read(evtchn_fd, &v, sizeof(v))) == -1 )
+ {
+ if ( errno == EINTR )
+ continue;
+ /* EAGAIN was cased to return 'None' in the python version... */
+ return -errno;
+ }
+
+ if ( bytes == sizeof(v) )
+ return v;
+
+ /* bad return */
+ return -1;
+}
+
+void evtchn_unmask(u16 idx)
+{
+ (void)write(evtchn_fd, &idx, sizeof(idx));
+}
+
+int evtchn_bind(int idx)
+{
+ if ( ioctl(evtchn_fd, EVTCHN_BIND, idx) != 0 )
+ return -errno;
+
+ return 0;
+}
+
+int evtchn_unbind(int idx)
+{
+ if ( ioctl(evtchn_fd, EVTCHN_UNBIND, idx) != 0 )
+ return -errno;
+
+ return 0;
+}
+
+int evtchn_open(void)
+{
+ struct stat st;
+
+ /* Make sure any existing device file links to correct device. */
+ if ( (lstat(EVTCHN_DEV_NAME, &st) != 0) ||
+ !S_ISCHR(st.st_mode) ||
+ (st.st_rdev != makedev(EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR)) )
+ (void)unlink(EVTCHN_DEV_NAME);
+
+ reopen:
+ evtchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR);
+ if ( evtchn_fd == -1 )
+ {
+ if ( (errno == ENOENT) &&
+ ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
+ (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600,
+ makedev(EVTCHN_DEV_MAJOR,EVTCHN_DEV_MINOR)) == 0) )
+ goto reopen;
+ return -errno;
+ }
+ /*set_cloexec(evtchn_fd); -- no longer required*/
+printf("Eventchan_fd is %d\n", evtchn_fd);
+ return evtchn_fd;
+}
+
+void evtchn_close()
+{
+ (void)close(evtchn_fd);
+ evtchn_fd = -1;
+}
+
diff --git a/tools/xcs/xcs.c b/tools/xcs/xcs.c
new file mode 100644
index 0000000000..f0b1a96a88
--- /dev/null
+++ b/tools/xcs/xcs.c
@@ -0,0 +1,880 @@
+/* xcs.c
+ *
+ * xcs - Xen Control Switch
+ *
+ * Copyright (c) 2004, Andrew Warfield
+ */
+
+/*
+
+ Things we need to select on in xcs:
+
+ 1. Events arriving on /dev/evtchn
+
+ These will kick a function to read everything off the fd, and scan the
+ associated control message rings, resulting in notifications sent on
+ data channels to connected clients.
+
+ 2. New TCP connections on XCS_PORT.
+
+ These will either be control (intially) or associated data connections.
+
+ Control connections will instantiate or rebind to an existing connnection
+ struct. The control channel is used to configure what events will be
+ received on an associated data channel. These two channels are split
+ out because the control channel is synchronous, all messages will return
+ a result from XCS. The data channel is effectively asynchronous, events
+ may arrive in the middle of a control message exchange. Additionally,
+ Having two TCP connections allows the client side to have a blocking
+ listen loop for data messages, while independently interacting on the
+ control channel at other places in the code.
+
+ Data connections attach to an existing control struct, using a session
+ id that is passed during the control connect. There is currently a
+ one-to-one relationship between data and control channels, but there
+ could just as easily be many data channels, if there were a set of
+ clients with identical interests, or if you wanted to trace an existing
+ client's data traffic.
+
+ 3. Messages arriving on open TCP connections.
+ There are three types of open connections:
+
+ 3a. Messages arriving on open control channel file descriptors.
+
+ [description of the control protocol here]
+
+ 3b. Messages arriving on open data channel file descriptors.
+
+ [description of the data protocol here]
+
+ 3c. Messages arriving on (new) unbound connections.
+
+ A connection must issue a XCS_CONNECT message to specify what
+ it is, after which the connection is moved into one of the above
+ two groups.
+
+ Additionally, we need a periodic timer to do housekeeping.
+
+ 4. Every XCS_GC_INTERVAL seconds, we need to clean up outstanding state.
+ Specifically, we garbage collect any sessions (connection_t structs)
+ that have been unconnected for a period of time (XCS_SESSION_TIMEOUT),
+ and close any connections that have been openned, but not connected
+ as a control or data connection (XCS_UFD_TIMEOUT).
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <malloc.h>
+#include <fcntl.h>
+#include "xcs.h"
+
+#undef fd_max
+#define fd_max(x,y) ((x) > (y) ? (x) : (y))
+
+/* ------[ Control channel interfaces ]------------------------------------*/
+
+static control_channel_t *cc_list[NR_EVENT_CHANNELS];
+static int *dom_port_map = 0;
+static int dom_port_map_size = 0;
+
+static void map_dom_to_port(u32 dom, int port)
+{
+ if (dom >= dom_port_map_size) {
+ dom_port_map = (int *)realloc(dom_port_map,
+ (dom + 10) * sizeof(dom_port_map[0]));
+
+ if (dom_port_map == NULL) {
+ perror("realloc(dom_port_map)");
+ exit(1);
+ }
+
+ for (; dom_port_map_size < dom + 10; dom_port_map_size++) {
+ dom_port_map[dom_port_map_size] = -1;
+ }
+ }
+
+ dom_port_map[dom] = port;
+}
+
+static int dom_to_port(u32 dom) {
+ if (dom >= dom_port_map_size) return -1;
+
+ return dom_port_map[dom];
+}
+
+static void init_interfaces(void)
+{
+ memset(cc_list, 0, sizeof cc_list);
+}
+
+static control_channel_t *add_interface(u32 dom, int local_port,
+ int remote_port)
+{
+ control_channel_t *cc=NULL, *oldcc;
+ int ret;
+
+ if (cc_list[dom_to_port(dom)] != NULL)
+ {
+ return(cc_list[dom_to_port(dom)]);
+ }
+
+ if (cc_list[local_port] == NULL)
+ {
+ cc = ctrl_chan_new(dom, local_port, remote_port);
+ }
+
+ if (cc == NULL)
+ return NULL;
+
+ DPRINTF("added a new interface: dom: %u (l:%d,r:%d): %p\n",
+ dom, local_port, remote_port, cc);
+ DPRINTF("added a new interface: dom: %u (l:%d,r:%d): %p\n",
+ dom, cc->local_port, cc->remote_port, cc);
+
+ if ((ret = evtchn_bind(cc->local_port)) != 0)
+ {
+ DPRINTF("Got control interface, but couldn't bind evtchan!(%d)\n", ret);
+ ctrl_chan_free(cc);
+ return NULL;
+ }
+
+ if ( cc_list[cc->local_port] != NULL )
+ {
+ oldcc = cc_list[cc->local_port];
+
+ if ((oldcc->remote_dom != cc->remote_dom) ||
+ (oldcc->remote_port != cc->remote_port))
+ {
+ DPRINTF("CC conflict! (port: %d, old dom: %u, new dom: %u)\n",
+ cc->local_port, oldcc->remote_dom, cc->remote_dom);
+ map_dom_to_port(oldcc->remote_dom, -1);
+ ctrl_chan_free(cc_list[cc->local_port]);
+ }
+ }
+
+ cc_list[cc->local_port] = cc;
+ map_dom_to_port(cc->remote_dom, cc->local_port);
+ cc->type = CC_TYPE_INTERDOMAIN;
+ cc->ref_count = 0;
+ return cc;
+}
+
+control_channel_t *add_virq(int virq)
+{
+ control_channel_t *cc;
+ int virq_port;
+
+ if (ctrl_chan_bind_virq(virq, &virq_port) == -1)
+ return NULL;
+
+ if ((cc_list[virq_port] != NULL) &&
+ (cc_list[virq_port]->type != CC_TYPE_VIRQ))
+ return NULL;
+
+ if ((cc_list[virq_port] != NULL) &&
+ (cc_list[virq_port]->type == CC_TYPE_VIRQ))
+ return cc_list[virq_port];
+
+ cc = (control_channel_t *)malloc(sizeof(control_channel_t));
+ if ( cc == NULL ) return NULL;
+
+ cc->type = CC_TYPE_VIRQ;
+ cc->local_port = virq_port;
+ cc->virq = virq;
+
+ return cc;
+}
+
+void get_interface(control_channel_t *cc)
+{
+ if (cc != NULL)
+ cc->ref_count++;
+}
+
+void put_interface(control_channel_t *cc)
+{
+ if (cc != NULL)
+ {
+ cc->ref_count--;
+ if (cc->ref_count <= 0)
+ {
+ DPRINTF("Freeing cc on port %d.\n", cc->local_port);
+ (void)evtchn_unbind(cc->local_port);
+ ctrl_chan_free(cc);
+ }
+ }
+}
+
+/* ------[ Simple helpers ]------------------------------------------------*/
+
+/* listen_socket() is straight from paul sheer's useful select_tut manpage. */
+static int listen_socket (int listen_port)
+{
+ struct sockaddr_in a;
+ int s;
+ int yes;
+
+ if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ perror ("socket");
+ return -1;
+ }
+
+ yes = 1;
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+ (char *) &yes, sizeof (yes)) < 0)
+ {
+ perror ("setsockopt");
+ close (s);
+ return -1;
+ }
+
+ memset (&a, 0, sizeof (a));
+ a.sin_port = htons (listen_port);
+ a.sin_family = AF_INET;
+ if (bind(s, (struct sockaddr *) &a, sizeof (a)) < 0)
+ {
+ perror ("bind");
+ close (s);
+ return -1;
+ }
+ printf ("accepting connections on port %d\n", (int) listen_port);
+ listen (s, 10);
+ return s;
+}
+
+/* ------[ Message handlers ]----------------------------------------------*/
+
+#define NO_CHANGE 0
+#define CONNECTED 1
+#define DISCONNECTED 2
+int handle_connect_msg( xcs_msg_t *msg, int fd )
+{
+ xcs_connect_msg_t *cmsg = &msg->u.connect;
+ connection_t *con;
+ int ret = NO_CHANGE;
+
+ switch (msg->type)
+ {
+ case XCS_CONNECT_CTRL:
+ {
+ if ( cmsg->session_id == 0 )
+ {
+ con = connection_new();
+ if ( con == NULL)
+ {
+ msg->result = XCS_RSLT_FAILED;
+ break;
+ }
+ msg->result = XCS_RSLT_OK;
+ cmsg->session_id = con->id;
+ con->ctrl_fd = fd;
+ ret = CONNECTED;
+ DPRINTF("New control connection\n");
+ break;
+ }
+
+ con = get_con_by_session(cmsg->session_id);
+ if ( con == NULL )
+ {
+ msg->result = XCS_RSLT_BADSESSION;
+ break;
+ }
+ if ( con->ctrl_fd != -1 )
+ {
+ msg->result = XCS_RSLT_CONINUSE;
+ break;
+ }
+ con->ctrl_fd = fd;
+ msg->result = XCS_RSLT_OK;
+ ret = CONNECTED;
+ DPRINTF("Rebound to control connection\n");
+ break;
+ }
+ case XCS_CONNECT_DATA:
+ {
+ con = get_con_by_session(cmsg->session_id);
+ if ( con == NULL )
+ {
+ msg->result = XCS_RSLT_BADSESSION;
+ break;
+ }
+ if ( con->data_fd != -1 )
+ {
+ msg->result = XCS_RSLT_CONINUSE;
+ break;
+ }
+ con->data_fd = fd;
+ msg->result = XCS_RSLT_OK;
+ ret = CONNECTED;
+ DPRINTF("Attached data connection\n");
+ break;
+
+ }
+ case XCS_CONNECT_BYE:
+ {
+ close ( fd );
+ ret = DISCONNECTED;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int handle_control_message( connection_t *con, xcs_msg_t *msg )
+{
+ int ret;
+ int reply_needed = 1;
+
+ DPRINTF("Got message, type %u.\n", msg->type);
+
+ switch (msg->type)
+ {
+ case XCS_MSG_BIND:
+ {
+ xcs_bind_msg_t *bmsg = &msg->u.bind;
+
+ if ( ! BIND_MSG_VALID(bmsg) )
+ {
+ msg->result = XCS_RSLT_BADREQUEST;
+ break;
+ }
+
+ ret = xcs_bind(con, bmsg->port, bmsg->type);
+ if (ret == 0) {
+ msg->result = XCS_RSLT_OK;
+ } else {
+ msg->result = XCS_RSLT_FAILED;
+ }
+ break;
+ }
+ case XCS_MSG_UNBIND:
+ {
+ xcs_bind_msg_t *bmsg = &msg->u.bind;
+
+ if ( ! BIND_MSG_VALID(bmsg) )
+ {
+ msg->result = XCS_RSLT_BADREQUEST;
+ break;
+ }
+
+ ret = xcs_unbind(con, bmsg->port, bmsg->type);
+ if (ret == 0) {
+ msg->result = XCS_RSLT_OK;
+ } else {
+ msg->result = XCS_RSLT_FAILED;
+ }
+ break;
+ }
+ case XCS_VIRQ_BIND:
+ {
+ control_channel_t *cc;
+ xcs_virq_msg_t *vmsg = &msg->u.virq;
+ if ( ! VIRQ_MSG_VALID(vmsg) )
+ {
+ msg->result = XCS_RSLT_BADREQUEST;
+ break;
+ }
+
+ cc = add_virq(vmsg->virq);
+ if (cc == NULL)
+ {
+ msg->result = XCS_RSLT_FAILED;
+ break;
+ }
+ ret = xcs_bind(con, cc->local_port, TYPE_VIRQ);
+ if (ret == 0) {
+ vmsg->port = cc->local_port;
+ msg->result = XCS_RSLT_OK;
+ } else {
+ msg->result = XCS_RSLT_FAILED;
+ }
+ break;
+ }
+
+ case XCS_CIF_NEW_CC:
+ {
+ control_channel_t *cc;
+ xcs_interface_msg_t *imsg = &msg->u.interface;
+
+ if ( ! INTERFACE_MSG_VALID(imsg) )
+ {
+ msg->result = XCS_RSLT_BADREQUEST;
+ break;
+ }
+
+ cc = add_interface(imsg->dom, imsg->local_port, imsg->remote_port);
+ if (cc != NULL) {
+ get_interface(cc);
+ msg->result = XCS_RSLT_OK;
+ imsg->local_port = cc->local_port;
+ imsg->remote_port = cc->remote_port;
+ } else {
+ msg->result = XCS_RSLT_FAILED;
+ }
+ break;
+ }
+
+ case XCS_CIF_FREE_CC:
+ {
+ control_channel_t *cc;
+ xcs_interface_msg_t *imsg = &msg->u.interface;
+
+ if ( ! INTERFACE_MSG_VALID(imsg) )
+ {
+ msg->result = XCS_RSLT_BADREQUEST;
+ break;
+ }
+
+ cc = add_interface(imsg->dom, imsg->local_port, imsg->remote_port);
+ if (cc != NULL) {
+ put_interface(cc);
+ }
+ msg->result = XCS_RSLT_OK;
+ break;
+ }
+ }
+ return reply_needed;
+}
+
+void handle_data_message( connection_t *con, xcs_msg_t *msg )
+{
+ control_channel_t *cc;
+ xcs_control_msg_t *cmsg = &msg->u.control;
+ int port;
+
+ switch (msg->type)
+ {
+ case XCS_REQUEST:
+ if ( cmsg->remote_dom > MAX_DOMS )
+ break;
+
+ port = dom_to_port(cmsg->remote_dom);
+ if (port == -1) break;
+ cc = cc_list[port];
+ if ((cc != NULL) && ( cc->type == CC_TYPE_INTERDOMAIN ))
+ {
+ DPRINTF("DN:REQ: dom:%d port: %d type: %d\n",
+ cc->remote_dom, cc->local_port,
+ cmsg->msg.type);
+ ctrl_chan_write_request(cc, cmsg);
+ ctrl_chan_notify(cc);
+ } else {
+ DPRINTF("tried to send a REQ to a null cc\n.");
+ }
+ break;
+
+ case XCS_RESPONSE:
+ if ( cmsg->remote_dom > MAX_DOMS )
+ break;
+
+ port = dom_to_port(cmsg->remote_dom);
+ if (port == -1) break;
+ cc = cc_list[port];
+ if ((cc != NULL) && ( cc->type == CC_TYPE_INTERDOMAIN ))
+ {
+ DPRINTF("DN:RSP: dom:%d port: %d type: %d\n",
+ cc->remote_dom, cc->local_port,
+ cmsg->msg.type);
+ ctrl_chan_write_response(cc, cmsg);
+ ctrl_chan_notify(cc);
+ }
+ break;
+
+ case XCS_VIRQ:
+ if ( !(PORT_VALID(cmsg->local_port)) )
+ break;
+
+ cc = cc_list[cmsg->local_port];
+
+ if ((cc != NULL) && ( cc->type == CC_TYPE_VIRQ ))
+ {
+ DPRINTF("DN:VIRQ: virq: %d port: %d\n",
+ cc->virq, cc->local_port);
+ ctrl_chan_notify(cc);
+ }
+ break;
+ }
+}
+
+/* ------[ Control interface handler ]-------------------------------------*/
+
+/* passed as a function pointer to the lookup. */
+void send_kmsg(connection_t *c, void *arg)
+{
+ xcs_msg_t *msg = (xcs_msg_t *)arg;
+
+ DPRINTF(" -> CONNECTION %d\n", c->data_fd);
+ if (c->data_fd > 0)
+ {
+ send(c->data_fd, msg, sizeof(xcs_msg_t), 0);
+ }
+}
+
+int handle_ctrl_if(void)
+{
+ control_channel_t *cc;
+ control_msg_t *msg;
+ xcs_msg_t kmsg;
+ int chan, ret;
+
+ DPRINTF("Event thread kicked!\n");
+again:
+ while ((chan = evtchn_read()) > 0)
+ {
+ evtchn_unmask(chan);
+ cc = cc_list[chan];
+ if (cc_list[chan] == NULL) {
+ DPRINTF("event from unknown channel (%d)\n", chan);
+ continue;
+ }
+
+ if ( cc_list[chan]->type == CC_TYPE_VIRQ )
+ {
+ DPRINTF("UP:VIRQ: virq:%d port: %d\n",
+ cc->virq, cc->local_port);
+ kmsg.type = XCS_VIRQ;
+ kmsg.u.control.local_port = cc->local_port;
+ xcs_lookup(cc->local_port, TYPE_VIRQ, send_kmsg, &kmsg);
+ continue;
+ }
+
+ while (ctrl_chan_request_to_read(cc))
+ {
+ msg = &kmsg.u.control.msg;
+ kmsg.type = XCS_REQUEST;
+ kmsg.u.control.remote_dom = cc->remote_dom;
+ kmsg.u.control.local_port = cc->local_port;
+ ret = ctrl_chan_read_request(cc, &kmsg.u.control);
+ DPRINTF("UP:REQ: dom:%d port: %d type: %d len: %d\n",
+ cc->remote_dom, cc->local_port,
+ msg->type, msg->length);
+ if (ret == 0)
+ xcs_lookup(cc->local_port, msg->type, send_kmsg, &kmsg);
+ }
+
+ while (ctrl_chan_response_to_read(cc))
+ {
+ msg = &kmsg.u.control.msg;
+ kmsg.type = XCS_RESPONSE;
+ kmsg.u.control.remote_dom = cc->remote_dom;
+ kmsg.u.control.local_port = cc->local_port;
+ ret = ctrl_chan_read_response(cc, &kmsg.u.control);
+ DPRINTF("UP:RSP: dom:%d port: %d type: %d len: %d\n",
+ cc->remote_dom, cc->local_port,
+ msg->type, msg->length);
+ if (ret == 0)
+ xcs_lookup(cc->local_port, msg->type, send_kmsg, &kmsg);
+ }
+ }
+
+ if (chan == -EINTR)
+ goto again;
+
+ return chan;
+}
+
+
+/* ------[ Main xcs code / big select loop ]-------------------------------*/
+
+
+typedef struct unbound_fd_st {
+ int fd;
+ struct timeval born;
+ struct unbound_fd_st *next;
+} unbound_fd_t;
+
+/* This makes ufd point to the next entry in the list, so need to *
+ * break/continue if called while iterating. */
+void delete_ufd(unbound_fd_t **ufd)
+{
+ unbound_fd_t *del_ufd;
+
+ del_ufd = *ufd;
+ *ufd = (*ufd)->next;
+ free( del_ufd );
+}
+
+void gc_ufd_list( unbound_fd_t **ufd )
+{
+ struct timeval now, delta;
+
+ gettimeofday(&now, NULL);
+
+ while ( *ufd != NULL )
+ {
+ timersub(&now, &(*ufd)->born, &delta);
+ if (delta.tv_sec > XCS_UFD_TIMEOUT)
+ {
+ DPRINTF("GC-UFD: closing fd: %d\n", (*ufd)->fd);
+ close((*ufd)->fd);
+ delete_ufd(ufd);
+ continue;
+ }
+ ufd = &(*ufd)->next;
+ }
+}
+
+int main (int argc, char*argv[])
+{
+ int listen_fd, evtchn_fd;
+ unbound_fd_t *unbound_fd_list = NULL, **ufd;
+ struct timeval timeout = { XCS_GC_INTERVAL, 0 };
+ connection_t **con;
+
+ /* Initialize xc and event connections. */
+ if (ctrl_chan_init() != 0)
+ {
+ printf("Couldn't open conneciton to libxc.\n");
+ exit(-1);
+ }
+
+ if ((evtchn_fd = evtchn_open()) < 0)
+ {
+ printf("Couldn't open event channel driver interface.\n");
+ exit(-1);
+ }
+
+ /* Initialize control interfaces, bindings. */
+ init_interfaces();
+ init_bindings();
+
+ listen_fd = listen_socket(XCS_TCP_PORT);
+
+ /* detach from our controlling tty so that a shell does hang waiting for
+ stopped jobs. */
+ /* we should use getopt() here */
+
+ if (!(argc == 2 && !strcmp(argv[1], "-i"))) {
+ pid_t pid = fork();
+ int fd;
+
+ if (pid == -1) {
+ perror("fork()");
+ } else if (pid) {
+ exit(0);
+ }
+
+ setsid();
+ close(2);
+ close(1);
+ close(0);
+ fd = open("/dev/null", O_RDWR);
+ dup(fd);
+ dup(fd);
+ }
+
+ for (;;)
+ {
+ int n, ret;
+ fd_set rd, wr, er;
+ FD_ZERO ( &rd );
+ FD_ZERO ( &wr );
+ FD_ZERO ( &er );
+
+ /* TCP listen fd: */
+ FD_SET ( listen_fd, &rd );
+ n = fd_max ( n, listen_fd );
+
+ /* Evtchn fd: */
+ FD_SET ( evtchn_fd, &rd );
+ n = fd_max ( n, evtchn_fd );
+
+ /* unbound connection fds: */
+ ufd = &unbound_fd_list;
+ while ((*ufd) != NULL)
+ {
+ FD_SET ( (*ufd)->fd, &rd );
+ n = fd_max ( n, (*ufd)->fd );
+ ufd = &(*ufd)->next;
+ }
+
+ /* control and data fds: */
+ con = &connection_list;
+ while ((*con) != NULL)
+ {
+ if ((*con)->ctrl_fd > 0)
+ {
+ FD_SET ( (*con)->ctrl_fd, &rd );
+ n = fd_max ( n, (*con)->ctrl_fd );
+ }
+ if ((*con)->data_fd > 0)
+ {
+ FD_SET ( (*con)->data_fd, &rd );
+ n = fd_max ( n, (*con)->data_fd );
+ }
+ con = &(*con)->next;
+ }
+
+ ret = select ( n + 1, &rd, &wr, &er, &timeout );
+
+ if ( (timeout.tv_sec == 0) && (timeout.tv_usec == 0) )
+ {
+ gc_ufd_list(&unbound_fd_list);
+ gc_connection_list();
+ timeout.tv_sec = XCS_GC_INTERVAL;
+ }
+
+ if ( (ret == -1) && (errno == EINTR) )
+ continue;
+ if ( ret < 0 )
+ {
+ perror ("select()");
+ exit(-1);
+ }
+
+ /* CASE 1: Events arriving on /dev/evtchn. */
+
+ if ( FD_ISSET (evtchn_fd, &rd ))
+ handle_ctrl_if();
+
+ /* CASE 2: New connection on the listen port. */
+ if ( FD_ISSET ( listen_fd, &rd ))
+ {
+ struct sockaddr_in remote_addr;
+ int size;
+ memset (&remote_addr, 0, sizeof (remote_addr));
+ size = sizeof remote_addr;
+ ret = accept(listen_fd, (struct sockaddr *)&remote_addr, &size);
+ if ( ret < 0 )
+ {
+ perror("accept()");
+ } else {
+ unbound_fd_t *new_ufd;
+
+ new_ufd = (unbound_fd_t *)malloc(sizeof(*new_ufd));
+
+ if (new_ufd != NULL)
+ {
+ gettimeofday(&new_ufd->born, NULL);
+ new_ufd->fd = ret;
+ new_ufd->next = unbound_fd_list;
+ unbound_fd_list = new_ufd;
+ } else {
+ perror("malloc unbound connection");
+ close(ret);
+ }
+ }
+ }
+
+ /* CASE 3a: Handle messages on control connections. */
+
+ con = &connection_list;
+ while ( *con != NULL )
+ {
+ if ( ((*con)->ctrl_fd > 0) && (FD_ISSET((*con)->ctrl_fd, &rd)) )
+ {
+ xcs_msg_t msg;
+ memset (&msg, 0, sizeof(msg));
+ ret = read( (*con)->ctrl_fd, &msg, sizeof(msg) );
+
+ if ( ret < 0 )
+ {
+ perror("reading ctrl fd.");
+ } else if ( ret == 0 )
+ {
+ DPRINTF("Control connection dropped.\n");
+ close ( (*con)->ctrl_fd );
+ (*con)->ctrl_fd = -1;
+ gettimeofday(&(*con)->disconnect_time, NULL);
+ } else
+ {
+ if ( ret != sizeof(msg) )
+ {
+ DPRINTF("Unexpected frame size!\n");
+ continue;
+ }
+
+ ret = handle_control_message( *con, &msg );
+
+ if ( ret == 1 )
+ send( (*con)->ctrl_fd, &msg, sizeof(msg), 0 );
+ }
+ }
+ con = &(*con)->next;
+ }
+
+ /* CASE 3b: Handle messages on data connections. */
+
+ con = &connection_list;
+ while ( *con != NULL )
+ {
+ if ( ((*con)->data_fd > 0) && (FD_ISSET((*con)->data_fd, &rd)) )
+ {
+ xcs_msg_t msg;
+ memset (&msg, 0, sizeof(msg));
+ ret = read( (*con)->data_fd, &msg, sizeof(msg) );
+
+ if ( ret < 0 )
+ {
+ perror("reading data fd.");
+ } else if ( ret == 0 )
+ {
+ DPRINTF("Data connection dropped.\n");
+ close ( (*con)->data_fd );
+ (*con)->data_fd = -1;
+ gettimeofday(&(*con)->disconnect_time, NULL);
+ } else
+ {
+ if ( ret != sizeof(msg) )
+ {
+ DPRINTF("Unexpected frame size!\n");
+ continue;
+ }
+
+ handle_data_message( *con, &msg );
+ }
+ }
+ con = &(*con)->next;
+ }
+
+ /* CASE 3c: Handle messages arriving on unbound connections. */
+ ufd = &unbound_fd_list;
+ while ((*ufd) != NULL)
+ {
+ if ( FD_ISSET( (*ufd)->fd, &rd ) )
+ {
+ xcs_msg_t msg;
+ memset (&msg, 0, sizeof(msg));
+ ret = read( (*ufd)->fd, &msg, sizeof(msg) );
+
+ if ( ret == 0 )
+ {
+ close ( (*ufd)->fd );
+ delete_ufd(ufd);
+ continue; /* we just advanced ufd */
+ } else {
+ if ( ret != sizeof(msg) )
+ {
+ DPRINTF("Unexpected frame size!\n");
+ continue;
+ }
+
+ ret = handle_connect_msg( &msg, (*ufd)->fd );
+
+ if ( (ret == CONNECTED) || (ret == NO_CHANGE) )
+ send( (*ufd)->fd, &msg, sizeof(msg), 0 );
+
+ if ( (ret = CONNECTED) || (ret = DISCONNECTED) )
+ {
+ delete_ufd( ufd );
+ continue;
+ }
+ }
+ }
+ ufd = &(*ufd)->next;
+ }
+ }
+}
+
diff --git a/tools/xcs/xcs.h b/tools/xcs/xcs.h
new file mode 100644
index 0000000000..545fc3d05f
--- /dev/null
+++ b/tools/xcs/xcs.h
@@ -0,0 +1,155 @@
+/* xcs.h
+ *
+ * public interfaces for the control interface switch (xcs).
+ *
+ * (c) 2004, Andrew Warfield
+ *
+ */
+
+
+#ifndef __XCS_H__
+#define __XCS_H__
+
+#include <pthread.h>
+#include <xc.h>
+#include <xen/xen.h>
+#include <xen/io/domain_controller.h>
+#include <xen/linux/privcmd.h>
+#include <sys/time.h>
+#include "xcs_proto.h"
+
+/* ------[ Debug macros ]--------------------------------------------------*/
+
+#if 0
+#define DPRINTF(_f, _a...) printf ( _f , ## _a )
+#else
+#define DPRINTF(_f, _a...) ((void)0)
+#endif
+
+/* ------[ XCS-specific defines and types ]--------------------------------*/
+
+#define MAX_DOMS 1024
+#define XCS_SESSION_TIMEOUT 10 /* (secs) disconnected session gc timeout */
+#define XCS_UFD_TIMEOUT 5 /* how long can connections be unbound? */
+#define XCS_GC_INTERVAL 5 /* How often to run gc handlers. */
+
+
+/* ------[ Other required defines ]----------------------------------------*/
+
+/* Size of a machine page frame. */
+#define PAGE_SIZE 4096
+
+#if defined(__i386__)
+#define rmb() __asm__ __volatile__ ( "lock; addl $0,0(%%esp)" : : : "memory" )
+#define wmb() __asm__ __volatile__ ( "" : : : "memory" )
+#else
+#error "Define barriers"
+#endif
+
+#ifndef timersub /* XOPEN and __BSD don't cooperate well... */
+#define timersub(a, b, result) \
+ do { \
+ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
+ if ((result)->tv_usec < 0) { \
+ --(result)->tv_sec; \
+ (result)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif /*timersub*/
+
+/* ------[ Bindings Interface ]--------------------------------------------*/
+
+/*forward declare connection_t */
+typedef struct connection_st connection_t;
+
+typedef struct {
+ int port;
+ u16 type;
+} binding_key_t;
+
+typedef struct binding_key_ent_st {
+ binding_key_t key;
+ struct binding_key_ent_st *next;
+} binding_key_ent_t;
+
+#define BINDING_KEYS_EQUAL(_k1, _k2) \
+ (((_k1)->port == (_k2)->port) && ((_k1)->type == (_k2)->type))
+
+int xcs_bind(connection_t *con, int port, u16 type);
+int xcs_unbind(connection_t *con, int port, u16 type);
+void xcs_lookup(int port, u16 type, void (*f)(connection_t *, void *),
+ void *arg);
+void init_bindings(void);
+
+/* ------[ Connection Interface ]------------------------------------------*/
+
+struct connection_st {
+ unsigned long id; /* Unique session id */
+ int ctrl_fd; /* TCP descriptors */
+ int data_fd; /* */
+ binding_key_ent_t *bindings; /* List of bindings */
+ connection_t *next; /* Linked list of connections */
+ struct timeval disconnect_time; /* " " */
+}; /* previously typedefed as connection_t */
+
+
+extern connection_t *connection_list;
+
+connection_t *get_con_by_session(unsigned long session_id);
+connection_t *connection_new();
+void connection_free(connection_t *con);
+int connection_add_binding(connection_t *con, binding_key_t *key);
+int connection_remove_binding(connection_t *con, binding_key_t *key);
+int connection_has_binding(connection_t *con, binding_key_t *key);
+void gc_connection_list(void);
+
+/* ------[ Control Channel Interfaces ]------------------------------------*/
+
+typedef struct {
+ int connected;
+ int ref_count;
+ int type;
+ u32 remote_dom;
+ int local_port;
+ int remote_port;
+ control_if_t *interface;
+ ctrl_back_ring_t tx_ring;
+ ctrl_front_ring_t rx_ring;
+ int virq;
+} control_channel_t;
+
+/* cc types that we care about */
+#define CC_TYPE_INTERDOMAIN 0
+#define CC_TYPE_VIRQ 1
+
+control_channel_t
+ *ctrl_chan_new(u32 dom, int local_port, int remote_port);
+void ctrl_chan_free(control_channel_t *cc);
+int ctrl_chan_init(void);
+int ctrl_chan_notify(control_channel_t *cc);
+int ctrl_chan_read_request(control_channel_t *cc, xcs_control_msg_t *);
+int ctrl_chan_write_request(control_channel_t *cc,
+ xcs_control_msg_t *smsg);
+int ctrl_chan_read_response(control_channel_t *cc, xcs_control_msg_t *);
+int ctrl_chan_write_response(control_channel_t *cc,
+ xcs_control_msg_t *smsg);
+int ctrl_chan_request_to_read(control_channel_t *cc);
+int ctrl_chan_space_to_write_request(control_channel_t *cc);
+int ctrl_chan_response_to_read(control_channel_t *cc);
+int ctrl_chan_space_to_write_response(control_channel_t *cc);
+int ctrl_chan_connect(control_channel_t *cc);
+void ctrl_chan_disconnect(control_channel_t *cc);
+int ctrl_chan_bind_virq(int virq, int *port);
+
+/* ------[ Event notification interfaces ]---------------------------------*/
+
+
+int evtchn_open(void);
+void evtchn_close();
+int evtchn_bind(int idx);
+int evtchn_unbind(int idx);
+void evtchn_unmask(u16 idx);
+int evtchn_read();
+
+#endif /* __XCS_H__ */
diff --git a/tools/xcs/xcs_proto.h b/tools/xcs/xcs_proto.h
new file mode 100644
index 0000000000..ea227c2ff7
--- /dev/null
+++ b/tools/xcs/xcs_proto.h
@@ -0,0 +1,101 @@
+/* xcs_proto.h
+ *
+ * protocol interfaces for the control interface switch (xcs).
+ *
+ * (c) 2004, Andrew Warfield
+ *
+ */
+
+#ifndef __XCS_PROTO_H__
+#define __XCS_PROTO_H__
+
+#define XCS_TCP_PORT 1633
+
+/* xcs message types: */
+#define XCS_CONNECT_CTRL 0 /* This is a control connection. */
+#define XCS_CONNECT_DATA 1 /* This is a data connection. */
+#define XCS_CONNECT_BYE 2 /* Terminate a session. */
+#define XCS_MSG_BIND 3 /* Register for a message type. */
+#define XCS_MSG_UNBIND 4 /* Unregister for a message type. */
+#define XCS_VIRQ_BIND 5 /* Register for a virq. */
+#define XCS_MSG_WRITELOCK 6 /* Writelock a (dom,type) pair. */
+#define XCS_CIF_NEW_CC 7 /* Create a new control channel. */
+#define XCS_CIF_FREE_CC 8 /* Create a new control channel. */
+#define XCS_REQUEST 9 /* This is a request message. */
+#define XCS_RESPONSE 10 /* this is a response Message. */
+#define XCS_VIRQ 11 /* this is a virq notification. */
+
+/* xcs result values: */
+#define XCS_RSLT_OK 0
+#define XCS_RSLT_FAILED 1 /* something bad happened. */
+#define XCS_RSLT_ARECONNECTED 2 /* attempt to over connect. */
+#define XCS_RSLT_BADSESSION 3 /* request for unknown session id. */
+#define XCS_RSLT_NOSESSION 4 /* tried to do something before NEW. */
+#define XCS_RSLT_CONINUSE 5 /* Requested connection is taken. */
+#define XCS_RSLT_BADREQUEST 6 /* Request message didn't validate. */
+
+/* Binding wildcards */
+#define PORT_WILDCARD 0xefffffff
+#define TYPE_WILDCARD 0xffff
+#define TYPE_VIRQ 0xfffe
+
+typedef struct {
+ u32 session_id;
+} xcs_connect_msg_t;
+
+typedef struct {
+ int port;
+ u16 type;
+} xcs_bind_msg_t;
+
+typedef struct {
+ int port;
+ u16 virq;
+} xcs_virq_msg_t;
+
+typedef struct {
+ u32 dom;
+ int local_port;
+ int remote_port;
+} xcs_interface_msg_t;
+
+typedef struct {
+ u32 remote_dom;
+ int local_port;
+ control_msg_t msg;
+} xcs_control_msg_t;
+
+typedef struct {
+ u32 type;
+ u32 result;
+ union {
+ xcs_connect_msg_t connect; /* These are xcs ctrl message types */
+ xcs_bind_msg_t bind;
+ xcs_virq_msg_t virq;
+ xcs_interface_msg_t interface;
+
+ xcs_control_msg_t control; /* These are xcs data message types */
+ } PACKED u;
+} xcs_msg_t;
+
+/* message validation macros. */
+#define PORT_VALID(_p) \
+ ( (((_p) >= 0) && ((_p) < NR_EVENT_CHANNELS)) \
+ || ((_p) == PORT_WILDCARD) )
+
+#define TYPE_VALID(_t) \
+ ( ((_t) < 256) \
+ || ((_t) == TYPE_VIRQ) \
+ || ((_t) == TYPE_WILDCARD) )
+
+#define BIND_MSG_VALID(_b) \
+ ( PORT_VALID((_b)->port) && TYPE_VALID((_b)->type) )
+
+/* Port is overwritten, and we don't currently validate the requested virq. */
+#define VIRQ_MSG_VALID(_v) ( 1 )
+
+/* Interfaces may return with ports of -1, but may not be requested as such */
+#define INTERFACE_MSG_VALID(_i) \
+ ( PORT_VALID((_i)->local_port) && PORT_VALID((_i)->remote_port) )
+
+#endif /* __XCS_PROTO_H__ */
diff --git a/tools/xcs/xcsdump.c b/tools/xcs/xcsdump.c
new file mode 100644
index 0000000000..dcfd2c9119
--- /dev/null
+++ b/tools/xcs/xcsdump.c
@@ -0,0 +1,182 @@
+/* xcsdump.c
+ *
+ * little tool to sniff control messages.
+ *
+ * Copyright (c) 2004, Andrew Warfield
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <xc.h>
+#include <xen/xen.h>
+#include <xen/io/domain_controller.h>
+#include "xcs_proto.h"
+#include "xcs.h"
+
+static int xcs_ctrl_fd = -1; /* connection to the xcs server. */
+static int xcs_data_fd = -1; /* connection to the xcs server. */
+
+int tcp_connect(char *ip, short port)
+{
+ struct sockaddr_in addr;
+ int ret, fd;
+
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ {
+ printf("error creating xcs socket!\n");
+ return -1;
+ }
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = inet_addr(ip);
+ memset(&(addr.sin_zero), '\0', 8);
+
+ ret = connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr));
+ if (ret < 0)
+ {
+ printf("error connecting to xcs!\n");
+ return -1;
+ }
+
+ return fd;
+}
+
+void tcp_disconnect(int *fd)
+{
+ close(*fd);
+ *fd = -1;
+}
+
+void xcs_read(int fd, xcs_msg_t *msg)
+{
+ int ret;
+
+ ret = read(fd, msg, sizeof(xcs_msg_t));
+ if (ret != sizeof(xcs_msg_t)) {
+ printf("read error\n");
+ exit(-1);
+ }
+}
+
+void xcs_send(int fd, xcs_msg_t *msg)
+{
+ int ret;
+
+ ret = send(fd, msg, sizeof(xcs_msg_t), 0);
+ if (ret != sizeof(xcs_msg_t) )
+ {
+ printf("send error\n");
+ exit(-1);
+ }
+}
+
+
+int main(int argc, char* argv[])
+{
+ int ret, i;
+ xcs_msg_t msg;
+ control_msg_t *cmsg;
+ int verbose = 0;
+
+ if (argc > 1)
+ if ((strlen(argv[1]) >=2) && (strncmp(argv[1], "-v", 2) == 0))
+ verbose = 1;
+
+ ret = tcp_connect("127.0.0.1", XCS_TCP_PORT);
+ if (ret < 0)
+ {
+ printf("connect failed!\n");
+ exit(-1);
+ }
+ xcs_ctrl_fd = ret;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.type = XCS_CONNECT_CTRL;
+ xcs_send(xcs_ctrl_fd, &msg);
+ xcs_read(xcs_ctrl_fd, &msg);
+ if (msg.result != XCS_RSLT_OK)
+ {
+ printf("Error connecting control channel\n");
+ exit(-1);
+ }
+
+ ret = tcp_connect("127.0.0.1", XCS_TCP_PORT);
+ if (ret < 0)
+ {
+ printf("connect failed!\n");
+ exit(-1);
+ }
+ xcs_data_fd = ret;
+
+ msg.type = XCS_CONNECT_DATA;
+ /* session id is set from before... */
+ xcs_send(xcs_data_fd, &msg);
+ xcs_read(xcs_data_fd, &msg);
+ if (msg.result != XCS_RSLT_OK)
+ {
+ printf("Error connecting data channel\n");
+ exit(-1);
+ }
+
+ msg.type = XCS_MSG_BIND;
+ msg.u.bind.port = PORT_WILDCARD;
+ msg.u.bind.type = TYPE_WILDCARD;
+ xcs_send(xcs_ctrl_fd, &msg);
+ xcs_read(xcs_ctrl_fd, &msg);
+ if (msg.result != XCS_RSLT_OK)
+ {
+ printf("Error binding.\n");
+ exit(-1);
+ }
+
+
+ while (1)
+ {
+ xcs_read(xcs_data_fd, &msg);
+ cmsg = &msg.u.control.msg;
+
+ for (i=0; i<60; i++)
+ if ((!isprint(cmsg->msg[i])) && (cmsg->msg[i] != '\0'))
+ cmsg->msg[i] = '.';
+ cmsg->msg[59] = '\0';
+
+ switch (msg.type)
+ {
+ case XCS_REQUEST:
+ printf("[REQUEST ] : (dom:%u port:%d) (type:(%d,%d) len %d) \n",
+ msg.u.control.remote_dom,
+ msg.u.control.local_port,
+ msg.u.control.msg.type,
+ msg.u.control.msg.subtype,
+ msg.u.control.msg.length);
+ if (verbose)
+ printf(" : %s\n", msg.u.control.msg.msg);
+ break;
+ case XCS_RESPONSE:
+ printf("[RESPONSE] : (dom:%u port:%d) (type:(%d,%d) len %d) \n",
+ msg.u.control.remote_dom,
+ msg.u.control.local_port,
+ msg.u.control.msg.type,
+ msg.u.control.msg.subtype,
+ msg.u.control.msg.length);
+ if (verbose)
+ printf(" : %s\n", msg.u.control.msg.msg);
+ break;
+ case XCS_VIRQ:
+ printf("[VIRQ ] : %d\n", msg.u.control.local_port);
+ default:
+ printf("[UNKNOWN ]\n");
+ }
+ }
+
+ return(0);
+}
diff --git a/xen/Makefile b/xen/Makefile
index 57a89ad454..85596cd328 100644
--- a/xen/Makefile
+++ b/xen/Makefile
@@ -8,9 +8,9 @@ INSTALL_DIR = $(INSTALL) -d -m0755
# This is the correct place to edit the build version.
# All other places this is stored (eg. compile.h) should be autogenerated.
-export XEN_VERSION = 2
+export XEN_VERSION = 3
export XEN_SUBVERSION = 0
-export XEN_EXTRAVERSION = ""
+export XEN_EXTRAVERSION = "-devel"
export BASEDIR := $(CURDIR)
@@ -85,7 +85,7 @@ include/xen/banner.h: tools/figlet/figlet tools/figlet/xen.flf
tools/figlet/figlet -d tools/figlet Xen $(XEN_VERSION).$(XEN_SUBVERSION)$(XEN_EXTRAVERSION) > $@.new
@mv -f $@.new $@
-include/asm-$(TARGET_ARCH)/asm-offsets.h: arch/$(TARGET_ARCH)/asm-offsets.s
+include/asm-$(TARGET_ARCH)/asm-offsets.h: arch/$(TARGET_ARCH)/asm-offsets.s $(HDRS)
@(set -e; \
echo "/*"; \
echo " * DO NOT MODIFY."; \
@@ -108,6 +108,6 @@ TAGS:
( find include/asm-$(TARGET_ARCH) -name '*.h'; \
find include -type d \( -name "asm-*" -o -name config \) -prune -o \
-name '*.h' -print; \
- find $(SUBDIRS) -name '*.[ch]' ) | grep -v /SCCS/ | etags -
+ find $(SUBDIRS) -name '*.[chS]' ) | grep -v /SCCS/ | etags -
MAP:
nm $(TARGET) | grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | sort > System.map
diff --git a/xen/Rules.mk b/xen/Rules.mk
index 82599afec0..186f4e3536 100644
--- a/xen/Rules.mk
+++ b/xen/Rules.mk
@@ -54,9 +54,9 @@ else
CFLAGS += -DVERBOSE
endif
-ifeq ($(debugger),y)
-CFLAGS += -DXEN_DEBUGGER
-endif
+#ifeq ($(debugger),y)
+#CFLAGS += -DXEN_DEBUGGER
+#endif
ifeq ($(perfc),y)
CFLAGS += -DPERF_COUNTERS
diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
index 9a6029dcaf..0d1b05dedf 100644
--- a/xen/arch/x86/Makefile
+++ b/xen/arch/x86/Makefile
@@ -1,17 +1,19 @@
include $(BASEDIR)/Rules.mk
-ifneq ($(debugger),y)
-OBJS := $(subst pdb-linux.o,,$(OBJS))
-OBJS := $(subst pdb-stub.o,,$(OBJS))
-endif
-
OBJS += $(patsubst %.S,%.o,$(wildcard $(TARGET_SUBARCH)/*.S))
OBJS += $(patsubst %.c,%.o,$(wildcard $(TARGET_SUBARCH)/*.c))
OBJS += $(patsubst %.c,%.o,$(wildcard mtrr/*.c))
OBJS := $(subst $(TARGET_SUBARCH)/asm-offsets.o,,$(OBJS))
+ifneq ($(TARGET_SUBARCH),x86_32)
+OBJS := $(subst vmx.o,,$(OBJS))
+OBJS := $(subst vmx_io.o,,$(OBJS))
+OBJS := $(subst vmx_platform.o,,$(OBJS))
+OBJS := $(subst vmx_vmcs.o,,$(OBJS))
+endif
+
default: $(TARGET)
$(TARGET): $(TARGET)-syms boot/mkelf32
diff --git a/xen/arch/x86/Rules.mk b/xen/arch/x86/Rules.mk
index c3e1c2aea1..1eda23b416 100644
--- a/xen/arch/x86/Rules.mk
+++ b/xen/arch/x86/Rules.mk
@@ -5,7 +5,7 @@ CC := gcc
LD := ld
CFLAGS := -nostdinc -fno-builtin -fno-common -fno-strict-aliasing
-CFLAGS += -iwithprefix include -Wall -Werror -pipe
+CFLAGS += -iwithprefix include -Wall -Werror -Wno-format -pipe
CFLAGS += -I$(BASEDIR)/include -Wno-pointer-arith -Wredundant-decls
ifeq ($(optimize),y)
diff --git a/xen/arch/x86/boot/x86_32.S b/xen/arch/x86/boot/x86_32.S
index b8cf16dc83..0b15876e96 100644
--- a/xen/arch/x86/boot/x86_32.S
+++ b/xen/arch/x86/boot/x86_32.S
@@ -169,7 +169,7 @@ ignore_int:
/*** STACK LOCATION ***/
ENTRY(stack_start)
- .long SYMBOL_NAME(cpu0_stack) + 8100 - __PAGE_OFFSET
+ .long SYMBOL_NAME(cpu0_stack) + STACK_SIZE - 200 - __PAGE_OFFSET
.long __HYPERVISOR_DS
/*** DESCRIPTOR TABLES ***/
diff --git a/xen/arch/x86/boot/x86_64.S b/xen/arch/x86/boot/x86_64.S
index a8253a4ce1..319f18a54b 100644
--- a/xen/arch/x86/boot/x86_64.S
+++ b/xen/arch/x86/boot/x86_64.S
@@ -52,16 +52,16 @@ __start:
/* Set up a few descriptors: on entry only CS is guaranteed good. */
lgdt %cs:0x1001f0
- mov $(__HYPERVISOR_DS),%ecx
+ mov $(__HYPERVISOR_DS32),%ecx
mov %ecx,%ds
mov %ecx,%es
- /* Check for Multiboot bootloader */
cmp $(SECONDARY_CPU_FLAG),%ebx
- je skip_multiboot_check
+ je skip_boot_checks
+
+ /* Check for Multiboot bootloader */
cmp $0x2BADB002,%eax
jne not_multiboot
-skip_multiboot_check:
/* Save the Multiboot info structure for later use. */
mov %ebx,0x1001e0
@@ -75,7 +75,8 @@ skip_multiboot_check:
cpuid
bt $29,%edx # Long mode feature?
jnc bad_cpu
-
+skip_boot_checks:
+
/* Set up FPU. */
fninit
@@ -106,10 +107,6 @@ skip_multiboot_check:
/* Install relocated selectors (FS/GS unused). */
lgdt gdt_descr(%rip)
- mov $(__HYPERVISOR_DS),%ecx
- mov %ecx,%ds
- mov %ecx,%es
- mov %ecx,%ss
/* Enable full CR4 features. */
mov mmu_cr4_features(%rip),%rcx
@@ -127,6 +124,13 @@ skip_multiboot_check:
ret
__high_start:
+ mov $(__HYPERVISOR_DS64),%ecx
+ mov %ecx,%ds
+ mov %ecx,%es
+ mov %ecx,%fs
+ mov %ecx,%gs
+ mov %ecx,%ss
+
lidt idt_descr(%rip)
cmp $(SECONDARY_CPU_FLAG),%ebx
@@ -156,16 +160,14 @@ __high_start:
lea start(%rip),%rax
sub $0x100000,%rax
add %rax,%rdi
- call cmain
+ call __start_xen
+ ud2 /* Force a panic (invalid opcode). */
/* This is the default interrupt handler. */
int_msg:
.asciz "Unknown interrupt\n"
ignore_int:
cld
- mov $(__HYPERVISOR_DS),%eax
- mov %eax,%ds
- mov %eax,%es
lea int_msg(%rip),%rdi
call SYMBOL_NAME(printf)
1: jmp 1b
@@ -187,14 +189,14 @@ ignore_int:
ENTRY(gdt_table)
.fill FIRST_RESERVED_GDT_ENTRY,8,0
.quad 0x0000000000000000 /* unused */
- .quad 0x00cf9a000000ffff /* 0x0808 ring 0 code, compatability */
+ .quad 0x00cf9a000000ffff /* 0x0808 ring 0 code, compatibility */
.quad 0x00af9a000000ffff /* 0x0810 ring 0 code, 64-bit mode */
.quad 0x00cf92000000ffff /* 0x0818 ring 0 data */
.quad 0x00cffa000000ffff /* 0x0823 ring 3 code, compatibility */
.quad 0x00affa000000ffff /* 0x082b ring 3 code, 64-bit mode */
.quad 0x00cff2000000ffff /* 0x0833 ring 3 data */
.quad 0x0000000000000000 /* unused */
- .fill 2*NR_CPUS,8,0 /* space for TSS and LDT per CPU */
+ .fill 4*NR_CPUS,8,0 /* space for TSS and LDT per CPU */
.word 0
gdt_descr:
@@ -204,12 +206,12 @@ SYMBOL_NAME(gdt):
.word 0
idt_descr:
- .word 256*8-1
+ .word 256*16-1
SYMBOL_NAME(idt):
.quad SYMBOL_NAME(idt_table)
ENTRY(stack_start)
- .quad SYMBOL_NAME(cpu0_stack) + 8100
+ .quad SYMBOL_NAME(cpu0_stack) + STACK_SIZE - 200
high_start:
.quad __high_start
@@ -246,33 +248,3 @@ ENTRY(cpu0_stack) # Initial stack is 8kB
.org 0x6000
ENTRY(stext)
ENTRY(_stext)
-
-.globl map_domain_mem, unmap_domain_mem, ret_from_intr
-map_domain_mem:
-unmap_domain_mem:
-ret_from_intr:
-#undef machine_to_phys_mapping
-.globl copy_to_user, set_intr_gate, die, machine_to_phys_mapping
-copy_to_user:
-set_intr_gate:
-die:
-machine_to_phys_mapping:
-.globl copy_from_user, show_registers, do_iopl
-copy_from_user:
-show_registers:
-do_iopl:
-.globl idt_table, copy_user_generic, memcmp, idt_tables, new_thread
-idt_table:
-copy_user_generic:
-memcmp:
-idt_tables:
-new_thread:
-.globl switch_to, __get_user_1, __get_user_4, __get_user_8, trap_init
-switch_to:
-__get_user_1:
-__get_user_4:
-__get_user_8:
-trap_init:
-.globl set_debugreg
-set_debugreg:
-
diff --git a/xen/arch/x86/dom0_ops.c b/xen/arch/x86/dom0_ops.c
index b6ade93ee7..84bc49eed6 100644
--- a/xen/arch/x86/dom0_ops.c
+++ b/xen/arch/x86/dom0_ops.c
@@ -15,7 +15,6 @@
#include <xen/event.h>
#include <asm/domain_page.h>
#include <asm/msr.h>
-#include <asm/pdb.h>
#include <xen/trace.h>
#include <xen/console.h>
#include <asm/shadow.h>
@@ -50,7 +49,7 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op)
{
long ret = 0;
- if ( !IS_PRIV(current) )
+ if ( !IS_PRIV(current->domain) )
return -EPERM;
switch ( op->cmd )
@@ -299,6 +298,44 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op)
}
break;
+ case DOM0_GETMEMLIST:
+ {
+ int i;
+ struct domain *d = find_domain_by_id(op->u.getmemlist.domain);
+ unsigned long max_pfns = op->u.getmemlist.max_pfns;
+ unsigned long pfn;
+ unsigned long *buffer = op->u.getmemlist.buffer;
+ struct list_head *list_ent;
+
+ ret = -EINVAL;
+ if ( d != NULL )
+ {
+ ret = 0;
+
+ spin_lock(&d->page_alloc_lock);
+ list_ent = d->page_list.next;
+ for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ )
+ {
+ pfn = list_entry(list_ent, struct pfn_info, list) -
+ frame_table;
+ if ( put_user(pfn, buffer) )
+ {
+ ret = -EFAULT;
+ break;
+ }
+ buffer++;
+ list_ent = frame_table[pfn].list.next;
+ }
+ spin_unlock(&d->page_alloc_lock);
+
+ op->u.getmemlist.num_pfns = i;
+ copy_to_user(u_dom0_op, op, sizeof(*op));
+
+ put_domain(d);
+ }
+ }
+ break;
+
default:
ret = -ENOSYS;
@@ -307,49 +344,50 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op)
return ret;
}
-void arch_getdomaininfo_ctxt(struct domain *d, full_execution_context_t *c)
+void arch_getdomaininfo_ctxt(
+ struct exec_domain *ed, full_execution_context_t *c)
{
int i;
c->flags = 0;
memcpy(&c->cpu_ctxt,
- &d->thread.user_ctxt,
- sizeof(d->thread.user_ctxt));
- if ( test_bit(DF_DONEFPUINIT, &d->flags) )
+ &ed->arch.user_ctxt,
+ sizeof(ed->arch.user_ctxt));
+ if ( test_bit(EDF_DONEFPUINIT, &ed->ed_flags) )
c->flags |= ECF_I387_VALID;
memcpy(&c->fpu_ctxt,
- &d->thread.i387,
- sizeof(d->thread.i387));
+ &ed->arch.i387,
+ sizeof(ed->arch.i387));
memcpy(&c->trap_ctxt,
- d->thread.traps,
- sizeof(d->thread.traps));
+ ed->arch.traps,
+ sizeof(ed->arch.traps));
#ifdef ARCH_HAS_FAST_TRAP
- if ( (d->thread.fast_trap_desc.a == 0) &&
- (d->thread.fast_trap_desc.b == 0) )
+ if ( (ed->arch.fast_trap_desc.a == 0) &&
+ (ed->arch.fast_trap_desc.b == 0) )
c->fast_trap_idx = 0;
else
c->fast_trap_idx =
- d->thread.fast_trap_idx;
+ ed->arch.fast_trap_idx;
#endif
- c->ldt_base = d->mm.ldt_base;
- c->ldt_ents = d->mm.ldt_ents;
+ c->ldt_base = ed->arch.ldt_base;
+ c->ldt_ents = ed->arch.ldt_ents;
c->gdt_ents = 0;
- if ( GET_GDT_ADDRESS(d) == GDT_VIRT_START )
+ if ( GET_GDT_ADDRESS(ed) == GDT_VIRT_START(ed) )
{
for ( i = 0; i < 16; i++ )
c->gdt_frames[i] =
- l1_pgentry_to_pagenr(d->mm.perdomain_pt[i]);
- c->gdt_ents = GET_GDT_ENTRIES(d);
+ l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i]);
+ c->gdt_ents = GET_GDT_ENTRIES(ed);
}
- c->guestos_ss = d->thread.guestos_ss;
- c->guestos_esp = d->thread.guestos_sp;
+ c->guestos_ss = ed->arch.guestos_ss;
+ c->guestos_esp = ed->arch.guestos_sp;
c->pt_base =
- pagetable_val(d->mm.pagetable);
+ pagetable_val(ed->arch.pagetable);
memcpy(c->debugreg,
- d->thread.debugreg,
- sizeof(d->thread.debugreg));
- c->event_callback_cs = d->thread.event_selector;
- c->event_callback_eip = d->thread.event_address;
- c->failsafe_callback_cs = d->thread.failsafe_selector;
- c->failsafe_callback_eip = d->thread.failsafe_address;
+ ed->arch.debugreg,
+ sizeof(ed->arch.debugreg));
+ c->event_callback_cs = ed->arch.event_selector;
+ c->event_callback_eip = ed->arch.event_address;
+ c->failsafe_callback_cs = ed->arch.failsafe_selector;
+ c->failsafe_callback_eip = ed->arch.failsafe_address;
}
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 4ca96f5d3c..f456a7b79a 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* arch/x86/domain.c
*
@@ -33,26 +34,16 @@
#include <asm/shadow.h>
#include <xen/console.h>
#include <xen/elf.h>
+#include <asm/vmx.h>
+#include <asm/vmx_vmcs.h>
+#include <xen/kernel.h>
+#include <public/io/ioreq.h>
#include <xen/multicall.h>
/* opt_noreboot: If true, machine will need manual reset on error. */
static int opt_noreboot = 0;
boolean_param("noreboot", opt_noreboot);
-#if !defined(CONFIG_X86_64BITMODE)
-/* No ring-3 access in initial page tables. */
-#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
-#else
-/* Allow ring-3 access in long mode as guest cannot use ring 1. */
-#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
-#endif
-#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
-#define L3_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
-#define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
-
-#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
-#define round_pgdown(_p) ((_p)&PAGE_MASK)
-
static void default_idle(void)
{
__cli();
@@ -77,8 +68,8 @@ static __attribute_used__ void idle_loop(void)
void startup_cpu_idle_loop(void)
{
/* Just some sanity to ensure that the scheduler is set up okay. */
- ASSERT(current->id == IDLE_DOMAIN_ID);
- domain_unpause_by_systemcontroller(current);
+ ASSERT(current->domain->id == IDLE_DOMAIN_ID);
+ domain_unpause_by_systemcontroller(current->domain);
__enter_scheduler();
/*
@@ -162,6 +153,9 @@ void machine_restart(char * __unused)
smp_send_stop();
disable_IO_APIC();
#endif
+#ifdef CONFIG_VMX
+ stop_vmx();
+#endif
if(!reboot_thru_bios) {
/* rebooting needs to touch the page at absolute addr 0 */
@@ -216,121 +210,263 @@ void dump_pageframe_info(struct domain *d)
page->u.inuse.type_info);
}
-xmem_cache_t *domain_struct_cachep;
-void __init domain_startofday(void)
+struct domain *arch_alloc_domain_struct(void)
{
- domain_struct_cachep = xmem_cache_create(
- "domain_cache", sizeof(struct domain),
- 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
- if ( domain_struct_cachep == NULL )
- panic("No slab cache for domain structs.");
+ return xmalloc(struct domain);
}
-struct domain *arch_alloc_domain_struct(void)
+void arch_free_domain_struct(struct domain *d)
{
- return xmem_cache_alloc(domain_struct_cachep);
+ xfree(d);
}
-void arch_free_domain_struct(struct domain *d)
+struct exec_domain *arch_alloc_exec_domain_struct(void)
+{
+ return xmalloc(struct exec_domain);
+}
+
+void arch_free_exec_domain_struct(struct exec_domain *ed)
{
- xmem_cache_free(domain_struct_cachep, d);
+ xfree(ed);
}
void free_perdomain_pt(struct domain *d)
{
- free_xenheap_page((unsigned long)d->mm.perdomain_pt);
+ free_xenheap_page((unsigned long)d->arch.mm_perdomain_pt);
}
-static void continue_idle_task(struct domain *d)
+static void continue_idle_task(struct exec_domain *ed)
{
reset_stack_and_jump(idle_loop);
}
-static void continue_nonidle_task(struct domain *d)
+static void continue_nonidle_task(struct exec_domain *ed)
{
reset_stack_and_jump(ret_from_intr);
}
-void arch_do_createdomain(struct domain *d)
+void arch_do_createdomain(struct exec_domain *ed)
{
-#ifdef ARCH_HAS_FAST_TRAP
- SET_DEFAULT_FAST_TRAP(&d->thread);
-#endif
+ struct domain *d = ed->domain;
+
+ SET_DEFAULT_FAST_TRAP(&ed->arch);
if ( d->id == IDLE_DOMAIN_ID )
{
- d->thread.schedule_tail = continue_idle_task;
+ ed->arch.schedule_tail = continue_idle_task;
}
else
{
- d->thread.schedule_tail = continue_nonidle_task;
+ ed->arch.schedule_tail = continue_nonidle_task;
d->shared_info = (void *)alloc_xenheap_page();
memset(d->shared_info, 0, PAGE_SIZE);
- d->shared_info->arch.mfn_to_pfn_start = m2p_start_mfn;
+ ed->vcpu_info = &d->shared_info->vcpu_data[ed->eid];
SHARE_PFN_WITH_DOMAIN(virt_to_page(d->shared_info), d);
machine_to_phys_mapping[virt_to_phys(d->shared_info) >>
PAGE_SHIFT] = INVALID_P2M_ENTRY;
- d->mm.perdomain_pt = (l1_pgentry_t *)alloc_xenheap_page();
- memset(d->mm.perdomain_pt, 0, PAGE_SIZE);
- machine_to_phys_mapping[virt_to_phys(d->mm.perdomain_pt) >>
+ d->arch.mm_perdomain_pt = (l1_pgentry_t *)alloc_xenheap_page();
+ memset(d->arch.mm_perdomain_pt, 0, PAGE_SIZE);
+ machine_to_phys_mapping[virt_to_phys(d->arch.mm_perdomain_pt) >>
PAGE_SHIFT] = INVALID_P2M_ENTRY;
+ ed->arch.perdomain_ptes = d->arch.mm_perdomain_pt;
+ }
+}
+
+void arch_do_boot_vcpu(struct exec_domain *ed)
+{
+ struct domain *d = ed->domain;
+ ed->arch.schedule_tail = d->exec_domain[0]->arch.schedule_tail;
+ ed->arch.perdomain_ptes =
+ d->arch.mm_perdomain_pt + (ed->eid << PDPT_VCPU_SHIFT);
+}
+
+#ifdef CONFIG_VMX
+void arch_vmx_do_resume(struct exec_domain *ed)
+{
+ u64 vmcs_phys_ptr = (u64) virt_to_phys(ed->arch.arch_vmx.vmcs);
+
+ load_vmcs(&ed->arch.arch_vmx, vmcs_phys_ptr);
+ vmx_do_resume(ed);
+ reset_stack_and_jump(vmx_asm_do_resume);
+}
+
+void arch_vmx_do_launch(struct exec_domain *ed)
+{
+ u64 vmcs_phys_ptr = (u64) virt_to_phys(ed->arch.arch_vmx.vmcs);
+
+ load_vmcs(&ed->arch.arch_vmx, vmcs_phys_ptr);
+ vmx_do_launch(ed);
+ reset_stack_and_jump(vmx_asm_do_launch);
+}
+
+static void monitor_mk_pagetable(struct exec_domain *ed)
+{
+ unsigned long mpfn;
+ l2_pgentry_t *mpl2e;
+ struct pfn_info *mpfn_info;
+ struct domain *d = ed->domain;
+
+ mpfn_info = alloc_domheap_page(NULL);
+ ASSERT( mpfn_info );
+
+ mpfn = (unsigned long) (mpfn_info - frame_table);
+ mpl2e = (l2_pgentry_t *) map_domain_mem(mpfn << L1_PAGETABLE_SHIFT);
+ memset(mpl2e, 0, PAGE_SIZE);
+
+ memcpy(&mpl2e[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
+ &idle_pg_table[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
+ HYPERVISOR_ENTRIES_PER_L2_PAGETABLE * sizeof(l2_pgentry_t));
+
+ ed->arch.monitor_table = mk_pagetable(mpfn << L1_PAGETABLE_SHIFT);
+ d->arch.shadow_mode = SHM_full_32;
+
+ mpl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
+ mk_l2_pgentry((__pa(d->arch.mm_perdomain_pt) & PAGE_MASK)
+ | __PAGE_HYPERVISOR);
+
+ unmap_domain_mem(mpl2e);
+}
+
+/*
+ * Free the pages for monitor_table and guest_pl2e_cache
+ */
+static void monitor_rm_pagetable(struct exec_domain *ed)
+{
+ l2_pgentry_t *mpl2e;
+ unsigned long mpfn;
+
+ ASSERT( pagetable_val(ed->arch.monitor_table) );
+
+ mpl2e = (l2_pgentry_t *) map_domain_mem(pagetable_val(ed->arch.monitor_table));
+ /*
+ * First get the pfn for guest_pl2e_cache by looking at monitor_table
+ */
+ mpfn = l2_pgentry_val(mpl2e[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT])
+ >> PAGE_SHIFT;
+
+ free_domheap_page(&frame_table[mpfn]);
+ unmap_domain_mem(mpl2e);
+
+ /*
+ * Then free monitor_table.
+ */
+ mpfn = (pagetable_val(ed->arch.monitor_table)) >> PAGE_SHIFT;
+ free_domheap_page(&frame_table[mpfn]);
+
+ ed->arch.monitor_table = mk_pagetable(0);
+}
+
+static int vmx_final_setup_guestos(struct exec_domain *ed,
+ full_execution_context_t *full_context)
+{
+ int error;
+ execution_context_t *context;
+ struct vmcs_struct *vmcs;
+
+ context = &full_context->cpu_ctxt;
+
+ /*
+ * Create a new VMCS
+ */
+ if (!(vmcs = alloc_vmcs())) {
+ printk("Failed to create a new VMCS\n");
+ return -ENOMEM;
}
+
+ memset(&ed->arch.arch_vmx, 0, sizeof (struct arch_vmx_struct));
+
+ ed->arch.arch_vmx.vmcs = vmcs;
+ error = construct_vmcs(&ed->arch.arch_vmx, context, full_context, VMCS_USE_HOST_ENV);
+ if (error < 0) {
+ printk("Failed to construct a new VMCS\n");
+ goto out;
+ }
+
+ monitor_mk_pagetable(ed);
+ ed->arch.schedule_tail = arch_vmx_do_launch;
+ clear_bit(VMX_CPU_STATE_PG_ENABLED, &ed->arch.arch_vmx.cpu_state);
+
+#if defined (__i386)
+ ed->arch.arch_vmx.vmx_platform.real_mode_data =
+ (unsigned long *) context->esi;
+#endif
+
+ if (ed == ed->domain->exec_domain[0]) {
+ /*
+ * Required to do this once per domain
+ */
+ memset(&ed->domain->shared_info->evtchn_mask[0], 0xff,
+ sizeof(ed->domain->shared_info->evtchn_mask));
+ clear_bit(IOPACKET_PORT, &ed->domain->shared_info->evtchn_mask[0]);
+ }
+
+ return 0;
+
+out:
+ free_vmcs(vmcs);
+ ed->arch.arch_vmx.vmcs = 0;
+ return error;
}
+#endif
-int arch_final_setup_guestos(struct domain *d, full_execution_context_t *c)
+int arch_final_setup_guestos(
+ struct exec_domain *d, full_execution_context_t *c)
{
unsigned long phys_basetab;
int i, rc;
- clear_bit(DF_DONEFPUINIT, &d->flags);
+ clear_bit(EDF_DONEFPUINIT, &d->ed_flags);
if ( c->flags & ECF_I387_VALID )
- set_bit(DF_DONEFPUINIT, &d->flags);
+ set_bit(EDF_DONEFPUINIT, &d->ed_flags);
- memcpy(&d->thread.user_ctxt,
+ memcpy(&d->arch.user_ctxt,
&c->cpu_ctxt,
- sizeof(d->thread.user_ctxt));
+ sizeof(d->arch.user_ctxt));
+
+ /* Clear IOPL for unprivileged domains. */
+ if (!IS_PRIV(d->domain))
+ d->arch.user_ctxt.eflags &= 0xffffcfff;
/*
* This is sufficient! If the descriptor DPL differs from CS RPL then we'll
* #GP. If DS, ES, FS, GS are DPL 0 then they'll be cleared automatically.
* If SS RPL or DPL differs from CS RPL then we'll #GP.
*/
- if ( ((d->thread.user_ctxt.cs & 3) == 0) ||
- ((d->thread.user_ctxt.ss & 3) == 0) )
- return -EINVAL;
+ if (!(c->flags & ECF_VMX_GUEST))
+ if ( ((d->arch.user_ctxt.cs & 3) == 0) ||
+ ((d->arch.user_ctxt.ss & 3) == 0) )
+ return -EINVAL;
- memcpy(&d->thread.i387,
+ memcpy(&d->arch.i387,
&c->fpu_ctxt,
- sizeof(d->thread.i387));
+ sizeof(d->arch.i387));
- memcpy(d->thread.traps,
+ memcpy(d->arch.traps,
&c->trap_ctxt,
- sizeof(d->thread.traps));
+ sizeof(d->arch.traps));
-#ifdef ARCH_HAS_FAST_TRAP
if ( (rc = (int)set_fast_trap(d, c->fast_trap_idx)) != 0 )
return rc;
-#endif
- d->mm.ldt_base = c->ldt_base;
- d->mm.ldt_ents = c->ldt_ents;
+ d->arch.ldt_base = c->ldt_base;
+ d->arch.ldt_ents = c->ldt_ents;
- d->thread.guestos_ss = c->guestos_ss;
- d->thread.guestos_sp = c->guestos_esp;
+ d->arch.guestos_ss = c->guestos_ss;
+ d->arch.guestos_sp = c->guestos_esp;
for ( i = 0; i < 8; i++ )
(void)set_debugreg(d, i, c->debugreg[i]);
- d->thread.event_selector = c->event_callback_cs;
- d->thread.event_address = c->event_callback_eip;
- d->thread.failsafe_selector = c->failsafe_callback_cs;
- d->thread.failsafe_address = c->failsafe_callback_eip;
+ d->arch.event_selector = c->event_callback_cs;
+ d->arch.event_address = c->event_callback_eip;
+ d->arch.failsafe_selector = c->failsafe_callback_cs;
+ d->arch.failsafe_address = c->failsafe_callback_eip;
phys_basetab = c->pt_base;
- d->mm.pagetable = mk_pagetable(phys_basetab);
- if ( !get_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT], d,
+ d->arch.pagetable = mk_pagetable(phys_basetab);
+ if ( !get_page_and_type(&frame_table[phys_basetab>>PAGE_SHIFT], d->domain,
PGT_base_page_table) )
return -EINVAL;
@@ -346,28 +482,32 @@ int arch_final_setup_guestos(struct domain *d, full_execution_context_t *c)
}
}
+#ifdef CONFIG_VMX
+ if (c->flags & ECF_VMX_GUEST)
+ return vmx_final_setup_guestos(d, c);
+#endif
+
return 0;
}
-#if defined(__i386__)
-
-void new_thread(struct domain *d,
+void new_thread(struct exec_domain *d,
unsigned long start_pc,
unsigned long start_stack,
unsigned long start_info)
{
- execution_context_t *ec = &d->thread.user_ctxt;
+ execution_context_t *ec = &d->arch.user_ctxt;
/*
* Initial register values:
- * DS,ES,FS,GS = FLAT_RING1_DS
- * CS:EIP = FLAT_RING1_CS:start_pc
- * SS:ESP = FLAT_RING1_DS:start_stack
+ * DS,ES,FS,GS = FLAT_GUESTOS_DS
+ * CS:EIP = FLAT_GUESTOS_CS:start_pc
+ * SS:ESP = FLAT_GUESTOS_SS:start_stack
* ESI = start_info
* [EAX,EBX,ECX,EDX,EDI,EBP are zero]
*/
- ec->ds = ec->es = ec->fs = ec->gs = ec->ss = FLAT_RING1_DS;
- ec->cs = FLAT_RING1_CS;
+ ec->ds = ec->es = ec->fs = ec->gs = FLAT_GUESTOS_DS;
+ ec->ss = FLAT_GUESTOS_SS;
+ ec->cs = FLAT_GUESTOS_CS;
ec->eip = start_pc;
ec->esp = start_stack;
ec->esi = start_info;
@@ -380,74 +520,92 @@ void new_thread(struct domain *d,
/*
* This special macro can be used to load a debugging register
*/
-#define loaddebug(thread,register) \
- __asm__("movl %0,%%db" #register \
+#define loaddebug(_ed,_reg) \
+ __asm__("mov %0,%%db" #_reg \
: /* no output */ \
- :"r" (thread->debugreg[register]))
+ :"r" ((_ed)->debugreg[_reg]))
-
-void switch_to(struct domain *prev_p, struct domain *next_p)
+void switch_to(struct exec_domain *prev_p, struct exec_domain *next_p)
{
- struct thread_struct *next = &next_p->thread;
struct tss_struct *tss = init_tss + smp_processor_id();
execution_context_t *stack_ec = get_execution_context();
int i;
-
+#ifdef CONFIG_VMX
+ unsigned long vmx_domain = next_p->arch.arch_vmx.flags;
+#endif
+
__cli();
/* Switch guest general-register state. */
- if ( !is_idle_task(prev_p) )
+ if ( !is_idle_task(prev_p->domain) )
{
- memcpy(&prev_p->thread.user_ctxt,
+ memcpy(&prev_p->arch.user_ctxt,
stack_ec,
sizeof(*stack_ec));
unlazy_fpu(prev_p);
- CLEAR_FAST_TRAP(&prev_p->thread);
+ CLEAR_FAST_TRAP(&prev_p->arch);
}
- if ( !is_idle_task(next_p) )
+ if ( !is_idle_task(next_p->domain) )
{
memcpy(stack_ec,
- &next_p->thread.user_ctxt,
+ &next_p->arch.user_ctxt,
sizeof(*stack_ec));
- SET_FAST_TRAP(&next_p->thread);
-
- /* Switch the guest OS ring-1 stack. */
- tss->esp1 = next->guestos_sp;
- tss->ss1 = next->guestos_ss;
-
/* Maybe switch the debug registers. */
- if ( unlikely(next->debugreg[7]) )
+ if ( unlikely(next_p->arch.debugreg[7]) )
{
- loaddebug(next, 0);
- loaddebug(next, 1);
- loaddebug(next, 2);
- loaddebug(next, 3);
+ loaddebug(&next_p->arch, 0);
+ loaddebug(&next_p->arch, 1);
+ loaddebug(&next_p->arch, 2);
+ loaddebug(&next_p->arch, 3);
/* no 4 and 5 */
- loaddebug(next, 6);
- loaddebug(next, 7);
+ loaddebug(&next_p->arch, 6);
+ loaddebug(&next_p->arch, 7);
+ }
+
+#ifdef CONFIG_VMX
+ if ( vmx_domain )
+ {
+ /* Switch page tables. */
+ write_ptbase(next_p);
+
+ set_current(next_p);
+ /* Switch GDT and LDT. */
+ __asm__ __volatile__ ("lgdt %0" : "=m" (*next_p->arch.gdt));
+
+ __sti();
+ return;
}
+#endif
+
+ SET_FAST_TRAP(&next_p->arch);
+
+#ifdef __i386__
+ /* Switch the guest OS ring-1 stack. */
+ tss->esp1 = next_p->arch.guestos_sp;
+ tss->ss1 = next_p->arch.guestos_ss;
+#endif
/* Switch page tables. */
- write_ptbase(&next_p->mm);
+ write_ptbase(next_p);
}
- if ( unlikely(prev_p->thread.io_bitmap != NULL) )
+ if ( unlikely(prev_p->arch.io_bitmap != NULL) )
{
- for ( i = 0; i < sizeof(prev_p->thread.io_bitmap_sel) * 8; i++ )
- if ( !test_bit(i, &prev_p->thread.io_bitmap_sel) )
+ for ( i = 0; i < sizeof(prev_p->arch.io_bitmap_sel) * 8; i++ )
+ if ( !test_bit(i, &prev_p->arch.io_bitmap_sel) )
memset(&tss->io_bitmap[i * IOBMP_BYTES_PER_SELBIT],
~0U, IOBMP_BYTES_PER_SELBIT);
tss->bitmap = IOBMP_INVALID_OFFSET;
}
- if ( unlikely(next_p->thread.io_bitmap != NULL) )
+ if ( unlikely(next_p->arch.io_bitmap != NULL) )
{
- for ( i = 0; i < sizeof(next_p->thread.io_bitmap_sel) * 8; i++ )
- if ( !test_bit(i, &next_p->thread.io_bitmap_sel) )
+ for ( i = 0; i < sizeof(next_p->arch.io_bitmap_sel) * 8; i++ )
+ if ( !test_bit(i, &next_p->arch.io_bitmap_sel) )
memcpy(&tss->io_bitmap[i * IOBMP_BYTES_PER_SELBIT],
- &next_p->thread.io_bitmap[i * IOBMP_BYTES_PER_SELBIT],
+ &next_p->arch.io_bitmap[i * IOBMP_BYTES_PER_SELBIT],
IOBMP_BYTES_PER_SELBIT);
tss->bitmap = IOBMP_OFFSET;
}
@@ -455,7 +613,7 @@ void switch_to(struct domain *prev_p, struct domain *next_p)
set_current(next_p);
/* Switch GDT and LDT. */
- __asm__ __volatile__ ("lgdt %0" : "=m" (*next_p->mm.gdt));
+ __asm__ __volatile__ ("lgdt %0" : "=m" (*next_p->arch.gdt));
load_LDT(next_p);
__sti();
@@ -470,8 +628,6 @@ long do_iopl(domid_t domain, unsigned int new_io_pl)
return 0;
}
-#endif
-
unsigned long hypercall_create_continuation(
unsigned int op, unsigned int nr_args, ...)
{
@@ -567,9 +723,42 @@ static void relinquish_list(struct domain *d, struct list_head *list)
spin_unlock_recursive(&d->page_alloc_lock);
}
+#ifdef CONFIG_VMX
+static void vmx_domain_relinquish_memory(struct exec_domain *ed)
+{
+ struct domain *d = ed->domain;
+
+ /*
+ * Free VMCS
+ */
+ ASSERT(ed->arch.arch_vmx.vmcs);
+ free_vmcs(ed->arch.arch_vmx.vmcs);
+ ed->arch.arch_vmx.vmcs = 0;
+
+ monitor_rm_pagetable(ed);
+
+ if (ed == d->exec_domain[0]) {
+ int i;
+ unsigned long pfn;
+
+ for (i = 0; i < ENTRIES_PER_L1_PAGETABLE; i++) {
+ unsigned long l1e;
+
+ l1e = l1_pgentry_val(d->arch.mm_perdomain_pt[i]);
+ if (l1e & _PAGE_PRESENT) {
+ pfn = l1e >> PAGE_SHIFT;
+ free_domheap_page(&frame_table[pfn]);
+ }
+ }
+ }
+
+}
+#endif
void domain_relinquish_memory(struct domain *d)
{
+ struct exec_domain *ed;
+
/* Ensure that noone is running over the dead domain's page tables. */
synchronise_pagetables(~0UL);
@@ -577,377 +766,28 @@ void domain_relinquish_memory(struct domain *d)
shadow_mode_disable(d);
/* Drop the in-use reference to the page-table base. */
- if ( pagetable_val(d->mm.pagetable) != 0 )
- put_page_and_type(&frame_table[pagetable_val(d->mm.pagetable) >>
- PAGE_SHIFT]);
+ for_each_exec_domain ( d, ed )
+ {
+ if ( pagetable_val(ed->arch.pagetable) != 0 )
+ put_page_and_type(&frame_table[pagetable_val(ed->arch.pagetable) >>
+ PAGE_SHIFT]);
+ }
+
+#ifdef CONFIG_VMX
+ if ( VMX_DOMAIN(d->exec_domain[0]) )
+ for_each_exec_domain ( d, ed )
+ vmx_domain_relinquish_memory(ed);
+#endif
/*
* Relinquish GDT mappings. No need for explicit unmapping of the LDT as
* it automatically gets squashed when the guest's mappings go away.
*/
- destroy_gdt(d);
+ for_each_exec_domain(d, ed)
+ destroy_gdt(ed);
/* Relinquish every page of memory. */
relinquish_list(d, &d->xenpage_list);
relinquish_list(d, &d->page_list);
}
-
-int construct_dom0(struct domain *p,
- unsigned long alloc_start,
- unsigned long alloc_end,
- char *image_start, unsigned long image_len,
- char *initrd_start, unsigned long initrd_len,
- char *cmdline)
-{
- char *dst;
- int i, rc;
- unsigned long pfn, mfn;
- unsigned long nr_pages = (alloc_end - alloc_start) >> PAGE_SHIFT;
- unsigned long nr_pt_pages;
- unsigned long count;
- l2_pgentry_t *l2tab, *l2start;
- l1_pgentry_t *l1tab = NULL, *l1start = NULL;
- struct pfn_info *page = NULL;
- start_info_t *si;
-
- /*
- * This fully describes the memory layout of the initial domain. All
- * *_start address are page-aligned, except v_start (and v_end) which are
- * superpage-aligned.
- */
- struct domain_setup_info dsi;
- unsigned long vinitrd_start;
- unsigned long vinitrd_end;
- unsigned long vphysmap_start;
- unsigned long vphysmap_end;
- unsigned long vstartinfo_start;
- unsigned long vstartinfo_end;
- unsigned long vstack_start;
- unsigned long vstack_end;
- unsigned long vpt_start;
- unsigned long vpt_end;
- unsigned long v_end;
-
- /* Machine address of next candidate page-table page. */
- unsigned long mpt_alloc;
-
- extern void physdev_init_dom0(struct domain *);
-
- /* Sanity! */
- if ( p->id != 0 )
- BUG();
- if ( test_bit(DF_CONSTRUCTED, &p->flags) )
- BUG();
-
- memset(&dsi, 0, sizeof(struct domain_setup_info));
-
- printk("*** LOADING DOMAIN 0 ***\n");
-
- /*
- * This is all a bit grim. We've moved the modules to the "safe" physical
- * memory region above MAP_DIRECTMAP_ADDRESS (48MB). Later in this
- * routine we're going to copy it down into the region that's actually
- * been allocated to domain 0. This is highly likely to be overlapping, so
- * we use a forward copy.
- *
- * MAP_DIRECTMAP_ADDRESS should be safe. The worst case is a machine with
- * 4GB and lots of network/disk cards that allocate loads of buffers.
- * We'll have to revisit this if we ever support PAE (64GB).
- */
-
- rc = parseelfimage(image_start, image_len, &dsi);
- if ( rc != 0 )
- return rc;
-
- /* Set up domain options */
- if ( dsi.use_writable_pagetables )
- vm_assist(p, VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
-
- if ( (dsi.v_start & (PAGE_SIZE-1)) != 0 )
- {
- printk("Initial guest OS must load to a page boundary.\n");
- return -EINVAL;
- }
-
- /*
- * Why do we need this? The number of page-table frames depends on the
- * size of the bootstrap address space. But the size of the address space
- * depends on the number of page-table frames (since each one is mapped
- * read-only). We have a pair of simultaneous equations in two unknowns,
- * which we solve by exhaustive search.
- */
- vinitrd_start = round_pgup(dsi.v_kernend);
- vinitrd_end = vinitrd_start + initrd_len;
- vphysmap_start = round_pgup(vinitrd_end);
- vphysmap_end = vphysmap_start + (nr_pages * sizeof(unsigned long));
- vpt_start = round_pgup(vphysmap_end);
- for ( nr_pt_pages = 2; ; nr_pt_pages++ )
- {
- vpt_end = vpt_start + (nr_pt_pages * PAGE_SIZE);
- vstartinfo_start = vpt_end;
- vstartinfo_end = vstartinfo_start + PAGE_SIZE;
- vstack_start = vstartinfo_end;
- vstack_end = vstack_start + PAGE_SIZE;
- v_end = (vstack_end + (1<<22)-1) & ~((1<<22)-1);
- if ( (v_end - vstack_end) < (512 << 10) )
- v_end += 1 << 22; /* Add extra 4MB to get >= 512kB padding. */
- if ( (((v_end - dsi.v_start + ((1<<L2_PAGETABLE_SHIFT)-1)) >>
- L2_PAGETABLE_SHIFT) + 1) <= nr_pt_pages )
- break;
- }
-
- printk("PHYSICAL MEMORY ARRANGEMENT:\n"
- " Kernel image: %p->%p\n"
- " Initrd image: %p->%p\n"
- " Dom0 alloc.: %08lx->%08lx\n",
- image_start, image_start + image_len,
- initrd_start, initrd_start + initrd_len,
- alloc_start, alloc_end);
- printk("VIRTUAL MEMORY ARRANGEMENT:\n"
- " Loaded kernel: %08lx->%08lx\n"
- " Init. ramdisk: %08lx->%08lx\n"
- " Phys-Mach map: %08lx->%08lx\n"
- " Page tables: %08lx->%08lx\n"
- " Start info: %08lx->%08lx\n"
- " Boot stack: %08lx->%08lx\n"
- " TOTAL: %08lx->%08lx\n",
- dsi.v_kernstart, dsi.v_kernend,
- vinitrd_start, vinitrd_end,
- vphysmap_start, vphysmap_end,
- vpt_start, vpt_end,
- vstartinfo_start, vstartinfo_end,
- vstack_start, vstack_end,
- dsi.v_start, v_end);
- printk(" ENTRY ADDRESS: %08lx\n", dsi.v_kernentry);
-
- if ( (v_end - dsi.v_start) > (nr_pages * PAGE_SIZE) )
- {
- printk("Initial guest OS requires too much space\n"
- "(%luMB is greater than %luMB limit)\n",
- (v_end-dsi.v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
- return -ENOMEM;
- }
-
- /*
- * Protect the lowest 1GB of memory. We use a temporary mapping there
- * from which we copy the kernel and ramdisk images.
- */
- if ( dsi.v_start < (1<<30) )
- {
- printk("Initial loading isn't allowed to lowest 1GB of memory.\n");
- return -EINVAL;
- }
-
- /* Paranoia: scrub DOM0's memory allocation. */
- printk("Scrubbing DOM0 RAM: ");
- dst = (char *)alloc_start;
- while ( dst < (char *)alloc_end )
- {
-#define SCRUB_BYTES (100 * 1024 * 1024) /* 100MB */
- printk(".");
- touch_nmi_watchdog();
- if ( ((char *)alloc_end - dst) > SCRUB_BYTES )
- {
- memset(dst, 0, SCRUB_BYTES);
- dst += SCRUB_BYTES;
- }
- else
- {
- memset(dst, 0, (char *)alloc_end - dst);
- break;
- }
- }
- printk("done.\n");
-
- /* Construct a frame-allocation list for the initial domain. */
- for ( mfn = (alloc_start>>PAGE_SHIFT);
- mfn < (alloc_end>>PAGE_SHIFT);
- mfn++ )
- {
- page = &frame_table[mfn];
- page->u.inuse.domain = p;
- page->u.inuse.type_info = 0;
- page->count_info = PGC_allocated | 1;
- list_add_tail(&page->list, &p->page_list);
- p->tot_pages++; p->max_pages++;
- }
-
- mpt_alloc = (vpt_start - dsi.v_start) + alloc_start;
-
- SET_GDT_ENTRIES(p, DEFAULT_GDT_ENTRIES);
- SET_GDT_ADDRESS(p, DEFAULT_GDT_ADDRESS);
-
- /*
- * We're basically forcing default RPLs to 1, so that our "what privilege
- * level are we returning to?" logic works.
- */
- p->thread.failsafe_selector = FLAT_GUESTOS_CS;
- p->thread.event_selector = FLAT_GUESTOS_CS;
- p->thread.guestos_ss = FLAT_GUESTOS_DS;
- for ( i = 0; i < 256; i++ )
- p->thread.traps[i].cs = FLAT_GUESTOS_CS;
-
- /* WARNING: The new domain must have its 'processor' field filled in! */
- l2start = l2tab = (l2_pgentry_t *)mpt_alloc; mpt_alloc += PAGE_SIZE;
- memcpy(l2tab, &idle_pg_table[0], PAGE_SIZE);
- l2tab[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry((unsigned long)l2start | __PAGE_HYPERVISOR);
- l2tab[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry(__pa(p->mm.perdomain_pt) | __PAGE_HYPERVISOR);
- p->mm.pagetable = mk_pagetable((unsigned long)l2start);
-
- l2tab += l2_table_offset(dsi.v_start);
- mfn = alloc_start >> PAGE_SHIFT;
- for ( count = 0; count < ((v_end-dsi.v_start)>>PAGE_SHIFT); count++ )
- {
- if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) )
- {
- l1start = l1tab = (l1_pgentry_t *)mpt_alloc;
- mpt_alloc += PAGE_SIZE;
- *l2tab++ = mk_l2_pgentry((unsigned long)l1start | L2_PROT);
- clear_page(l1tab);
- if ( count == 0 )
- l1tab += l1_table_offset(dsi.v_start);
- }
- *l1tab++ = mk_l1_pgentry((mfn << PAGE_SHIFT) | L1_PROT);
-
- page = &frame_table[mfn];
- if ( !get_page_and_type(page, p, PGT_writable_page) )
- BUG();
-
- mfn++;
- }
-
- /* Pages that are part of page tables must be read only. */
- l2tab = l2start + l2_table_offset(vpt_start);
- l1start = l1tab = (l1_pgentry_t *)l2_pgentry_to_phys(*l2tab);
- l1tab += l1_table_offset(vpt_start);
- l2tab++;
- for ( count = 0; count < nr_pt_pages; count++ )
- {
- *l1tab = mk_l1_pgentry(l1_pgentry_val(*l1tab) & ~_PAGE_RW);
- page = &frame_table[l1_pgentry_to_pagenr(*l1tab)];
- if ( count == 0 )
- {
- page->u.inuse.type_info &= ~PGT_type_mask;
- page->u.inuse.type_info |= PGT_l2_page_table;
-
- /*
- * No longer writable: decrement the type_count.
- * Installed as CR3: increment both the ref_count and type_count.
- * Net: just increment the ref_count.
- */
- get_page(page, p); /* an extra ref because of readable mapping */
-
- /* Get another ref to L2 page so that it can be pinned. */
- if ( !get_page_and_type(page, p, PGT_l2_page_table) )
- BUG();
- set_bit(_PGT_pinned, &page->u.inuse.type_info);
- }
- else
- {
- page->u.inuse.type_info &= ~PGT_type_mask;
- page->u.inuse.type_info |= PGT_l1_page_table;
- page->u.inuse.type_info |=
- ((dsi.v_start>>L2_PAGETABLE_SHIFT)+(count-1))<<PGT_va_shift;
-
- /*
- * No longer writable: decrement the type_count.
- * This is an L1 page, installed in a validated L2 page:
- * increment both the ref_count and type_count.
- * Net: just increment the ref_count.
- */
- get_page(page, p); /* an extra ref because of readable mapping */
- }
- l1tab++;
- if( !((unsigned long)l1tab & (PAGE_SIZE - 1)) )
- l1start = l1tab = (l1_pgentry_t *)l2_pgentry_to_phys(*l2tab);
- }
-
- /* Set up shared-info area. */
- update_dom_time(p->shared_info);
- p->shared_info->domain_time = 0;
- /* Mask all upcalls... */
- for ( i = 0; i < MAX_VIRT_CPUS; i++ )
- p->shared_info->vcpu_data[i].evtchn_upcall_mask = 1;
-
- /* Install the new page tables. */
- __cli();
- write_ptbase(&p->mm);
-
- /* Copy the OS image. */
- (void)loadelfimage(image_start);
-
- /* Copy the initial ramdisk. */
- if ( initrd_len != 0 )
- memcpy((void *)vinitrd_start, initrd_start, initrd_len);
-
- /* Set up start info area. */
- si = (start_info_t *)vstartinfo_start;
- memset(si, 0, PAGE_SIZE);
- si->nr_pages = p->tot_pages;
- si->shared_info = virt_to_phys(p->shared_info);
- si->flags = SIF_PRIVILEGED | SIF_INITDOMAIN;
- si->pt_base = vpt_start;
- si->nr_pt_frames = nr_pt_pages;
- si->mfn_list = vphysmap_start;
-
- /* Write the phys->machine and machine->phys table entries. */
- for ( pfn = 0; pfn < p->tot_pages; pfn++ )
- {
- mfn = pfn + (alloc_start>>PAGE_SHIFT);
-#ifndef NDEBUG
-#define REVERSE_START ((v_end - dsi.v_start) >> PAGE_SHIFT)
- if ( pfn > REVERSE_START )
- mfn = (alloc_end>>PAGE_SHIFT) - (pfn - REVERSE_START);
-#endif
- ((unsigned long *)vphysmap_start)[pfn] = mfn;
- machine_to_phys_mapping[mfn] = pfn;
- }
-
- if ( initrd_len != 0 )
- {
- si->mod_start = vinitrd_start;
- si->mod_len = initrd_len;
- printk("Initrd len 0x%lx, start at 0x%08lx\n",
- si->mod_len, si->mod_start);
- }
-
- dst = si->cmd_line;
- if ( cmdline != NULL )
- {
- for ( i = 0; i < 255; i++ )
- {
- if ( cmdline[i] == '\0' )
- break;
- *dst++ = cmdline[i];
- }
- }
- *dst = '\0';
-
- /* Reinstate the caller's page tables. */
- write_ptbase(&current->mm);
- __sti();
-
- /* Destroy low mappings - they were only for our convenience. */
- for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
- if ( l2_pgentry_val(l2start[i]) & _PAGE_PSE )
- l2start[i] = mk_l2_pgentry(0);
- zap_low_mappings(); /* Do the same for the idle page tables. */
-
- /* DOM0 gets access to everything. */
- physdev_init_dom0(p);
-
- set_bit(DF_CONSTRUCTED, &p->flags);
-
- new_thread(p, dsi.v_kernentry, vstack_end, vstartinfo_start);
-
-#if 0 /* XXXXX DO NOT CHECK IN ENABLED !!! (but useful for testing so leave) */
- shadow_lock(&p->mm);
- shadow_mode_enable(p, SHM_test);
- shadow_unlock(&p->mm);
-#endif
-
- return 0;
-}
diff --git a/xen/arch/x86/e820.c b/xen/arch/x86/e820.c
index 50f1b5fc8b..cf78c21844 100644
--- a/xen/arch/x86/e820.c
+++ b/xen/arch/x86/e820.c
@@ -305,17 +305,11 @@ static unsigned long __init find_max_pfn(void)
return max_pfn;
}
-static void __init machine_specific_memory_setup(
- struct e820entry *raw, int raw_nr)
+#ifdef __i386__
+static void __init clip_4gb(void)
{
- char nr = (char)raw_nr;
int i;
- sanitize_e820_map(raw, &nr);
-
- (void)copy_e820_map(raw, nr);
-
-#ifdef __i386__
/* 32-bit systems restricted to a 4GB physical memory map. */
for ( i = 0; i < e820.nr_map; i++ )
{
@@ -335,7 +329,18 @@ static void __init machine_specific_memory_setup(
e820.nr_map = i + 1;
}
}
+}
+#else
+#define clip_4gb() ((void)0)
#endif
+
+static void __init machine_specific_memory_setup(
+ struct e820entry *raw, int raw_nr)
+{
+ char nr = (char)raw_nr;
+ sanitize_e820_map(raw, &nr);
+ (void)copy_e820_map(raw, nr);
+ clip_4gb();
}
unsigned long init_e820(struct e820entry *raw, int raw_nr)
diff --git a/xen/arch/x86/i387.c b/xen/arch/x86/i387.c
index 6cc15dd3b5..902da0b57f 100644
--- a/xen/arch/x86/i387.c
+++ b/xen/arch/x86/i387.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/*
* linux/arch/i386/kernel/i387.c
*
@@ -17,40 +18,40 @@ void init_fpu(void)
{
__asm__("fninit");
if ( cpu_has_xmm ) load_mxcsr(0x1f80);
- set_bit(DF_DONEFPUINIT, &current->flags);
+ set_bit(EDF_DONEFPUINIT, &current->ed_flags);
}
-static inline void __save_init_fpu( struct domain *tsk )
+static inline void __save_init_fpu( struct exec_domain *tsk )
{
if ( cpu_has_fxsr ) {
asm volatile( "fxsave %0 ; fnclex"
- : "=m" (tsk->thread.i387) );
+ : "=m" (tsk->arch.i387) );
} else {
asm volatile( "fnsave %0 ; fwait"
- : "=m" (tsk->thread.i387) );
+ : "=m" (tsk->arch.i387) );
}
- clear_bit(DF_USEDFPU, &tsk->flags);
+ clear_bit(EDF_USEDFPU, &tsk->ed_flags);
}
-void save_init_fpu( struct domain *tsk )
+void save_init_fpu( struct exec_domain *tsk )
{
/*
* The guest OS may have set the 'virtual STTS' flag.
* This causes us to set the real flag, so we'll need
* to temporarily clear it while saving f-p state.
*/
- if ( test_bit(DF_GUEST_STTS, &tsk->flags) ) clts();
+ if ( test_bit(EDF_GUEST_STTS, &tsk->ed_flags) ) clts();
__save_init_fpu(tsk);
stts();
}
-void restore_fpu( struct domain *tsk )
+void restore_fpu( struct exec_domain *tsk )
{
if ( cpu_has_fxsr ) {
asm volatile( "fxrstor %0"
- : : "m" (tsk->thread.i387) );
+ : : "m" (tsk->arch.i387) );
} else {
asm volatile( "frstor %0"
- : : "m" (tsk->thread.i387) );
+ : : "m" (tsk->arch.i387) );
}
}
diff --git a/xen/arch/x86/idle0_task.c b/xen/arch/x86/idle0_task.c
index a8c670c573..b3cb95b81b 100644
--- a/xen/arch/x86/idle0_task.c
+++ b/xen/arch/x86/idle0_task.c
@@ -1,17 +1,19 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+
#include <xen/config.h>
#include <xen/sched.h>
#include <asm/desc.h>
-#define IDLE0_TASK(_t) \
-{ \
- processor: 0, \
- id: IDLE_DOMAIN_ID, \
- mm: IDLE0_MM, \
- thread: INIT_THREAD, \
- flags: 1<<DF_IDLETASK, \
- refcnt: ATOMIC_INIT(1) \
-}
+struct domain idle0_domain = {
+ id: IDLE_DOMAIN_ID,
+ d_flags: 1<<DF_IDLETASK,
+ refcnt: ATOMIC_INIT(1)
+};
-struct domain idle0_task = IDLE0_TASK(idle0_task);
+struct exec_domain idle0_exec_domain = {
+ processor: 0,
+ domain: &idle0_domain,
+ arch: IDLE0_ARCH_EXEC_DOMAIN
+};
struct tss_struct init_tss[NR_CPUS];
diff --git a/xen/arch/x86/io_apic.c b/xen/arch/x86/io_apic.c
index 5e3fa047f5..4f2cf3119c 100644
--- a/xen/arch/x86/io_apic.c
+++ b/xen/arch/x86/io_apic.c
@@ -615,6 +615,10 @@ static inline int IO_APIC_irq_trigger(int irq)
int irq_vector[NR_IRQS] = { FIRST_DEVICE_VECTOR , 0 };
+#ifdef CONFIG_VMX
+int vector_irq[256];
+#endif
+
static int __init assign_irq_vector(int irq)
{
static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
@@ -637,6 +641,10 @@ next:
panic("ran out of interrupt sources!");
IO_APIC_VECTOR(irq) = current_vector;
+#ifdef CONFIG_VMX
+ vector_irq[current_vector] = irq;
+ printk("vector_irq[%x] = %d\n", current_vector, irq);
+#endif
return current_vector;
}
diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c
index fd8648d454..210c52b8af 100644
--- a/xen/arch/x86/irq.c
+++ b/xen/arch/x86/irq.c
@@ -87,13 +87,9 @@ void enable_irq(unsigned int irq)
spin_unlock_irqrestore(&desc->lock, flags);
}
-asmlinkage void do_IRQ(struct xen_regs regs)
+asmlinkage void do_IRQ(struct xen_regs *regs)
{
-#if defined(__i386__)
- unsigned int irq = regs.entry_vector;
-#else
- unsigned int irq = 0; /* XXX */
-#endif
+ unsigned int irq = regs->entry_vector;
irq_desc_t *desc = &irq_desc[irq];
struct irqaction *action;
@@ -127,7 +123,7 @@ asmlinkage void do_IRQ(struct xen_regs regs)
desc->status &= ~IRQ_PENDING;
irq_enter(smp_processor_id(), irq);
spin_unlock_irq(&desc->lock);
- action->handler(irq, action->dev_id, &regs);
+ action->handler(irq, action->dev_id, regs);
spin_lock_irq(&desc->lock);
irq_exit(smp_processor_id(), irq);
}
@@ -188,22 +184,22 @@ typedef struct {
u8 nr_guests;
u8 in_flight;
u8 shareable;
- struct domain *guest[IRQ_MAX_GUESTS];
+ struct exec_domain *guest[IRQ_MAX_GUESTS];
} irq_guest_action_t;
static void __do_IRQ_guest(int irq)
{
irq_desc_t *desc = &irq_desc[irq];
irq_guest_action_t *action = (irq_guest_action_t *)desc->action;
- struct domain *d;
+ struct exec_domain *ed;
int i;
for ( i = 0; i < action->nr_guests; i++ )
{
- d = action->guest[i];
- if ( !test_and_set_bit(irq, &d->pirq_mask) )
+ ed = action->guest[i];
+ if ( !test_and_set_bit(irq, &ed->domain->pirq_mask) )
action->in_flight++;
- send_guest_pirq(d, irq);
+ send_guest_pirq(ed, irq);
}
}
@@ -235,8 +231,9 @@ int pirq_guest_unmask(struct domain *d)
return 0;
}
-int pirq_guest_bind(struct domain *d, int irq, int will_share)
+int pirq_guest_bind(struct exec_domain *ed, int irq, int will_share)
{
+ struct domain *d = ed->domain;
irq_desc_t *desc = &irq_desc[irq];
irq_guest_action_t *action;
unsigned long flags;
@@ -259,7 +256,7 @@ int pirq_guest_bind(struct domain *d, int irq, int will_share)
goto out;
}
- action = xmalloc(sizeof(irq_guest_action_t));
+ action = xmalloc(irq_guest_action_t);
if ( (desc->action = (struct irqaction *)action) == NULL )
{
DPRINTK("Cannot bind IRQ %d to guest. Out of memory.\n", irq);
@@ -279,7 +276,7 @@ int pirq_guest_bind(struct domain *d, int irq, int will_share)
/* Attempt to bind the interrupt target to the correct CPU. */
if ( desc->handler->set_affinity != NULL )
desc->handler->set_affinity(
- irq, apicid_to_phys_cpu_present(d->processor));
+ irq, apicid_to_phys_cpu_present(ed->processor));
}
else if ( !will_share || !action->shareable )
{
@@ -296,7 +293,7 @@ int pirq_guest_bind(struct domain *d, int irq, int will_share)
goto out;
}
- action->guest[action->nr_guests++] = d;
+ action->guest[action->nr_guests++] = ed;
out:
spin_unlock_irqrestore(&desc->lock, flags);
@@ -330,7 +327,7 @@ int pirq_guest_unbind(struct domain *d, int irq)
else
{
i = 0;
- while ( action->guest[i] != d )
+ while ( action->guest[i] && action->guest[i]->domain != d )
i++;
memmove(&action->guest[i], &action->guest[i+1], IRQ_MAX_GUESTS-i-1);
action->nr_guests--;
diff --git a/xen/arch/x86/memory.c b/xen/arch/x86/memory.c
index 486d6ba407..c532700e3c 100644
--- a/xen/arch/x86/memory.c
+++ b/xen/arch/x86/memory.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* arch/x86/memory.c
*
@@ -105,7 +106,7 @@
#ifdef VERBOSE
#define MEM_LOG(_f, _a...) \
printk("DOM%u: (file=memory.c, line=%d) " _f "\n", \
- current->id , __LINE__ , ## _a )
+ current->domain->id , __LINE__ , ## _a )
#else
#define MEM_LOG(_f, _a...) ((void)0)
#endif
@@ -136,7 +137,7 @@ static struct {
* Returns the current foreign domain; defaults to the currently-executing
* domain if a foreign override hasn't been specified.
*/
-#define FOREIGNDOM (percpu_info[smp_processor_id()].foreign ? : current)
+#define FOREIGNDOM (percpu_info[smp_processor_id()].foreign ? : current->domain)
/* Private domain structs for DOMID_XEN and DOMID_IO. */
static struct domain *dom_xen, *dom_io;
@@ -159,8 +160,8 @@ void __init init_frametable(void)
p = alloc_boot_pages(min(frame_table_size - i, 4UL << 20), 4UL << 20);
if ( p == 0 )
panic("Not enough memory for frame table\n");
- idle_pg_table[(FRAMETABLE_VIRT_START + i) >> L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry(p | __PAGE_HYPERVISOR | _PAGE_PSE);
+ map_pages(idle_pg_table, FRAMETABLE_VIRT_START + i, p,
+ 4UL << 20, PAGE_HYPERVISOR);
}
memset(frame_table, 0, frame_table_size);
@@ -168,30 +169,10 @@ void __init init_frametable(void)
void arch_init_memory(void)
{
- unsigned long i;
-
- /*
- * We are rather picky about the layout of 'struct pfn_info'. The
- * count_info and domain fields must be adjacent, as we perform atomic
- * 64-bit operations on them. Also, just for sanity, we assert the size
- * of the structure here.
- */
- if ( (offsetof(struct pfn_info, u.inuse.domain) !=
- (offsetof(struct pfn_info, count_info) + sizeof(u32))) ||
- (sizeof(struct pfn_info) != 24) )
- {
- printk("Weird pfn_info layout (%ld,%ld,%d)\n",
- offsetof(struct pfn_info, count_info),
- offsetof(struct pfn_info, u.inuse.domain),
- sizeof(struct pfn_info));
- for ( ; ; ) ;
- }
+ extern void subarch_init_memory(struct domain *);
memset(percpu_info, 0, sizeof(percpu_info));
- /* Initialise to a magic of 0x55555555 so easier to spot bugs later. */
- memset(machine_to_phys_mapping, 0x55, 4<<20);
-
/*
* Initialise our DOMID_XEN domain.
* Any Xen-heap pages that we will allow to be mapped will have
@@ -210,33 +191,47 @@ void arch_init_memory(void)
atomic_set(&dom_io->refcnt, 1);
dom_io->id = DOMID_IO;
- /* M2P table is mappable read-only by privileged domains. */
- for ( i = 0; i < 1024; i++ )
- {
- frame_table[m2p_start_mfn+i].count_info = PGC_allocated | 1;
- /* gdt to make sure it's only mapped read-only by non-privileged
- domains. */
- frame_table[m2p_start_mfn+i].u.inuse.type_info = PGT_gdt_page | 1;
- frame_table[m2p_start_mfn+i].u.inuse.domain = dom_xen;
- }
+ subarch_init_memory(dom_xen);
+}
+
+void write_ptbase(struct exec_domain *ed)
+{
+ struct domain *d = ed->domain;
+ unsigned long pa;
+
+#ifdef CONFIG_VMX
+ if ( unlikely(d->arch.shadow_mode) )
+ pa = ((d->arch.shadow_mode == SHM_full_32) ?
+ pagetable_val(ed->arch.monitor_table) :
+ pagetable_val(ed->arch.shadow_table));
+ else
+ pa = pagetable_val(ed->arch.pagetable);
+#else
+ if ( unlikely(d->arch.shadow_mode) )
+ pa = pagetable_val(ed->arch.shadow_table);
+ else
+ pa = pagetable_val(ed->arch.pagetable);
+#endif
+
+ write_cr3(pa);
}
-static void __invalidate_shadow_ldt(struct domain *d)
+static void __invalidate_shadow_ldt(struct exec_domain *d)
{
int i;
unsigned long pfn;
struct pfn_info *page;
- d->mm.shadow_ldt_mapcnt = 0;
+ d->arch.shadow_ldt_mapcnt = 0;
for ( i = 16; i < 32; i++ )
{
- pfn = l1_pgentry_to_pagenr(d->mm.perdomain_pt[i]);
+ pfn = l1_pgentry_to_pagenr(d->arch.perdomain_ptes[i]);
if ( pfn == 0 ) continue;
- d->mm.perdomain_pt[i] = mk_l1_pgentry(0);
+ d->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
page = &frame_table[pfn];
ASSERT_PAGE_IS_TYPE(page, PGT_ldt_page);
- ASSERT_PAGE_IS_DOMAIN(page, d);
+ ASSERT_PAGE_IS_DOMAIN(page, d->domain);
put_page_and_type(page);
}
@@ -245,9 +240,9 @@ static void __invalidate_shadow_ldt(struct domain *d)
}
-static inline void invalidate_shadow_ldt(struct domain *d)
+static inline void invalidate_shadow_ldt(struct exec_domain *d)
{
- if ( d->mm.shadow_ldt_mapcnt != 0 )
+ if ( d->arch.shadow_ldt_mapcnt != 0 )
__invalidate_shadow_ldt(d);
}
@@ -273,13 +268,14 @@ static int alloc_segdesc_page(struct pfn_info *page)
/* Map shadow page at offset @off. */
int map_ldt_shadow_page(unsigned int off)
{
- struct domain *d = current;
+ struct exec_domain *ed = current;
+ struct domain *d = ed->domain;
unsigned long l1e;
if ( unlikely(in_irq()) )
BUG();
- __get_user(l1e, (unsigned long *)&linear_pg_table[(d->mm.ldt_base >>
+ __get_user(l1e, (unsigned long *)&linear_pg_table[(ed->arch.ldt_base >>
PAGE_SHIFT) + off]);
if ( unlikely(!(l1e & _PAGE_PRESENT)) ||
@@ -287,8 +283,8 @@ int map_ldt_shadow_page(unsigned int off)
d, PGT_ldt_page)) )
return 0;
- d->mm.perdomain_pt[off + 16] = mk_l1_pgentry(l1e | _PAGE_RW);
- d->mm.shadow_ldt_mapcnt++;
+ ed->arch.perdomain_ptes[off + 16] = mk_l1_pgentry(l1e | _PAGE_RW);
+ ed->arch.shadow_ldt_mapcnt++;
return 1;
}
@@ -414,7 +410,7 @@ get_page_from_l1e(
{
/* Revert to caller privileges if FD == DOMID_IO. */
if ( d == dom_io )
- d = current;
+ d = current->domain;
if ( IS_PRIV(d) )
return 1;
@@ -471,7 +467,7 @@ static void put_page_from_l1e(l1_pgentry_t l1e, struct domain *d)
if ( !(l1v & _PAGE_PRESENT) || !pfn_is_ram(pfn) )
return;
- e = page->u.inuse.domain;
+ e = page_get_owner(page);
if ( unlikely(e != d) )
{
/*
@@ -500,7 +496,7 @@ static void put_page_from_l1e(l1_pgentry_t l1e, struct domain *d)
if ( unlikely(((page->u.inuse.type_info & PGT_type_mask) ==
PGT_ldt_page)) &&
unlikely(((page->u.inuse.type_info & PGT_count_mask) != 0)) )
- invalidate_shadow_ldt(e);
+ invalidate_shadow_ldt(e->exec_domain[0]);
put_page(page);
}
}
@@ -520,7 +516,7 @@ static void put_page_from_l2e(l2_pgentry_t l2e, unsigned long pfn)
static int alloc_l2_table(struct pfn_info *page)
{
- struct domain *d = page->u.inuse.domain;
+ struct domain *d = page_get_owner(page);
unsigned long page_nr = page_to_pfn(page);
l2_pgentry_t *pl2e;
int i;
@@ -539,7 +535,7 @@ static int alloc_l2_table(struct pfn_info *page)
pl2e[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
mk_l2_pgentry((page_nr << PAGE_SHIFT) | __PAGE_HYPERVISOR);
pl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry(__pa(page->u.inuse.domain->mm.perdomain_pt) |
+ mk_l2_pgentry(__pa(page_get_owner(page)->arch.mm_perdomain_pt) |
__PAGE_HYPERVISOR);
#endif
@@ -557,7 +553,7 @@ static int alloc_l2_table(struct pfn_info *page)
static int alloc_l1_table(struct pfn_info *page)
{
- struct domain *d = page->u.inuse.domain;
+ struct domain *d = page_get_owner(page);
unsigned long page_nr = page_to_pfn(page);
l1_pgentry_t *pl1e;
int i;
@@ -597,7 +593,7 @@ static void free_l2_table(struct pfn_info *page)
static void free_l1_table(struct pfn_info *page)
{
- struct domain *d = page->u.inuse.domain;
+ struct domain *d = page_get_owner(page);
unsigned long page_nr = page - frame_table;
l1_pgentry_t *pl1e;
int i;
@@ -650,7 +646,7 @@ static int mod_l2_entry(l2_pgentry_t *pl2e,
if ( ((l2_pgentry_val(ol2e) ^ l2_pgentry_val(nl2e)) & ~0xffe) == 0 )
return update_l2e(pl2e, ol2e, nl2e);
- if ( unlikely(!get_page_from_l2e(nl2e, pfn, current,
+ if ( unlikely(!get_page_from_l2e(nl2e, pfn, current->domain,
((unsigned long)pl2e &
~PAGE_MASK) >> 2)) )
return 0;
@@ -697,7 +693,7 @@ static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e)
{
l1_pgentry_t ol1e;
unsigned long _ol1e;
- struct domain *d = current;
+ struct domain *d = current->domain;
if ( unlikely(__get_user(_ol1e, (unsigned long *)pl1e) != 0) )
{
@@ -758,7 +754,7 @@ int alloc_page_type(struct pfn_info *page, unsigned int type)
void free_page_type(struct pfn_info *page, unsigned int type)
{
- struct domain *d = page->u.inuse.domain;
+ struct domain *d = page_get_owner(page);
switch ( type )
{
@@ -774,11 +770,11 @@ void free_page_type(struct pfn_info *page, unsigned int type)
BUG();
}
- if ( unlikely(d->mm.shadow_mode) &&
- (get_shadow_status(&d->mm, page_to_pfn(page)) & PSH_shadowed) )
+ if ( unlikely(d->arch.shadow_mode) &&
+ (get_shadow_status(d, page_to_pfn(page)) & PSH_shadowed) )
{
unshadow_table(page_to_pfn(page), type);
- put_shadow_status(&d->mm);
+ put_shadow_status(d);
}
}
@@ -801,7 +797,7 @@ void put_page_type(struct pfn_info *page)
* See domain.c:relinquish_list().
*/
ASSERT((x & PGT_validated) ||
- test_bit(DF_DYING, &page->u.inuse.domain->flags));
+ test_bit(DF_DYING, &page_get_owner(page)->d_flags));
if ( unlikely((nx & PGT_count_mask) == 0) )
{
@@ -859,12 +855,12 @@ int get_page_type(struct pfn_info *page, u32 type)
* may be unnecessary (e.g., page was GDT/LDT) but those
* circumstances should be very rare.
*/
- struct domain *d = page->u.inuse.domain;
- if ( unlikely(NEED_FLUSH(tlbflush_time[d->processor],
+ struct domain *d = page_get_owner(page);
+ if ( unlikely(NEED_FLUSH(tlbflush_time[d->exec_domain[0]->processor],
page->tlbflush_timestamp)) )
{
perfc_incr(need_flush_tlb_flush);
- flush_tlb_cpu(d->processor);
+ flush_tlb_cpu(d->exec_domain[0]->processor);
}
/* We lose existing type, back pointer, and validity. */
@@ -936,14 +932,44 @@ int get_page_type(struct pfn_info *page, u32 type)
}
+int new_guest_cr3(unsigned long pfn)
+{
+ struct exec_domain *ed = current;
+ struct domain *d = ed->domain;
+ int okay, cpu = smp_processor_id();
+ unsigned long old_base_pfn;
+
+ okay = get_page_and_type_from_pagenr(pfn, PGT_l2_page_table, d);
+ if ( likely(okay) )
+ {
+ invalidate_shadow_ldt(ed);
+
+ percpu_info[cpu].deferred_ops &= ~DOP_FLUSH_TLB;
+ old_base_pfn = pagetable_val(ed->arch.pagetable) >> PAGE_SHIFT;
+ ed->arch.pagetable = mk_pagetable(pfn << PAGE_SHIFT);
+
+ shadow_mk_pagetable(ed);
+
+ write_ptbase(ed);
+
+ put_page_and_type(&frame_table[old_base_pfn]);
+ }
+ else
+ {
+ MEM_LOG("Error while installing new baseptr %08lx", pfn);
+ }
+
+ return okay;
+}
+
static int do_extended_command(unsigned long ptr, unsigned long val)
{
int okay = 1, cpu = smp_processor_id();
unsigned int cmd = val & MMUEXT_CMD_MASK;
unsigned long pfn = ptr >> PAGE_SHIFT;
- unsigned long old_base_pfn;
struct pfn_info *page = &frame_table[pfn];
- struct domain *d = current, *nd, *e;
+ struct exec_domain *ed = current;
+ struct domain *d = ed->domain, *nd, *e;
u32 x, y;
domid_t domid;
grant_ref_t gntref;
@@ -984,7 +1010,7 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
if ( unlikely(!(okay = get_page_from_pagenr(pfn, FOREIGNDOM))) )
{
MEM_LOG("Page %08lx bad domain (dom=%p)",
- ptr, page->u.inuse.domain);
+ ptr, page_get_owner(page));
}
else if ( likely(test_and_clear_bit(_PGT_pinned,
&page->u.inuse.type_info)) )
@@ -1001,25 +1027,7 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
break;
case MMUEXT_NEW_BASEPTR:
- okay = get_page_and_type_from_pagenr(pfn, PGT_l2_page_table, d);
- if ( likely(okay) )
- {
- invalidate_shadow_ldt(d);
-
- percpu_info[cpu].deferred_ops &= ~DOP_FLUSH_TLB;
- old_base_pfn = pagetable_val(d->mm.pagetable) >> PAGE_SHIFT;
- d->mm.pagetable = mk_pagetable(pfn << PAGE_SHIFT);
-
- shadow_mk_pagetable(&d->mm);
-
- write_ptbase(&d->mm);
-
- put_page_and_type(&frame_table[old_base_pfn]);
- }
- else
- {
- MEM_LOG("Error while installing new baseptr %08lx", ptr);
- }
+ okay = new_guest_cr3(pfn);
break;
case MMUEXT_TLB_FLUSH:
@@ -1053,13 +1061,13 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
okay = 0;
MEM_LOG("Bad args to SET_LDT: ptr=%08lx, ents=%08lx", ptr, ents);
}
- else if ( (d->mm.ldt_ents != ents) ||
- (d->mm.ldt_base != ptr) )
+ else if ( (ed->arch.ldt_ents != ents) ||
+ (ed->arch.ldt_base != ptr) )
{
- invalidate_shadow_ldt(d);
- d->mm.ldt_base = ptr;
- d->mm.ldt_ents = ents;
- load_LDT(d);
+ invalidate_shadow_ldt(ed);
+ ed->arch.ldt_base = ptr;
+ ed->arch.ldt_ents = ents;
+ load_LDT(ed);
percpu_info[cpu].deferred_ops &= ~DOP_RELOAD_LDT;
if ( ents != 0 )
percpu_info[cpu].deferred_ops |= DOP_RELOAD_LDT;
@@ -1132,7 +1140,7 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
* benign reference to the page (PGC_allocated). If that reference
* disappears then the deallocation routine will safely spin.
*/
- nd = page->u.inuse.domain;
+ nd = page_get_owner(page);
y = page->count_info;
do {
x = y;
@@ -1171,13 +1179,13 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
* Also, a domain mustn't have PGC_allocated pages when it is dying.
*/
ASSERT(e->tot_pages <= e->max_pages);
- if ( unlikely(test_bit(DF_DYING, &e->flags)) ||
+ if ( unlikely(test_bit(DF_DYING, &e->d_flags)) ||
unlikely(e->tot_pages == e->max_pages) ||
unlikely(!gnttab_prepare_for_transfer(e, d, gntref)) )
{
MEM_LOG("Transferee has no reservation headroom (%d,%d), or "
"provided a bad grant ref, or is dying (%08lx).\n",
- e->tot_pages, e->max_pages, e->flags);
+ e->tot_pages, e->max_pages, e->d_flags);
spin_unlock(&e->page_alloc_lock);
put_domain(e);
okay = 0;
@@ -1188,7 +1196,7 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
if ( unlikely(e->tot_pages++ == 0) )
get_knownalive_domain(e);
list_add_tail(&page->list, &e->page_list);
- page->u.inuse.domain = e;
+ page_set_owner(page, e);
spin_unlock(&e->page_alloc_lock);
@@ -1231,7 +1239,7 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
}
/* A domain shouldn't have PGC_allocated pages when it is dying. */
- if ( unlikely(test_bit(DF_DYING, &e->flags)) ||
+ if ( unlikely(test_bit(DF_DYING, &e->d_flags)) ||
unlikely(IS_XEN_HEAP_FRAME(page)) )
{
MEM_LOG("Reassignment page is Xen heap, or dest dom is dying.");
@@ -1244,7 +1252,7 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
* benign reference to the page (PGC_allocated). If that reference
* disappears then the deallocation routine will safely spin.
*/
- nd = page->u.inuse.domain;
+ nd = page_get_owner(page);
y = page->count_info;
do {
x = y;
@@ -1321,10 +1329,13 @@ int do_mmu_update(
unsigned int cmd, done = 0;
unsigned long prev_spfn = 0;
l1_pgentry_t *prev_spl1e = 0;
- struct domain *d = current;
+ struct exec_domain *ed = current;
+ struct domain *d = ed->domain;
u32 type_info;
domid_t domid;
+ LOCK_BIGLOCK(d);
+
cleanup_writable_pagetable(d);
/*
@@ -1346,7 +1357,7 @@ int do_mmu_update(
count &= ~MMU_UPDATE_PREEMPT_FDOM_MASK;
if ( unlikely(pdone != NULL) )
(void)get_user(done, pdone);
- if ( (domid != current->id) &&
+ if ( (domid != current->domain->id) &&
!do_extended_command(0, MMUEXT_SET_FOREIGNDOM | (domid << 16)) )
{
rc = -EINVAL;
@@ -1393,7 +1404,7 @@ int do_mmu_update(
* MMU_NORMAL_PT_UPDATE: Normal update to any level of page table.
*/
case MMU_NORMAL_PT_UPDATE:
- if ( unlikely(!get_page_from_pagenr(pfn, current)) )
+ if ( unlikely(!get_page_from_pagenr(pfn, current->domain)) )
{
MEM_LOG("Could not get page for normal update");
break;
@@ -1421,13 +1432,13 @@ int do_mmu_update(
okay = mod_l1_entry((l1_pgentry_t *)va,
mk_l1_pgentry(req.val));
- if ( unlikely(d->mm.shadow_mode) && okay &&
- (get_shadow_status(&d->mm, page-frame_table) &
+ if ( unlikely(d->arch.shadow_mode) && okay &&
+ (get_shadow_status(d, page-frame_table) &
PSH_shadowed) )
{
shadow_l1_normal_pt_update(
req.ptr, req.val, &prev_spfn, &prev_spl1e);
- put_shadow_status(&d->mm);
+ put_shadow_status(d);
}
put_page_type(page);
@@ -1440,12 +1451,12 @@ int do_mmu_update(
mk_l2_pgentry(req.val),
pfn);
- if ( unlikely(d->mm.shadow_mode) && okay &&
- (get_shadow_status(&d->mm, page-frame_table) &
+ if ( unlikely(d->arch.shadow_mode) && okay &&
+ (get_shadow_status(d, page-frame_table) &
PSH_shadowed) )
{
shadow_l2_normal_pt_update(req.ptr, req.val);
- put_shadow_status(&d->mm);
+ put_shadow_status(d);
}
put_page_type(page);
@@ -1478,9 +1489,9 @@ int do_mmu_update(
* If in log-dirty mode, mark the corresponding pseudo-physical
* page as dirty.
*/
- if ( unlikely(d->mm.shadow_mode == SHM_logdirty) &&
- mark_dirty(&d->mm, pfn) )
- d->mm.shadow_dirty_block_count++;
+ if ( unlikely(d->arch.shadow_mode == SHM_logdirty) &&
+ mark_dirty(d, pfn) )
+ d->arch.shadow_dirty_block_count++;
put_page(&frame_table[pfn]);
break;
@@ -1534,6 +1545,7 @@ int do_mmu_update(
if ( unlikely(pdone != NULL) )
__put_user(done + i, pdone);
+ UNLOCK_BIGLOCK(d);
return rc;
}
@@ -1542,9 +1554,10 @@ int do_update_va_mapping(unsigned long page_nr,
unsigned long val,
unsigned long flags)
{
- struct domain *d = current;
+ struct exec_domain *ed = current;
+ struct domain *d = ed->domain;
int err = 0;
- unsigned int cpu = d->processor;
+ unsigned int cpu = ed->processor;
unsigned long deferred_ops;
perfc_incrc(calls_to_update_va);
@@ -1552,6 +1565,8 @@ int do_update_va_mapping(unsigned long page_nr,
if ( unlikely(page_nr >= (HYPERVISOR_VIRT_START >> PAGE_SHIFT)) )
return -EINVAL;
+ LOCK_BIGLOCK(d);
+
cleanup_writable_pagetable(d);
/*
@@ -1563,11 +1578,11 @@ int do_update_va_mapping(unsigned long page_nr,
mk_l1_pgentry(val))) )
err = -EINVAL;
- if ( unlikely(d->mm.shadow_mode) )
+ if ( unlikely(d->arch.shadow_mode) )
{
unsigned long sval;
- l1pte_propagate_from_guest(&d->mm, &val, &sval);
+ l1pte_propagate_from_guest(d, &val, &sval);
if ( unlikely(__put_user(sval, ((unsigned long *)(
&shadow_linear_pg_table[page_nr])))) )
@@ -1584,10 +1599,10 @@ int do_update_va_mapping(unsigned long page_nr,
* the PTE in the PT-holding page. We need the machine frame number
* for this.
*/
- if ( d->mm.shadow_mode == SHM_logdirty )
- mark_dirty(&current->mm, va_to_l1mfn(page_nr << PAGE_SHIFT));
+ if ( d->arch.shadow_mode == SHM_logdirty )
+ mark_dirty(d, va_to_l1mfn(page_nr << PAGE_SHIFT));
- check_pagetable(&d->mm, d->mm.pagetable, "va"); /* debug */
+ check_pagetable(d, ed->arch.pagetable, "va"); /* debug */
}
deferred_ops = percpu_info[cpu].deferred_ops;
@@ -1602,6 +1617,8 @@ int do_update_va_mapping(unsigned long page_nr,
if ( unlikely(deferred_ops & DOP_RELOAD_LDT) )
(void)map_ldt_shadow_page(0);
+ UNLOCK_BIGLOCK(d);
+
return err;
}
@@ -1614,7 +1631,7 @@ int do_update_va_mapping_otherdomain(unsigned long page_nr,
struct domain *d;
int rc;
- if ( unlikely(!IS_PRIV(current)) )
+ if ( unlikely(!IS_PRIV(current->domain)) )
return -EPERM;
percpu_info[cpu].foreign = d = find_domain_by_id(domid);
@@ -1656,7 +1673,8 @@ void ptwr_flush(const int which)
l1_pgentry_t *sl1e = NULL, *pl1e, ol1e, nl1e;
l2_pgentry_t *pl2e;
int i, cpu = smp_processor_id();
- struct domain *d = current;
+ struct exec_domain *ed = current;
+ struct domain *d = ed->domain;
l1va = ptwr_info[cpu].ptinfo[which].l1va;
ptep = (unsigned long *)&linear_pg_table[l1va>>PAGE_SHIFT];
@@ -1678,15 +1696,15 @@ void ptwr_flush(const int which)
PTWR_PRINT_WHICH, ptep, pte);
pte &= ~_PAGE_RW;
- if ( unlikely(d->mm.shadow_mode) )
+ if ( unlikely(d->arch.shadow_mode) )
{
/* Write-protect the p.t. page in the shadow page table. */
- l1pte_propagate_from_guest(&d->mm, &pte, &spte);
+ l1pte_propagate_from_guest(d, &pte, &spte);
__put_user(
spte, (unsigned long *)&shadow_linear_pg_table[l1va>>PAGE_SHIFT]);
/* Is the p.t. page itself shadowed? Map it into Xen space if so. */
- sstat = get_shadow_status(&d->mm, pte >> PAGE_SHIFT);
+ sstat = get_shadow_status(d, pte >> PAGE_SHIFT);
if ( sstat & PSH_shadowed )
sl1e = map_domain_mem((sstat & PSH_pfn_mask) << PAGE_SHIFT);
}
@@ -1704,7 +1722,11 @@ void ptwr_flush(const int which)
/* Ensure that there are no stale writable mappings in any TLB. */
/* NB. INVLPG is a serialising instruction: flushes pending updates. */
+#if 1
__flush_tlb_one(l1va); /* XXX Multi-CPU guests? */
+#else
+ flush_tlb_all();
+#endif
PTWR_PRINTK("[%c] disconnected_l1va at %p now %08lx\n",
PTWR_PRINT_WHICH, ptep, pte);
@@ -1731,7 +1753,7 @@ void ptwr_flush(const int which)
{
if ( unlikely(sl1e != NULL) )
l1pte_propagate_from_guest(
- &d->mm, &l1_pgentry_val(nl1e),
+ d, &l1_pgentry_val(nl1e),
&l1_pgentry_val(sl1e[i]));
put_page_type(&frame_table[l1_pgentry_to_pagenr(nl1e)]);
}
@@ -1749,12 +1771,13 @@ void ptwr_flush(const int which)
(ENTRIES_PER_L1_PAGETABLE - i) * sizeof(l1_pgentry_t));
unmap_domain_mem(pl1e);
ptwr_info[cpu].ptinfo[which].l1va = 0;
+ UNLOCK_BIGLOCK(d);
domain_crash();
}
if ( unlikely(sl1e != NULL) )
l1pte_propagate_from_guest(
- &d->mm, &l1_pgentry_val(nl1e), &l1_pgentry_val(sl1e[i]));
+ d, &l1_pgentry_val(nl1e), &l1_pgentry_val(sl1e[i]));
if ( unlikely(l1_pgentry_val(ol1e) & _PAGE_PRESENT) )
put_page_from_l1e(ol1e, d);
@@ -1765,7 +1788,7 @@ void ptwr_flush(const int which)
* STEP 3. Reattach the L1 p.t. page into the current address space.
*/
- if ( (which == PTWR_PT_ACTIVE) && likely(!d->mm.shadow_mode) )
+ if ( (which == PTWR_PT_ACTIVE) && likely(!d->arch.shadow_mode) )
{
pl2e = &linear_l2_table[ptwr_info[cpu].ptinfo[which].l2_idx];
*pl2e = mk_l2_pgentry(l2_pgentry_val(*pl2e) | _PAGE_PRESENT);
@@ -1780,7 +1803,7 @@ void ptwr_flush(const int which)
if ( unlikely(sl1e != NULL) )
{
unmap_domain_mem(sl1e);
- put_shadow_status(&d->mm);
+ put_shadow_status(d);
}
}
@@ -1800,7 +1823,9 @@ int ptwr_do_page_fault(unsigned long addr)
if ( !(l2_pgentry_val(linear_l2_table[addr>>L2_PAGETABLE_SHIFT]) &
_PAGE_PRESENT) ||
__get_user(pte, (unsigned long *)&linear_pg_table[addr>>PAGE_SHIFT]) )
+ {
return 0;
+ }
pfn = pte >> PAGE_SHIFT;
page = &frame_table[pfn];
@@ -1808,12 +1833,16 @@ int ptwr_do_page_fault(unsigned long addr)
/* We are looking only for read-only mappings of p.t. pages. */
if ( ((pte & (_PAGE_RW | _PAGE_PRESENT)) != _PAGE_PRESENT) ||
((page->u.inuse.type_info & PGT_type_mask) != PGT_l1_page_table) )
+ {
return 0;
+ }
/* Get the L2 index at which this L1 p.t. is always mapped. */
l2_idx = page->u.inuse.type_info & PGT_va_mask;
if ( unlikely(l2_idx >= PGT_va_unknown) )
+ {
domain_crash(); /* Urk! This L1 is mapped in multiple L2 slots! */
+ }
l2_idx >>= PGT_va_shift;
if ( l2_idx == (addr >> L2_PAGETABLE_SHIFT) )
@@ -1862,10 +1891,15 @@ int ptwr_do_page_fault(unsigned long addr)
ptwr_info[cpu].ptinfo[which].l2_idx = l2_idx;
/* For safety, disconnect the L1 p.t. page from current space. */
- if ( (which == PTWR_PT_ACTIVE) && likely(!current->mm.shadow_mode) )
+ if ( (which == PTWR_PT_ACTIVE) &&
+ likely(!current->domain->arch.shadow_mode) )
{
*pl2e = mk_l2_pgentry(l2e & ~_PAGE_PRESENT);
+#if 1
flush_tlb(); /* XXX Multi-CPU guests? */
+#else
+ flush_tlb_all();
+#endif
}
/* Temporarily map the L1 page, and make a copy of it. */
@@ -2044,12 +2078,12 @@ void audit_domain(struct domain *d)
struct list_head *list_ent;
struct pfn_info *page;
- if ( d != current )
+ if ( d != current->domain )
domain_pause(d);
synchronise_pagetables(~0UL);
printk("pt base=%lx sh_info=%x\n",
- pagetable_val(d->mm.pagetable)>>PAGE_SHIFT,
+ pagetable_val(d->exec_domain[0]->arch.pagetable)>>PAGE_SHIFT,
virt_to_page(d->shared_info)-frame_table);
spin_lock(&d->page_alloc_lock);
@@ -2062,7 +2096,7 @@ void audit_domain(struct domain *d)
pfn = list_entry(list_ent, struct pfn_info, list) - frame_table;
page = &frame_table[pfn];
- if ( page->u.inuse.domain != d )
+ if ( page_get_owner(page) != d )
BUG();
if ( (page->u.inuse.type_info & PGT_count_mask) >
@@ -2099,7 +2133,7 @@ void audit_domain(struct domain *d)
/* PHASE 1 */
- adjust(&frame_table[pagetable_val(d->mm.pagetable)>>PAGE_SHIFT], -1, 1);
+ adjust(&frame_table[pagetable_val(d->exec_domain[0]->arch.pagetable)>>PAGE_SHIFT], -1, 1);
list_ent = d->page_list.next;
for ( i = 0; (list_ent != &d->page_list); i++ )
@@ -2108,7 +2142,7 @@ void audit_domain(struct domain *d)
pfn = list_entry(list_ent, struct pfn_info, list) - frame_table;
page = &frame_table[pfn];
- if ( page->u.inuse.domain != d )
+ if ( page_get_owner(page) != d )
BUG();
switch ( page->u.inuse.type_info & PGT_type_mask )
@@ -2134,10 +2168,10 @@ void audit_domain(struct domain *d)
unsigned long l1pfn = pt[i]>>PAGE_SHIFT;
struct pfn_info *l1page = &frame_table[l1pfn];
- if ( l1page->u.inuse.domain != d )
+ if ( page_get_owner(l1page) != d )
{
printk("L2: Skip bizarre page belonging to other "
- "dom %p\n", l1page->u.inuse.domain);
+ "dom %p\n", page_get_owner(l1page));
continue;
}
@@ -2212,12 +2246,12 @@ void audit_domain(struct domain *d)
}
- if ( l1page->u.inuse.domain != d )
+ if ( page_get_owner(l1page) != d )
{
- printk("Audit %d: [%lx,%x] Skip foreign page dom=%lx "
+ printk("Audit %d: [%lx,%x] Skip foreign page dom=%p "
"pfn=%lx c=%08x t=%08x m2p=%lx\n",
d->id, pfn, i,
- (unsigned long)l1page->u.inuse.domain,
+ page_get_owner(l1page),
l1pfn,
l1page->count_info,
l1page->u.inuse.type_info,
@@ -2302,7 +2336,7 @@ void audit_domain(struct domain *d)
unsigned long l1pfn = pt[i]>>PAGE_SHIFT;
struct pfn_info *l1page = &frame_table[l1pfn];
- if ( l1page->u.inuse.domain == d)
+ if ( page_get_owner(l1page) == d )
adjust(l1page, 1, 1);
}
}
@@ -2323,7 +2357,7 @@ void audit_domain(struct domain *d)
unsigned long l1pfn = pt[i]>>PAGE_SHIFT;
struct pfn_info *l1page = &frame_table[l1pfn];
- if ( (l1page->u.inuse.domain != d) ||
+ if ( (page_get_owner(l1page) != d) ||
(l1pfn < 0x100) || (l1pfn > max_page) )
continue;
@@ -2343,11 +2377,12 @@ void audit_domain(struct domain *d)
spin_unlock(&d->page_alloc_lock);
- adjust(&frame_table[pagetable_val(d->mm.pagetable)>>PAGE_SHIFT], 1, 1);
+ adjust(&frame_table[pagetable_val(
+ d->exec_domain[0]->arch.pagetable)>>PAGE_SHIFT], 1, 1);
printk("Audit %d: Done. ctot=%d ttot=%d\n", d->id, ctot, ttot );
- if ( d != current )
+ if ( d != current->domain )
domain_unpause(d);
}
diff --git a/xen/arch/x86/microcode.c b/xen/arch/x86/microcode.c
index 2b5a18da50..d811e7ed70 100644
--- a/xen/arch/x86/microcode.c
+++ b/xen/arch/x86/microcode.c
@@ -84,7 +84,7 @@
#define DECLARE_MUTEX(_m) spinlock_t _m = SPIN_LOCK_UNLOCKED
#define down(_m) spin_lock(_m)
#define up(_m) spin_unlock(_m)
-#define vmalloc(_s) xmalloc(_s)
+#define vmalloc(_s) xmalloc_bytes(_s)
#define vfree(_p) xfree(_p)
#define num_online_cpus() smp_num_cpus
static inline int on_each_cpu(
diff --git a/xen/arch/x86/mpparse.c b/xen/arch/x86/mpparse.c
index 7db6f8a6da..97c85aad53 100644
--- a/xen/arch/x86/mpparse.c
+++ b/xen/arch/x86/mpparse.c
@@ -859,7 +859,7 @@ void __init get_smp_config (void)
static int __init smp_scan_config (unsigned long base, unsigned long length)
{
- unsigned long *bp = phys_to_virt(base);
+ unsigned int *bp = phys_to_virt(base);
struct intel_mp_floating *mpf;
Dprintk("Scan SMP from %p for %ld bytes.\n", bp,length);
diff --git a/xen/arch/x86/mtrr/generic.c b/xen/arch/x86/mtrr/generic.c
index 8da0c5b43c..6f8d104443 100644
--- a/xen/arch/x86/mtrr/generic.c
+++ b/xen/arch/x86/mtrr/generic.c
@@ -52,7 +52,8 @@ void __init get_mtrr_state(void)
unsigned lo, dummy;
if (!mtrr_state.var_ranges) {
- mtrr_state.var_ranges = xmalloc(num_var_ranges * sizeof (struct mtrr_var_range));
+ mtrr_state.var_ranges = xmalloc_array(struct mtrr_var_range,
+ num_var_ranges);
if (!mtrr_state.var_ranges)
return;
}
@@ -250,7 +251,7 @@ static void prepare_set(void)
/* Save value of CR4 and clear Page Global Enable (bit 7) */
if ( cpu_has_pge ) {
cr4 = read_cr4();
- write_cr4(cr4 & (unsigned char) ~(1 << 7));
+ write_cr4(cr4 & ~X86_CR4_PGE);
}
/* Flush all TLBs via a mov %cr3, %reg; mov %reg, %cr3 */
diff --git a/xen/arch/x86/mtrr/main.c b/xen/arch/x86/mtrr/main.c
index bd1ae5d054..257240b1d1 100644
--- a/xen/arch/x86/mtrr/main.c
+++ b/xen/arch/x86/mtrr/main.c
@@ -136,8 +136,7 @@ static void __init init_table(void)
int i, max;
max = num_var_ranges;
- if ((usage_table = xmalloc(max * sizeof *usage_table))
- == NULL) {
+ if ((usage_table = xmalloc_array(unsigned int, max)) == NULL) {
printk(KERN_ERR "mtrr: could not allocate\n");
return;
}
diff --git a/xen/arch/x86/nmi.c b/xen/arch/x86/nmi.c
index 556a661b57..0fa5968be4 100644
--- a/xen/arch/x86/nmi.c
+++ b/xen/arch/x86/nmi.c
@@ -48,9 +48,6 @@ extern int logical_proc_id[];
#define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79
#define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED
-#define MSR_P4_MISC_ENABLE 0x1A0
-#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7)
-#define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL (1<<12)
#define MSR_P4_PERFCTR0 0x300
#define MSR_P4_CCCR0 0x360
#define P4_ESCR_EVENT_SELECT(N) ((N)<<25)
@@ -186,15 +183,15 @@ static int __pminit setup_p4_watchdog(void)
{
unsigned int misc_enable, dummy;
- rdmsr(MSR_P4_MISC_ENABLE, misc_enable, dummy);
- if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
+ rdmsr(MSR_IA32_MISC_ENABLE, misc_enable, dummy);
+ if (!(misc_enable & MSR_IA32_MISC_ENABLE_PERF_AVAIL))
return 0;
nmi_perfctr_msr = MSR_P4_IQ_COUNTER0;
if ( logical_proc_id[smp_processor_id()] == 0 )
{
- if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL))
+ if (!(misc_enable & MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL))
clear_msr_range(0x3F1, 2);
/* MSR 0x3F0 seems to have a default value of 0xFC00, but current
docs doesn't fully define it, so leave it alone for now. */
diff --git a/xen/arch/x86/pci-pc.c b/xen/arch/x86/pci-pc.c
index c3c097efdc..264d4d5054 100644
--- a/xen/arch/x86/pci-pc.c
+++ b/xen/arch/x86/pci-pc.c
@@ -1038,7 +1038,7 @@ struct irq_routing_table * __devinit pcibios_get_irq_routing_table(void)
if (ret & 0xff00)
printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff);
else if (opt.size) {
- rt = xmalloc(sizeof(struct irq_routing_table) + opt.size);
+ rt = xmalloc_bytes(sizeof(struct irq_routing_table) + opt.size);
if (rt) {
memset(rt, 0, sizeof(struct irq_routing_table));
rt->size = opt.size + sizeof(struct irq_routing_table);
diff --git a/xen/arch/x86/pdb-linux.c b/xen/arch/x86/pdb-linux.c
deleted file mode 100644
index cb4f0e0e78..0000000000
--- a/xen/arch/x86/pdb-linux.c
+++ /dev/null
@@ -1,100 +0,0 @@
-
-/*
- * pervasive debugger
- * www.cl.cam.ac.uk/netos/pdb
- *
- * alex ho
- * 2004
- * university of cambridge computer laboratory
- *
- * linux & i386 dependent code. bleech.
- */
-
-#include <asm/pdb.h>
-
-/* offset to the first instruction in the linux system call code
- where we can safely set a breakpoint */
-unsigned int pdb_linux_syscall_enter_bkpt_offset = 20;
-
-/* offset to eflags saved on the stack after an int 80 */
-unsigned int pdb_linux_syscall_eflags_offset = 48;
-
-/* offset to the instruction pointer saved on the stack after an int 80 */
-unsigned int pdb_linux_syscall_eip_offset = 40;
-
-unsigned char
-pdb_linux_set_bkpt (unsigned long addr)
-{
- unsigned char old_instruction = *(unsigned char *)addr;
- *(unsigned char *)addr = 0xcc;
- return old_instruction;
-}
-
-void
-pdb_linux_clr_bkpt (unsigned long addr, unsigned char value)
-{
- *(unsigned char *)addr = value;
-}
-
-void
-pdb_linux_syscall_enter_bkpt (struct xen_regs *regs, long error_code,
- trap_info_t *ti)
-{
- /* set at breakpoint at the beginning of the
- system call in the target domain */
-
- pdb_system_call_enter_instr = pdb_linux_set_bkpt(ti->address +
- pdb_linux_syscall_enter_bkpt_offset);
- pdb_system_call = 1;
-}
-
-void
-pdb_linux_syscall_exit_bkpt (struct xen_regs *regs, struct pdb_context *pdb_ctx)
-{
- /*
- we've hit an int 0x80 in a user's program, jumped into xen
- (traps.c::do_general_protection()) which re-wrote the next
- instruction in the os kernel to 0xcc, and then hit that
- exception.
-
- we need to re-write the return instruction in the user's
- program so that we know when we have finished the system call
- and are back in the user's program.
-
- at this point our stack should look something like this:
-
- esp = 0x80a59f0
- esp + 4 = 0x0
- esp + 8 = 0x80485a0
- esp + 12 = 0x2d
- esp + 16 = 0x80485f4
- esp + 20 = 0xbffffa48
- esp + 24 = 0xd
- esp + 28 = 0xc00a0833
- esp + 32 = 0x833
- esp + 36 = 0xd
- esp + 40 = 0x804dcdd saved eip
- esp + 44 = 0x82b saved cs
- esp + 48 = 0x213392 saved eflags
- esp + 52 = 0xbffffa2c saved esp
- esp + 56 = 0x833 saved ss
- esp + 60 = 0x1000000
- */
-
- /* restore the entry instruction for the system call */
- pdb_linux_clr_bkpt(regs->eip - 1, pdb_system_call_enter_instr);
-
- /* save the address of eflags that was saved on the stack */
- pdb_system_call_eflags_addr = (regs->esp +
- pdb_linux_syscall_eflags_offset);
-
- /* muck with the return instruction so that we trap back into the
- debugger when re-entering user space */
- pdb_system_call_next_addr = *(unsigned long *)(regs->esp +
- pdb_linux_syscall_eip_offset);
- pdb_linux_get_values (&pdb_system_call_leave_instr, 1,
- pdb_system_call_next_addr,
- pdb_ctx->process, pdb_ctx->ptbr);
- pdb_linux_set_values ("cc", 1, pdb_system_call_next_addr,
- pdb_ctx->process, pdb_ctx->ptbr);
-}
diff --git a/xen/arch/x86/pdb-stub.c b/xen/arch/x86/pdb-stub.c
deleted file mode 100644
index 568bcea113..0000000000
--- a/xen/arch/x86/pdb-stub.c
+++ /dev/null
@@ -1,1280 +0,0 @@
-
-/*
- * pervasive debugger
- * www.cl.cam.ac.uk/netos/pdb
- *
- * alex ho
- * 2004
- * university of cambridge computer laboratory
- *
- * code adapted originally from kgdb, nemesis, & gdbserver
- */
-
-#include <xen/lib.h>
-#include <xen/sched.h>
-#include <asm/regs.h>
-#include <xen/keyhandler.h>
-#include <asm/apic.h>
-#include <asm/domain_page.h> /* [un]map_domain_mem */
-#include <asm/processor.h>
-#include <asm/pdb.h>
-#include <xen/list.h>
-#include <xen/serial.h>
-#include <xen/softirq.h>
-#include <xen/init.h>
-
-/* opt_pdb: Name of serial port for Xen pervasive debugger (and enable pdb) */
-static unsigned char opt_pdb[10] = "none";
-string_param("pdb", opt_pdb);
-
-#define PDB_DEBUG_TRACE
-#ifdef PDB_DEBUG_TRACE
-#define TRC(_x) _x
-#else
-#define TRC(_x)
-#endif
-
-#define DEBUG_EXCEPTION 0x01
-#define BREAKPT_EXCEPTION 0x03
-#define PDB_LIVE_EXCEPTION 0x58
-#define KEYPRESS_EXCEPTION 0x88
-
-#define BUFMAX 400
-
-static const char hexchars[] = "0123456789abcdef";
-
-static int remote_debug;
-
-#define PDB_BUFMAX 1024
-static char pdb_in_buffer[PDB_BUFMAX];
-static char pdb_out_buffer[PDB_BUFMAX];
-static char pdb_buffer[PDB_BUFMAX];
-
-struct pdb_context pdb_ctx;
-int pdb_continue_thread = 0;
-int pdb_general_thread = 0;
-
-void pdb_put_packet (unsigned char *buffer, int ack);
-void pdb_bkpt_check (u_char *buffer, int length,
- unsigned long cr3, unsigned long addr);
-
-int pdb_initialized = 0;
-int pdb_page_fault_possible = 0;
-int pdb_page_fault_scratch = 0; /* just a handy variable */
-int pdb_page_fault = 0;
-static int pdb_serhnd = -1;
-static int pdb_stepping = 0;
-
-int pdb_system_call = 0;
-unsigned char pdb_system_call_enter_instr = 0; /* original enter instr */
-unsigned char pdb_system_call_leave_instr = 0; /* original next instr */
-unsigned long pdb_system_call_next_addr = 0; /* instr after int 0x80 */
-unsigned long pdb_system_call_eflags_addr = 0; /* saved eflags on stack */
-
-static inline void pdb_put_char(unsigned char c)
-{
- serial_putc(pdb_serhnd, c);
-}
-
-static inline unsigned char pdb_get_char(void)
-{
- return serial_getc(pdb_serhnd);
-}
-
-int
-get_char (char *addr)
-{
- return *addr;
-}
-
-void
-set_char (char *addr, int val)
-{
- *addr = val;
-}
-
-void
-pdb_process_query (char *ptr)
-{
- if (strcmp(ptr, "C") == 0)
- {
- /* empty string */
- }
- else if (strcmp(ptr, "fThreadInfo") == 0)
- {
-#ifdef PDB_PAST
- struct domain *p;
-#endif /* PDB_PAST */
-
- int buf_idx = 0;
-
- pdb_out_buffer[buf_idx++] = 'l';
- pdb_out_buffer[buf_idx++] = 0;
-
-#ifdef PDB_PAST
- switch (pdb_level)
- {
- case PDB_LVL_XEN: /* return a list of domains */
- {
- int count = 0;
-
- read_lock(&domlist_lock);
-
- pdb_out_buffer[buf_idx++] = 'm';
- for_each_domain ( p )
- {
- domid_t domain = p->domain + PDB_ID_OFFSET;
-
- if (count > 0)
- {
- pdb_out_buffer[buf_idx++] = ',';
- }
- if (domain > 15)
- {
- pdb_out_buffer[buf_idx++] = hexchars[domain >> 4];
- }
- pdb_out_buffer[buf_idx++] = hexchars[domain % 16];
- count++;
- }
- pdb_out_buffer[buf_idx++] = 0;
-
- read_unlock(&domlist_lock);
- break;
- }
- case PDB_LVL_GUESTOS: /* return a list of processes */
- {
- int foobar[20];
- int loop, total;
-
- /* this cr3 is wrong! */
- total = pdb_linux_process_list(pdb_ctx[pdb_level].info_cr3,
- foobar, 20);
-
- pdb_out_buffer[buf_idx++] = 'm';
- pdb_out_buffer[buf_idx++] = '1'; /* 1 is to go back */
- for (loop = 0; loop < total; loop++)
- {
- int pid = foobar[loop] + PDB_ID_OFFSET;
-
- pdb_out_buffer[buf_idx++] = ',';
- if (pid > 15)
- {
- pdb_out_buffer[buf_idx++] = hexchars[pid >> 4];
- }
- pdb_out_buffer[buf_idx++] = hexchars[pid % 16];
- }
- pdb_out_buffer[buf_idx++] = 0;
- break;
- }
- case PDB_LVL_PROCESS: /* hmmm... */
- {
- pdb_out_buffer[buf_idx++] = 'm';
- pdb_out_buffer[buf_idx++] = '1'; /* 1 is to go back */
- break;
- }
- default:
- break;
- }
-#endif /* PDB_PAST */
-
- }
- else if (strcmp(ptr, "sThreadInfo") == 0)
- {
- int buf_idx = 0;
-
- pdb_out_buffer[buf_idx++] = 'l';
- pdb_out_buffer[buf_idx++] = 0;
- }
- else if (strncmp(ptr, "ThreadExtraInfo,", 16) == 0)
- {
- int thread = 0;
- char *message = "foobar ?";
-
- ptr += 16;
- if (hexToInt (&ptr, &thread))
- {
- mem2hex (message, pdb_out_buffer, strlen(message) + 1);
- }
-
-#ifdef PDB_PAST
- int thread = 0;
- char message[16];
- struct domain *p;
-
- strncpy (message, dom0->name, 16);
-
- ptr += 16;
- if (hexToInt (&ptr, &thread))
- {
- mem2hex ((char *)message, pdb_out_buffer, strlen(message) + 1);
- }
-#endif /* PDB_PAST */
-
-#ifdef PDB_FUTURE
- {
- char string[task_struct_comm_length];
-
- string[0] = 0;
- pdb_linux_process_details (cr3, pid, string);
- printk (" (%s)", string);
- }
-#endif /* PDB_FUTURE*/
-
- }
- else if (strcmp(ptr, "Offsets") == 0)
- {
- /* empty string */
- }
- else if (strncmp(ptr, "Symbol", 6) == 0)
- {
- strcpy (pdb_out_buffer, "OK");
- }
- else
- {
- printk("pdb: error, unknown query [%s]\n", ptr);
- }
-}
-
-void
-pdb_x86_to_gdb_regs (char *buffer, struct xen_regs *regs)
-{
- int idx = 0;
-
- mem2hex ((char *)&regs->eax, &buffer[idx], sizeof(regs->eax));
- idx += sizeof(regs->eax) * 2;
- mem2hex ((char *)&regs->ecx, &buffer[idx], sizeof(regs->ecx));
- idx += sizeof(regs->ecx) * 2;
- mem2hex ((char *)&regs->edx, &buffer[idx], sizeof(regs->edx));
- idx += sizeof(regs->edx) * 2;
- mem2hex ((char *)&regs->ebx, &buffer[idx], sizeof(regs->ebx));
- idx += sizeof(regs->ebx) * 2;
- mem2hex ((char *)&regs->esp, &buffer[idx], sizeof(regs->esp));
- idx += sizeof(regs->esp) * 2;
- mem2hex ((char *)&regs->ebp, &buffer[idx], sizeof(regs->ebp));
- idx += sizeof(regs->ebp) * 2;
- mem2hex ((char *)&regs->esi, &buffer[idx], sizeof(regs->esi));
- idx += sizeof(regs->esi) * 2;
- mem2hex ((char *)&regs->edi, &buffer[idx], sizeof(regs->edi));
- idx += sizeof(regs->edi) * 2;
- mem2hex ((char *)&regs->eip, &buffer[idx], sizeof(regs->eip));
- idx += sizeof(regs->eip) * 2;
- mem2hex ((char *)&regs->eflags, &buffer[idx], sizeof(regs->eflags));
- idx += sizeof(regs->eflags) * 2;
- mem2hex ((char *)&regs->cs, &buffer[idx], sizeof(regs->cs));
- idx += sizeof(regs->cs) * 2;
- mem2hex ((char *)&regs->ss, &buffer[idx], sizeof(regs->ss));
- idx += sizeof(regs->ss) * 2;
- mem2hex ((char *)&regs->ds, &buffer[idx], sizeof(regs->ds));
- idx += sizeof(regs->ds) * 2;
- mem2hex ((char *)&regs->es, &buffer[idx], sizeof(regs->es));
- idx += sizeof(regs->es) * 2;
- mem2hex ((char *)&regs->fs, &buffer[idx], sizeof(regs->fs));
- idx += sizeof(regs->fs) * 2;
- mem2hex ((char *)&regs->gs, &buffer[idx], sizeof(regs->gs));
-}
-
-/* at this point we allow any register to be changed, caveat emptor */
-void
-pdb_gdb_to_x86_regs (struct xen_regs *regs, char *buffer)
-{
- hex2mem(buffer, (char *)&regs->eax, sizeof(regs->eax));
- buffer += sizeof(regs->eax) * 2;
- hex2mem(buffer, (char *)&regs->ecx, sizeof(regs->ecx));
- buffer += sizeof(regs->ecx) * 2;
- hex2mem(buffer, (char *)&regs->edx, sizeof(regs->edx));
- buffer += sizeof(regs->edx) * 2;
- hex2mem(buffer, (char *)&regs->ebx, sizeof(regs->ebx));
- buffer += sizeof(regs->ebx) * 2;
- hex2mem(buffer, (char *)&regs->esp, sizeof(regs->esp));
- buffer += sizeof(regs->esp) * 2;
- hex2mem(buffer, (char *)&regs->ebp, sizeof(regs->ebp));
- buffer += sizeof(regs->ebp) * 2;
- hex2mem(buffer, (char *)&regs->esi, sizeof(regs->esi));
- buffer += sizeof(regs->esi) * 2;
- hex2mem(buffer, (char *)&regs->edi, sizeof(regs->edi));
- buffer += sizeof(regs->edi) * 2;
- hex2mem(buffer, (char *)&regs->eip, sizeof(regs->eip));
- buffer += sizeof(regs->eip) * 2;
- hex2mem(buffer, (char *)&regs->eflags, sizeof(regs->eflags));
- buffer += sizeof(regs->eflags) * 2;
- hex2mem(buffer, (char *)&regs->cs, sizeof(regs->cs));
- buffer += sizeof(regs->cs) * 2;
- hex2mem(buffer, (char *)&regs->ss, sizeof(regs->ss));
- buffer += sizeof(regs->ss) * 2;
- hex2mem(buffer, (char *)&regs->ds, sizeof(regs->ds));
- buffer += sizeof(regs->ds) * 2;
- hex2mem(buffer, (char *)&regs->es, sizeof(regs->es));
- buffer += sizeof(regs->es) * 2;
- hex2mem(buffer, (char *)&regs->fs, sizeof(regs->fs));
- buffer += sizeof(regs->fs) * 2;
- hex2mem(buffer, (char *)&regs->gs, sizeof(regs->gs));
-}
-
-int
-pdb_process_command (char *ptr, struct xen_regs *regs, unsigned long cr3,
- int sigval)
-{
- int length;
- unsigned long addr;
- int ack = 1; /* wait for ack in pdb_put_packet */
- int go = 0;
-
- TRC(printf("pdb: [%s]\n", ptr));
-
- pdb_out_buffer[0] = 0;
-
- if (pdb_ctx.valid == 1)
- {
- if (pdb_ctx.domain == -1) /* pdb context: xen */
- {
- struct domain *p;
-
- p = &idle0_task;
- if (p->mm.shadow_mode)
- pdb_ctx.ptbr = pagetable_val(p->mm.shadow_table);
- else
- pdb_ctx.ptbr = pagetable_val(p->mm.pagetable);
- }
- else if (pdb_ctx.process == -1) /* pdb context: guest os */
- {
- struct domain *p;
-
- if (pdb_ctx.domain == -2)
- {
- p = find_last_domain();
- }
- else
- {
- p = find_domain_by_id(pdb_ctx.domain);
- }
- if (p == NULL)
- {
- printk ("pdb error: unknown domain [0x%x]\n", pdb_ctx.domain);
- strcpy (pdb_out_buffer, "E01");
- pdb_ctx.domain = -1;
- goto exit;
- }
- if (p->mm.shadow_mode)
- pdb_ctx.ptbr = pagetable_val(p->mm.shadow_table);
- else
- pdb_ctx.ptbr = pagetable_val(p->mm.pagetable);
- put_domain(p);
- }
- else /* pdb context: process */
- {
- struct domain *p;
- unsigned long domain_ptbr;
-
- p = find_domain_by_id(pdb_ctx.domain);
- if (p == NULL)
- {
- printk ("pdb error: unknown domain [0x%x][0x%x]\n",
- pdb_ctx.domain, pdb_ctx.process);
- strcpy (pdb_out_buffer, "E01");
- pdb_ctx.domain = -1;
- goto exit;
- }
- if (p->mm.shadow_mode)
- domain_ptbr = pagetable_val(p->mm.shadow_table);
- else
- domain_ptbr = pagetable_val(p->mm.pagetable);
- put_domain(p);
-
- pdb_ctx.ptbr = domain_ptbr;
- /*pdb_ctx.ptbr=pdb_linux_pid_ptbr(domain_ptbr, pdb_ctx.process);*/
- }
-
- pdb_ctx.valid = 0;
- TRC(printk ("pdb change context (dom:%d, proc:%d) now 0x%lx\n",
- pdb_ctx.domain, pdb_ctx.process, pdb_ctx.ptbr));
- }
-
- switch (*ptr++)
- {
- case '?':
- pdb_out_buffer[0] = 'S';
- pdb_out_buffer[1] = hexchars[sigval >> 4];
- pdb_out_buffer[2] = hexchars[sigval % 16];
- pdb_out_buffer[3] = 0;
- break;
- case 'S': /* step with signal */
- case 's': /* step */
- {
- if ( pdb_system_call_eflags_addr != 0 )
- {
- unsigned long eflags;
- char eflags_buf[sizeof(eflags)*2]; /* STUPID STUPID STUPID */
-
- pdb_linux_get_values((u_char*)&eflags, sizeof(eflags),
- pdb_system_call_eflags_addr,
- pdb_ctx.process, pdb_ctx.ptbr);
- eflags |= X86_EFLAGS_TF;
- mem2hex ((u_char *)&eflags, eflags_buf, sizeof(eflags));
- pdb_linux_set_values(eflags_buf, sizeof(eflags),
- pdb_system_call_eflags_addr,
- pdb_ctx.process, pdb_ctx.ptbr);
- }
-
- regs->eflags |= X86_EFLAGS_TF;
- pdb_stepping = 1;
- return 1;
- /* not reached */
- }
- case 'C': /* continue with signal */
- case 'c': /* continue */
- {
- if ( pdb_system_call_eflags_addr != 0 )
- {
- unsigned long eflags;
- char eflags_buf[sizeof(eflags)*2]; /* STUPID STUPID STUPID */
-
- pdb_linux_get_values((u_char*)&eflags, sizeof(eflags),
- pdb_system_call_eflags_addr,
- pdb_ctx.process, pdb_ctx.ptbr);
- eflags &= ~X86_EFLAGS_TF;
- mem2hex ((u_char *)&eflags, eflags_buf, sizeof(eflags));
- pdb_linux_set_values(eflags_buf, sizeof(eflags),
- pdb_system_call_eflags_addr,
- pdb_ctx.process, pdb_ctx.ptbr);
- }
-
- regs->eflags &= ~X86_EFLAGS_TF;
- return 1; /* jump out before replying to gdb */
- /* not reached */
- }
- case 'd':
- remote_debug = !(remote_debug); /* toggle debug flag */
- break;
- case 'D': /* detach */
- return go;
- /* not reached */
- case 'g': /* return the value of the CPU registers */
- {
- pdb_x86_to_gdb_regs (pdb_out_buffer, regs);
- break;
- }
- case 'G': /* set the value of the CPU registers - return OK */
- {
- pdb_gdb_to_x86_regs (regs, ptr);
- break;
- }
- case 'H':
- {
- int thread;
- char *next = &ptr[1];
-
- if (hexToInt (&next, &thread))
- {
- if (*ptr == 'c')
- {
- pdb_continue_thread = thread;
- }
- else if (*ptr == 'g')
- {
- pdb_general_thread = thread;
- }
- else
- {
- printk ("pdb error: unknown set thread command %c (%d)\n",
- *ptr, thread);
- strcpy (pdb_out_buffer, "E00");
- break;
- }
- }
- strcpy (pdb_out_buffer, "OK");
- break;
- }
- case 'k': /* kill request */
- {
- strcpy (pdb_out_buffer, "OK"); /* ack for fun */
- printk ("don't kill bill...\n");
- ack = 0;
- break;
- }
-
- case 'q':
- {
- pdb_process_query(ptr);
- break;
- }
-
- /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
- case 'm':
- {
- /* TRY TO READ %x,%x. IF SUCCEED, SET PTR = 0 */
- if (hexToInt (&ptr, (int *)&addr))
- if (*(ptr++) == ',')
- if (hexToInt (&ptr, &length))
- {
- ptr = 0;
-
- pdb_page_fault_possible = 1;
- pdb_page_fault = 0;
- if (addr >= PAGE_OFFSET)
- {
- mem2hex ((char *) addr, pdb_out_buffer, length);
- }
- else if (pdb_ctx.process != -1)
- {
- pdb_linux_get_values(pdb_buffer, length, addr,
- pdb_ctx.process, pdb_ctx.ptbr);
- mem2hex (pdb_buffer, pdb_out_buffer, length);
- }
- else
- {
- pdb_get_values (pdb_buffer, length,
- pdb_ctx.ptbr, addr);
- mem2hex (pdb_buffer, pdb_out_buffer, length);
- }
-
- pdb_page_fault_possible = 0;
- if (pdb_page_fault)
- {
- strcpy (pdb_out_buffer, "E03");
- }
- }
-
- if (ptr)
- {
- strcpy (pdb_out_buffer, "E01");
- }
- break;
- }
-
- /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
- case 'M':
- {
- /* TRY TO READ '%x,%x:'. IF SUCCEED, SET PTR = 0 */
- if (hexToInt (&ptr, (int *)&addr))
- if (*(ptr++) == ',')
- if (hexToInt (&ptr, &length))
- if (*(ptr++) == ':')
- {
-
- pdb_page_fault_possible = 1;
- pdb_page_fault = 0;
- if (addr >= PAGE_OFFSET)
- {
- hex2mem (ptr, (char *)addr, length);
- pdb_bkpt_check(ptr, length, pdb_ctx.ptbr, addr);
- }
- else if (pdb_ctx.process != -1)
- {
- pdb_linux_set_values(ptr, length, addr,
- pdb_ctx.process,
- pdb_ctx.ptbr);
- pdb_bkpt_check(ptr, length, pdb_ctx.ptbr, addr);
- }
- else
- {
- pdb_set_values (ptr, length,
- pdb_ctx.ptbr, addr);
- pdb_bkpt_check(ptr, length, pdb_ctx.ptbr, addr);
- }
- pdb_page_fault_possible = 0;
- if (pdb_page_fault)
- {
- strcpy (pdb_out_buffer, "E03");
- }
- else
- {
- strcpy (pdb_out_buffer, "OK");
- }
-
- ptr = 0;
- }
- if (ptr)
- {
- strcpy (pdb_out_buffer, "E02");
- }
- break;
- }
- case 'T':
- {
- int id;
-
- if (hexToInt (&ptr, &id))
- {
- strcpy (pdb_out_buffer, "E00");
-
-#ifdef PDB_PAST
-
- switch (pdb_level) /* previous level */
- {
- case PDB_LVL_XEN:
- {
- struct domain *p;
- id -= PDB_ID_OFFSET;
- if ( (p = find_domain_by_id(id)) == NULL)
- strcpy (pdb_out_buffer, "E00");
- else
- strcpy (pdb_out_buffer, "OK");
- put_domain(p);
-
- pdb_level = PDB_LVL_GUESTOS;
- pdb_ctx[pdb_level].ctrl = id;
- pdb_ctx[pdb_level].info = id;
- break;
- }
- case PDB_LVL_GUESTOS:
- {
- if (pdb_level == -1)
- {
- pdb_level = PDB_LVL_XEN;
- }
- else
- {
- pdb_level = PDB_LVL_PROCESS;
- pdb_ctx[pdb_level].ctrl = id;
- pdb_ctx[pdb_level].info = id;
- }
- break;
- }
- case PDB_LVL_PROCESS:
- {
- if (pdb_level == -1)
- {
- pdb_level = PDB_LVL_GUESTOS;
- }
- break;
- }
- default:
- {
- printk ("pdb internal error: invalid level [%d]\n",
- pdb_level);
- }
- }
-
-#endif /* PDB_PAST */
- }
- break;
- }
- }
-
-exit:
- /* reply to the request */
- pdb_put_packet (pdb_out_buffer, ack);
-
- return go;
-}
-
-/*
- * process an input character from the serial line.
- *
- * return "1" if the character is a gdb debug string
- * (and hence shouldn't be further processed).
- */
-
-int pdb_debug_state = 0; /* small parser state machine */
-
-int hex(char ch)
-{
- if ((ch >= 'a') && (ch <= 'f')) return (ch-'a'+10);
- if ((ch >= '0') && (ch <= '9')) return (ch-'0');
- if ((ch >= 'A') && (ch <= 'F')) return (ch-'A'+10);
- return (-1);
-}
-
-/* convert the memory pointed to by mem into hex, placing result in buf */
-/* return a pointer to the last char put in buf (null) */
-char *
-mem2hex (mem, buf, count)
- char *mem;
- char *buf;
- int count;
-{
- int i;
- unsigned char ch;
-
- for (i = 0; i < count; i++)
- {
- ch = get_char (mem++);
- *buf++ = hexchars[ch >> 4];
- *buf++ = hexchars[ch % 16];
- }
- *buf = 0;
- return (buf);
-}
-
-/* convert the hex array pointed to by buf into binary to be placed in mem */
-/* return a pointer to the character AFTER the last byte written */
-char *
-hex2mem (buf, mem, count)
- char *buf;
- char *mem;
- int count;
-{
- int i;
- unsigned char ch;
-
- for (i = 0; i < count; i++)
- {
- ch = hex (*buf++) << 4;
- ch = ch + hex (*buf++);
- set_char (mem++, ch);
- }
- return (mem);
-}
-
-int
-hexToInt (char **ptr, int *intValue)
-{
- int numChars = 0;
- int hexValue;
- int negative = 0;
-
- *intValue = 0;
-
- if (**ptr == '-')
- {
- negative = 1;
- numChars++;
- (*ptr)++;
- }
-
- while (**ptr)
- {
- hexValue = hex (**ptr);
- if (hexValue >= 0)
- {
- *intValue = (*intValue << 4) | hexValue;
- numChars++;
- }
- else
- break;
-
- (*ptr)++;
- }
-
- if ( negative )
- *intValue *= -1;
-
- return (numChars);
-}
-
-/***********************************************************************/
-/***********************************************************************/
-
-
-/*
- * Add a breakpoint to the list of known breakpoints.
- * For now there should only be two or three breakpoints so
- * we use a simple linked list. In the future, maybe a red-black tree?
- */
-struct pdb_breakpoint breakpoints;
-
-void pdb_bkpt_add (unsigned long cr3, unsigned long address)
-{
- struct pdb_breakpoint *bkpt = xmalloc(sizeof(*bkpt));
- bkpt->cr3 = cr3;
- bkpt->address = address;
- list_add(&bkpt->list, &breakpoints.list);
-}
-
-/*
- * Check to see of the breakpoint is in the list of known breakpoints
- * Return 1 if it has been set, NULL otherwise.
- */
-struct pdb_breakpoint* pdb_bkpt_search (unsigned long cr3,
- unsigned long address)
-{
- struct pdb_breakpoint *bkpt;
-
- list_for_each_entry ( bkpt, &breakpoints.list, list )
- {
- if ( bkpt->cr3 == cr3 && bkpt->address == address )
- return bkpt;
- }
-
- return NULL;
-}
-
-/*
- * Remove a breakpoint to the list of known breakpoints.
- * Return 1 if the element was not found, otherwise 0.
- */
-int pdb_bkpt_remove (unsigned long cr3, unsigned long address)
-{
- struct pdb_breakpoint *bkpt;
-
- list_for_each_entry ( bkpt, &breakpoints.list, list )
- {
- if ( bkpt->cr3 == cr3 && bkpt->address == address )
- {
- list_del(&bkpt->list);
- xfree(bkpt);
- return 0;
- }
- }
-
- return 1;
-}
-
-/*
- * Check to see if a memory write is really gdb setting a breakpoint
- */
-void pdb_bkpt_check (u_char *buffer, int length,
- unsigned long cr3, unsigned long addr)
-{
- if (length == 1 && buffer[0] == 'c' && buffer[1] == 'c')
- {
- /* inserting a new breakpoint */
- pdb_bkpt_add(cr3, addr);
- TRC(printk("pdb breakpoint detected at 0x%lx:0x%lx\n", cr3, addr));
- }
- else if ( pdb_bkpt_remove(cr3, addr) == 0 )
- {
- /* removing a breakpoint */
- TRC(printk("pdb breakpoint cleared at 0x%lx:0x%lx\n", cr3, addr));
- }
-}
-
-/***********************************************************************/
-
-int pdb_change_values(u_char *buffer, int length,
- unsigned long cr3, unsigned long addr, int rw);
-int pdb_change_values_one_page(u_char *buffer, int length,
- unsigned long cr3, unsigned long addr, int rw);
-
-#define __PDB_GET_VAL 1
-#define __PDB_SET_VAL 2
-
-/*
- * Set memory in a domain's address space
- * Set "length" bytes at "address" from "domain" to the values in "buffer".
- * Return the number of bytes set, 0 if there was a problem.
- */
-
-int pdb_set_values(u_char *buffer, int length,
- unsigned long cr3, unsigned long addr)
-{
- int count = pdb_change_values(buffer, length, cr3, addr, __PDB_SET_VAL);
- return count;
-}
-
-/*
- * Read memory from a domain's address space.
- * Fetch "length" bytes at "address" from "domain" into "buffer".
- * Return the number of bytes read, 0 if there was a problem.
- */
-
-int pdb_get_values(u_char *buffer, int length,
- unsigned long cr3, unsigned long addr)
-{
- return pdb_change_values(buffer, length, cr3, addr, __PDB_GET_VAL);
-}
-
-/*
- * Read or write memory in an address space
- */
-int pdb_change_values(u_char *buffer, int length,
- unsigned long cr3, unsigned long addr, int rw)
-{
- int remaining; /* number of bytes to touch past this page */
- int bytes = 0;
-
- while ( (remaining = (addr + length - 1) - (addr | (PAGE_SIZE - 1))) > 0)
- {
- bytes += pdb_change_values_one_page(buffer, length - remaining,
- cr3, addr, rw);
- buffer = buffer + (2 * (length - remaining));
- length = remaining;
- addr = (addr | (PAGE_SIZE - 1)) + 1;
- }
-
- bytes += pdb_change_values_one_page(buffer, length, cr3, addr, rw);
- return bytes;
-}
-
-/*
- * Change memory in a process' address space in one page
- * Read or write "length" bytes at "address" into/from "buffer"
- * from the virtual address space referenced by "cr3".
- * Return the number of bytes read, 0 if there was a problem.
- */
-
-int pdb_change_values_one_page(u_char *buffer, int length,
- unsigned long cr3, unsigned long addr, int rw)
-{
- l2_pgentry_t* l2_table = NULL; /* page directory */
- l1_pgentry_t* l1_table = NULL; /* page table */
- u_char *page; /* 4k page */
- int bytes = 0;
-
- l2_table = map_domain_mem(cr3);
- l2_table += l2_table_offset(addr);
- if (!(l2_pgentry_val(*l2_table) & _PAGE_PRESENT))
- {
- if (pdb_page_fault_possible == 1)
- {
- pdb_page_fault = 1;
- TRC(printk("pdb: L2 error (0x%lx)\n", addr));
- }
- else
- {
- printk ("pdb error: cr3: 0x%lx dom0cr3: 0x%lx\n", cr3,
- dom0->mm.shadow_mode ? pagetable_val(dom0->mm.shadow_table)
- : pagetable_val(dom0->mm.pagetable));
- printk ("pdb error: L2:0x%p (0x%lx)\n",
- l2_table, l2_pgentry_val(*l2_table));
- }
- goto exit2;
- }
-
- if (l2_pgentry_val(*l2_table) & _PAGE_PSE)
- {
-#define PSE_PAGE_SHIFT L2_PAGETABLE_SHIFT
-#define PSE_PAGE_SIZE (1UL << PSE_PAGE_SHIFT)
-#define PSE_PAGE_MASK (~(PSE_PAGE_SIZE-1))
-
-#define L1_PAGE_BITS ( (ENTRIES_PER_L1_PAGETABLE - 1) << L1_PAGETABLE_SHIFT )
-
-#define pse_pgentry_to_phys(_x) (l2_pgentry_val(_x) & PSE_PAGE_MASK)
-
- page = map_domain_mem(pse_pgentry_to_phys(*l2_table) + /* 10 bits */
- (addr & L1_PAGE_BITS)); /* 10 bits */
- page += addr & (PAGE_SIZE - 1); /* 12 bits */
- }
- else
- {
- l1_table = map_domain_mem(l2_pgentry_to_phys(*l2_table));
- l1_table += l1_table_offset(addr);
- if (!(l1_pgentry_val(*l1_table) & _PAGE_PRESENT))
- {
- if (pdb_page_fault_possible == 1)
- {
- pdb_page_fault = 1;
- TRC(printk ("pdb: L1 error (0x%lx)\n", addr));
- }
- else
- {
- printk ("L2:0x%p (0x%lx) L1:0x%p (0x%lx)\n",
- l2_table, l2_pgentry_val(*l2_table),
- l1_table, l1_pgentry_val(*l1_table));
- }
- goto exit1;
- }
-
- page = map_domain_mem(l1_pgentry_to_phys(*l1_table));
- page += addr & (PAGE_SIZE - 1);
- }
-
- switch (rw)
- {
- case __PDB_GET_VAL: /* read */
- memcpy (buffer, page, length);
- bytes = length;
- break;
- case __PDB_SET_VAL: /* write */
- hex2mem (buffer, page, length);
- bytes = length;
- break;
- default: /* unknown */
- printk ("error: unknown RW flag: %d\n", rw);
- return 0;
- }
-
- unmap_domain_mem((void *)page);
-exit1:
- if (l1_table != NULL)
- unmap_domain_mem((void *)l1_table);
-exit2:
- unmap_domain_mem((void *)l2_table);
-
- return bytes;
-}
-
-/***********************************************************************/
-
-void breakpoint(void);
-
-/* send the packet in buffer. */
-void pdb_put_packet (unsigned char *buffer, int ack)
-{
- unsigned char checksum;
- int count;
- char ch;
-
- /* $<packet info>#<checksum> */
- /* do */
- {
- pdb_put_char ('$');
- checksum = 0;
- count = 0;
-
- while ((ch = buffer[count]))
- {
- pdb_put_char (ch);
- checksum += ch;
- count += 1;
- }
-
- pdb_put_char('#');
- pdb_put_char(hexchars[checksum >> 4]);
- pdb_put_char(hexchars[checksum % 16]);
- }
-
- if (ack)
- {
- if ((ch = pdb_get_char()) != '+')
- {
- printk(" pdb return error: %c 0x%x [%s]\n", ch, ch, buffer);
- }
- }
-}
-
-void pdb_get_packet(char *buffer)
-{
- int count;
- char ch;
- unsigned char checksum = 0;
- unsigned char xmitcsum = 0;
-
- do
- {
- while ((ch = pdb_get_char()) != '$');
-
- count = 0;
- checksum = 0;
-
- while (count < BUFMAX)
- {
- ch = pdb_get_char();
- if (ch == '#') break;
- checksum += ch;
- buffer[count] = ch;
- count++;
- }
- buffer[count] = 0;
-
- if (ch == '#')
- {
- xmitcsum = hex(pdb_get_char()) << 4;
- xmitcsum += hex(pdb_get_char());
-
- if (xmitcsum == checksum)
- {
- pdb_put_char('+');
- if (buffer[2] == ':')
- {
- printk ("pdb: obsolete gdb packet (sequence ID)\n");
- }
- }
- else
- {
- pdb_put_char('-');
- }
- }
- } while (checksum != xmitcsum);
-
- return;
-}
-
-/*
- * process a machine interrupt or exception
- * Return 1 if pdb is not interested in the exception; it should
- * be propagated to the guest os.
- */
-
-int pdb_handle_exception(int exceptionVector,
- struct xen_regs *xen_regs)
-{
- int signal = 0;
- struct pdb_breakpoint* bkpt;
- int watchdog_save;
- unsigned long cr3 = read_cr3();
-
- /* No vm86 handling here as yet. */
- if ( VM86_MODE(xen_regs) )
- return 1;
-
- /* If the exception is an int3 from user space then pdb is only
- interested if it re-wrote an instruction set the breakpoint.
- This occurs when leaving a system call from a domain.
- */
- if ( (exceptionVector == 3) &&
- RING_3(xen_regs) &&
- (xen_regs->eip != (pdb_system_call_next_addr + 1)) )
- {
- TRC(printf("pdb: user bkpt (0x%x) at 0x%x:0x%lx:0x%x\n",
- exceptionVector, xen_regs->cs & 3, cr3, xen_regs->eip));
- return 1;
- }
-
- /*
- * If PDB didn't set the breakpoint, is not single stepping,
- * is not entering a system call in a domain,
- * the user didn't press the magic debug key,
- * then we don't handle the exception.
- */
- bkpt = pdb_bkpt_search(cr3, xen_regs->eip - 1);
- if ( (bkpt == NULL) &&
- !pdb_stepping &&
- !pdb_system_call &&
- xen_regs->eip != pdb_system_call_next_addr + 1 &&
- (exceptionVector != KEYPRESS_EXCEPTION) &&
- xen_regs->eip < 0xc0000000) /* Linux-specific for now! */
- {
- TRC(printf("pdb: user bkpt (0x%x) at 0x%lx:0x%x\n",
- exceptionVector, cr3, xen_regs->eip));
- return 1;
- }
-
- printk("pdb_handle_exception [0x%x][0x%lx:0x%x]\n",
- exceptionVector, cr3, xen_regs->eip);
-
- if ( pdb_stepping )
- {
- /* Stepped one instruction; now return to normal execution. */
- xen_regs->eflags &= ~X86_EFLAGS_TF;
- pdb_stepping = 0;
- }
-
- if ( pdb_system_call )
- {
- pdb_system_call = 0;
-
- pdb_linux_syscall_exit_bkpt (xen_regs, &pdb_ctx);
-
- /* we don't have a saved breakpoint so we need to rewind eip */
- xen_regs->eip--;
-
- /* if ther user doesn't care about breaking when entering a
- system call then we'll just ignore the exception */
- if ( (pdb_ctx.system_call & 0x01) == 0 )
- {
- return 0;
- }
- }
-
- if ( exceptionVector == BREAKPT_EXCEPTION && bkpt != NULL)
- {
- /* Executed Int3: replace breakpoint byte with real program byte. */
- xen_regs->eip--;
- }
-
- /* returning to user space after a system call */
- if ( xen_regs->eip == pdb_system_call_next_addr + 1)
- {
- u_char instr[2]; /* REALLY REALLY REALLY STUPID */
-
- mem2hex (&pdb_system_call_leave_instr, instr, sizeof(instr));
-
- pdb_linux_set_values (instr, 1, pdb_system_call_next_addr,
- pdb_ctx.process, pdb_ctx.ptbr);
-
- pdb_system_call_next_addr = 0;
- pdb_system_call_leave_instr = 0;
-
- /* manually rewind eip */
- xen_regs->eip--;
-
- /* if the user doesn't care about breaking when returning
- to user space after a system call then we'll just ignore
- the exception */
- if ( (pdb_ctx.system_call & 0x02) == 0 )
- {
- return 0;
- }
- }
-
- /* Generate a signal for GDB. */
- switch ( exceptionVector )
- {
- case KEYPRESS_EXCEPTION:
- signal = 2; break; /* SIGINT */
- case DEBUG_EXCEPTION:
- signal = 5; break; /* SIGTRAP */
- case BREAKPT_EXCEPTION:
- signal = 5; break; /* SIGTRAP */
- default:
- printk("pdb: can't generate signal for unknown exception vector %d\n",
- exceptionVector);
- break;
- }
-
- pdb_out_buffer[0] = 'S';
- pdb_out_buffer[1] = hexchars[signal >> 4];
- pdb_out_buffer[2] = hexchars[signal % 16];
- pdb_out_buffer[3] = 0;
- pdb_put_packet(pdb_out_buffer, 1);
-
- watchdog_save = watchdog_on;
- watchdog_on = 0;
-
- do {
- pdb_out_buffer[0] = 0;
- pdb_get_packet(pdb_in_buffer);
- }
- while ( pdb_process_command(pdb_in_buffer, xen_regs, cr3, signal) == 0 );
-
- watchdog_on = watchdog_save;
-
- return 0;
-}
-
-void pdb_key_pressed(unsigned char key)
-{
- struct xen_regs *regs = (struct xen_regs *)get_execution_context();
- pdb_handle_exception(KEYPRESS_EXCEPTION, regs);
-}
-
-void pdb_handle_debug_trap(struct xen_regs *regs, long error_code)
-{
- unsigned int condition;
- struct domain *d = current;
- struct trap_bounce *tb = &d->thread.trap_bounce;
-
- __asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
- if ( (condition & (1 << 14)) != (1 << 14) )
- printk("\nwarning: debug trap w/o BS bit [0x%x]\n\n", condition);
- __asm__("movl %0,%%db6" : : "r" (0));
-
- if ( pdb_handle_exception(1, regs) != 0 )
- {
- d->thread.debugreg[6] = condition;
-
- tb->flags = TBF_EXCEPTION;
- tb->cs = d->thread.traps[1].cs;
- tb->eip = d->thread.traps[1].address;
- }
-}
-
-void initialize_pdb()
-{
- /* Certain state must be initialised even when PDB will not be used. */
- memset((void *) &breakpoints, 0, sizeof(breakpoints));
- INIT_LIST_HEAD(&breakpoints.list);
- pdb_stepping = 0;
-
- if ( strcmp(opt_pdb, "none") == 0 )
- return;
-
- if ( (pdb_serhnd = parse_serial_handle(opt_pdb)) == -1 )
- {
- printk("error: failed to initialize PDB on port %s\n", opt_pdb);
- return;
- }
-
- pdb_ctx.valid = 1;
- pdb_ctx.domain = -1;
- pdb_ctx.process = -1;
- pdb_ctx.system_call = 0;
- pdb_ctx.ptbr = 0;
-
- printk("pdb: pervasive debugger (%s) www.cl.cam.ac.uk/netos/pdb\n",
- opt_pdb);
-
- /* Acknowledge any spurious GDB packets. */
- pdb_put_char('+');
-
- register_keyhandler('D', pdb_key_pressed, "enter pervasive debugger");
-
- pdb_initialized = 1;
-}
-
-void breakpoint(void)
-{
- if ( pdb_initialized )
- asm("int $3");
-}
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 6ef530c4e6..f8595633cc 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
#include <xen/config.h>
#include <xen/init.h>
@@ -17,7 +18,6 @@
#include <asm/apic.h>
#include <asm/desc.h>
#include <asm/domain_page.h>
-#include <asm/pdb.h>
#include <asm/shadow.h>
#include <asm/e820.h>
@@ -55,6 +55,8 @@ boolean_param("ignorebiostables", opt_ignorebiostables);
static int opt_watchdog = 0;
boolean_param("watchdog", opt_watchdog);
+int early_boot = 1;
+
unsigned long xenheap_phys_end;
extern void arch_init_memory(void);
@@ -77,7 +79,7 @@ EXPORT_SYMBOL(mmu_cr4_features);
unsigned long wait_init_idle;
-struct domain *idle_task[NR_CPUS] = { &idle0_task };
+struct exec_domain *idle_task[NR_CPUS] = { &idle0_exec_domain };
#ifdef CONFIG_ACPI_INTERPRETER
int acpi_disabled = 0;
@@ -89,23 +91,21 @@ EXPORT_SYMBOL(acpi_disabled);
int phys_proc_id[NR_CPUS];
int logical_proc_id[NR_CPUS];
-#if defined(__i386__)
-
-/* Standard macro to see if a specific flag is changeable */
-static inline int flag_is_changeable_p(u32 flag)
+/* Standard macro to see if a specific flag is changeable. */
+static inline int flag_is_changeable_p(unsigned long flag)
{
- u32 f1, f2;
-
- asm("pushfl\n\t"
- "pushfl\n\t"
- "popl %0\n\t"
- "movl %0,%1\n\t"
- "xorl %2,%0\n\t"
- "pushl %0\n\t"
- "popfl\n\t"
- "pushfl\n\t"
- "popl %0\n\t"
- "popfl\n\t"
+ unsigned long f1, f2;
+
+ asm("pushf\n\t"
+ "pushf\n\t"
+ "pop %0\n\t"
+ "mov %0,%1\n\t"
+ "xor %2,%0\n\t"
+ "push %0\n\t"
+ "popf\n\t"
+ "pushf\n\t"
+ "pop %0\n\t"
+ "popf\n\t"
: "=&r" (f1), "=&r" (f2)
: "ir" (flag));
@@ -118,12 +118,6 @@ static int __init have_cpuid_p(void)
return flag_is_changeable_p(X86_EFLAGS_ID);
}
-#elif defined(__x86_64__)
-
-#define have_cpuid_p() (1)
-
-#endif
-
void __init get_cpu_vendor(struct cpuinfo_x86 *c)
{
char *v = c->x86_vendor_id;
@@ -185,6 +179,11 @@ static void __init init_intel(struct cpuinfo_x86 *c)
}
}
#endif
+
+#ifdef CONFIG_VMX
+ start_vmx();
+#endif
+
}
static void __init init_amd(struct cpuinfo_x86 *c)
@@ -299,46 +298,50 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
unsigned long cpu_initialized;
void __init cpu_init(void)
{
-#if defined(__i386__) /* XXX */
+ extern void percpu_traps_init(void);
int nr = smp_processor_id();
- struct tss_struct * t = &init_tss[nr];
+ struct tss_struct *t = &init_tss[nr];
if ( test_and_set_bit(nr, &cpu_initialized) )
panic("CPU#%d already initialized!!!\n", nr);
printk("Initializing CPU#%d\n", nr);
- t->bitmap = IOBMP_INVALID_OFFSET;
- memset(t->io_bitmap, ~0, sizeof(t->io_bitmap));
-
/* Set up GDT and IDT. */
SET_GDT_ENTRIES(current, DEFAULT_GDT_ENTRIES);
SET_GDT_ADDRESS(current, DEFAULT_GDT_ADDRESS);
- __asm__ __volatile__("lgdt %0": "=m" (*current->mm.gdt));
- __asm__ __volatile__("lidt %0": "=m" (idt_descr));
+ __asm__ __volatile__ ( "lgdt %0" : "=m" (*current->arch.gdt) );
+ __asm__ __volatile__ ( "lidt %0" : "=m" (idt_descr) );
/* No nested task. */
- __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl");
+ __asm__ __volatile__ ( "pushf ; andw $0xbfff,(%"__OP"sp) ; popf" );
/* Ensure FPU gets initialised for each domain. */
stts();
/* Set up and load the per-CPU TSS and LDT. */
+ t->bitmap = IOBMP_INVALID_OFFSET;
+ memset(t->io_bitmap, ~0, sizeof(t->io_bitmap));
+#if defined(__i386__)
t->ss0 = __HYPERVISOR_DS;
t->esp0 = get_stack_top();
+#elif defined(__x86_64__)
+ t->rsp0 = get_stack_top();
+#endif
set_tss_desc(nr,t);
load_TR(nr);
- __asm__ __volatile__("lldt %%ax"::"a" (0));
+ __asm__ __volatile__ ( "lldt %%ax" : : "a" (0) );
/* Clear all 6 debug registers. */
-#define CD(register) __asm__("movl %0,%%db" #register ::"r"(0) );
+#define CD(register) __asm__ ( "mov %0,%%db" #register : : "r" (0UL) );
CD(0); CD(1); CD(2); CD(3); /* no db4 and db5 */; CD(6); CD(7);
#undef CD
+ percpu_traps_init();
+
/* Install correct page table. */
- write_ptbase(&current->mm);
+ write_ptbase(current);
init_idle_task();
-#endif
}
static void __init do_initcalls(void)
@@ -357,7 +360,7 @@ static void __init start_of_day(void)
#ifdef MEMORY_GUARD
/* Unmap the first page of CPU0's stack. */
extern unsigned long cpu0_stack[];
- memguard_guard_range(cpu0_stack, PAGE_SIZE);
+ memguard_guard_stack(cpu0_stack);
#endif
open_softirq(NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ, new_tlbflush_clock_period);
@@ -424,10 +427,6 @@ static void __init start_of_day(void)
serial_init_stage2();
-#ifdef XEN_DEBUGGER
- initialize_pdb(); /* pervasive debugger */
-#endif
-
if ( !cpu_has_apic )
{
do_timer_lists_from_pit = 1;
@@ -459,6 +458,9 @@ static void __init start_of_day(void)
#endif
watchdog_on = 1;
+#ifdef __x86_64__ /* x86_32 uses low mappings when building DOM0. */
+ zap_low_mappings();
+#endif
}
void __init __start_xen(multiboot_info_t *mbi)
@@ -477,7 +479,7 @@ void __init __start_xen(multiboot_info_t *mbi)
cmdline_parse(__va(mbi->cmdline));
/* Must do this early -- e.g., spinlocks rely on get_current(). */
- set_current(&idle0_task);
+ set_current(&idle0_exec_domain);
/* We initialise the serial devices very early so we can get debugging. */
serial_init_stage1();
@@ -503,7 +505,7 @@ void __init __start_xen(multiboot_info_t *mbi)
e820_raw[e820_raw_nr].size =
((u64)map->length_high << 32) | (u64)map->length_low;
e820_raw[e820_raw_nr].type =
- (map->type > E820_NVS) ? E820_RESERVED : map->type;
+ (map->type > E820_SHARED_PAGE) ? E820_RESERVED : map->type;
e820_raw_nr++;
bytes += map->size + 4;
}
@@ -589,11 +591,7 @@ void __init __start_xen(multiboot_info_t *mbi)
(xenheap_phys_end-__pa(heap_start)) >> 20,
(xenheap_phys_end-__pa(heap_start)) >> 10);
- /* Initialise the slab allocator. */
- xmem_cache_init();
- xmem_cache_sizes_init(max_page);
-
- domain_startofday();
+ early_boot = 0;
start_of_day();
@@ -606,7 +604,7 @@ void __init __start_xen(multiboot_info_t *mbi)
if ( dom0 == NULL )
panic("Error creating domain 0\n");
- set_bit(DF_PRIVILEGED, &dom0->flags);
+ set_bit(DF_PRIVILEGED, &dom0->d_flags);
/* Grab the DOM0 command line. Skip past the image name. */
cmdline = (unsigned char *)(mod[0].string ? __va(mod[0].string) : NULL);
@@ -622,10 +620,10 @@ void __init __start_xen(multiboot_info_t *mbi)
* above our heap. The second module, if present, is an initrd ramdisk.
*/
if ( construct_dom0(dom0, dom0_memory_start, dom0_memory_end,
- (char *)initial_images_start,
+ initial_images_start,
mod[0].mod_end-mod[0].mod_start,
(mbi->mods_count == 1) ? 0 :
- (char *)initial_images_start +
+ initial_images_start +
(mod[1].mod_start-mod[0].mod_start),
(mbi->mods_count == 1) ? 0 :
mod[mbi->mods_count-1].mod_end - mod[1].mod_start,
@@ -642,7 +640,7 @@ void __init __start_xen(multiboot_info_t *mbi)
/* Give up the VGA console if DOM0 is configured to grab it. */
console_endboot(cmdline && strstr(cmdline, "tty0"));
- domain_unpause_by_systemcontroller(current);
+ domain_unpause_by_systemcontroller(current->domain);
domain_unpause_by_systemcontroller(dom0);
startup_cpu_idle_loop();
}
diff --git a/xen/arch/x86/shadow.c b/xen/arch/x86/shadow.c
index 41ac65177a..1ac4109155 100644
--- a/xen/arch/x86/shadow.c
+++ b/xen/arch/x86/shadow.c
@@ -1,4 +1,4 @@
-/* -*- Mode:C++; c-file-style:BSD; c-basic-offset:4; tab-width:4 -*- */
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
#include <xen/config.h>
#include <xen/types.h>
@@ -28,9 +28,9 @@ hypercall lock anyhow (at least initially).
********/
static inline void free_shadow_page(
- struct mm_struct *m, struct pfn_info *page)
+ struct domain *d, struct pfn_info *page)
{
- m->shadow_page_count--;
+ d->arch.shadow_page_count--;
switch ( page->u.inuse.type_info & PGT_type_mask )
{
@@ -51,7 +51,7 @@ static inline void free_shadow_page(
free_domheap_page(page);
}
-static void free_shadow_state(struct mm_struct *m)
+static void free_shadow_state(struct domain *d)
{
int i, free = 0;
struct shadow_status *x, *n;
@@ -61,19 +61,19 @@ static void free_shadow_state(struct mm_struct *m)
* e.g., You are expected to have paused the domain and synchronized CR3.
*/
- shadow_audit(m, 1);
+ shadow_audit(d, 1);
/* Free each hash chain in turn. */
for ( i = 0; i < shadow_ht_buckets; i++ )
{
/* Skip empty buckets. */
- x = &m->shadow_ht[i];
+ x = &d->arch.shadow_ht[i];
if ( x->pfn == 0 )
continue;
/* Free the head page. */
free_shadow_page(
- m, &frame_table[x->spfn_and_flags & PSH_pfn_mask]);
+ d, &frame_table[x->spfn_and_flags & PSH_pfn_mask]);
/* Reinitialise the head node. */
x->pfn = 0;
@@ -88,7 +88,7 @@ static void free_shadow_state(struct mm_struct *m)
{
/* Free the shadow page. */
free_shadow_page(
- m, &frame_table[x->spfn_and_flags & PSH_pfn_mask]);
+ d, &frame_table[x->spfn_and_flags & PSH_pfn_mask]);
/* Re-initialise the chain node. */
x->pfn = 0;
@@ -96,20 +96,20 @@ static void free_shadow_state(struct mm_struct *m)
/* Add to the free list. */
n = x->next;
- x->next = m->shadow_ht_free;
- m->shadow_ht_free = x;
+ x->next = d->arch.shadow_ht_free;
+ d->arch.shadow_ht_free = x;
free++;
}
- shadow_audit(m, 0);
+ shadow_audit(d, 0);
}
SH_LOG("Free shadow table. Freed=%d.", free);
}
static inline int clear_shadow_page(
- struct mm_struct *m, struct shadow_status *x)
+ struct domain *d, struct shadow_status *x)
{
unsigned long *p;
int restart = 0;
@@ -120,14 +120,17 @@ static inline int clear_shadow_page(
/* We clear L2 pages by zeroing the guest entries. */
case PGT_l2_page_table:
p = map_domain_mem((spage - frame_table) << PAGE_SHIFT);
- memset(p, 0, DOMAIN_ENTRIES_PER_L2_PAGETABLE * sizeof(*p));
+ if (d->arch.shadow_mode == SHM_full_32)
+ memset(p, 0, ENTRIES_PER_L2_PAGETABLE * sizeof(*p));
+ else
+ memset(p, 0, DOMAIN_ENTRIES_PER_L2_PAGETABLE * sizeof(*p));
unmap_domain_mem(p);
break;
/* We clear L1 pages by freeing them: no benefit from zeroing them. */
case PGT_l1_page_table:
- delete_shadow_status(m, x->pfn);
- free_shadow_page(m, spage);
+ delete_shadow_status(d, x->pfn);
+ free_shadow_page(d, spage);
restart = 1; /* We need to go to start of list again. */
break;
}
@@ -135,29 +138,29 @@ static inline int clear_shadow_page(
return restart;
}
-static void clear_shadow_state(struct mm_struct *m)
+static void clear_shadow_state(struct domain *d)
{
int i;
struct shadow_status *x;
- shadow_audit(m, 1);
+ shadow_audit(d, 1);
for ( i = 0; i < shadow_ht_buckets; i++ )
{
retry:
/* Skip empty buckets. */
- x = &m->shadow_ht[i];
+ x = &d->arch.shadow_ht[i];
if ( x->pfn == 0 )
continue;
- if ( clear_shadow_page(m, x) )
+ if ( clear_shadow_page(d, x) )
goto retry;
for ( x = x->next; x != NULL; x = x->next )
- if ( clear_shadow_page(m, x) )
+ if ( clear_shadow_page(d, x) )
goto retry;
- shadow_audit(m, 0);
+ shadow_audit(d, 0);
}
SH_VLOG("Scan shadow table. l1=%d l2=%d",
@@ -169,119 +172,118 @@ void shadow_mode_init(void)
{
}
-int shadow_mode_enable(struct domain *p, unsigned int mode)
+int shadow_mode_enable(struct domain *d, unsigned int mode)
{
- struct mm_struct *m = &p->mm;
-
- m->shadow_ht = xmalloc(
- shadow_ht_buckets * sizeof(struct shadow_status));
- if ( m->shadow_ht == NULL )
+ d->arch.shadow_ht = xmalloc_array(struct shadow_status, shadow_ht_buckets);
+ if ( d->arch.shadow_ht == NULL )
goto nomem;
- memset(m->shadow_ht, 0, shadow_ht_buckets * sizeof(struct shadow_status));
+ memset(d->arch.shadow_ht, 0,
+ shadow_ht_buckets * sizeof(struct shadow_status));
if ( mode == SHM_logdirty )
{
- m->shadow_dirty_bitmap_size = (p->max_pages + 63) & ~63;
- m->shadow_dirty_bitmap =
- xmalloc(m->shadow_dirty_bitmap_size/8);
- if ( m->shadow_dirty_bitmap == NULL )
+ d->arch.shadow_dirty_bitmap_size = (d->max_pages + 63) & ~63;
+ d->arch.shadow_dirty_bitmap =
+ xmalloc_array(unsigned long, d->arch.shadow_dirty_bitmap_size /
+ (8 * sizeof(unsigned long)));
+ if ( d->arch.shadow_dirty_bitmap == NULL )
{
- m->shadow_dirty_bitmap_size = 0;
+ d->arch.shadow_dirty_bitmap_size = 0;
goto nomem;
}
- memset(m->shadow_dirty_bitmap, 0, m->shadow_dirty_bitmap_size/8);
+ memset(d->arch.shadow_dirty_bitmap, 0,
+ d->arch.shadow_dirty_bitmap_size/8);
}
- m->shadow_mode = mode;
+ d->arch.shadow_mode = mode;
- __shadow_mk_pagetable(m);
+ __shadow_mk_pagetable(d->exec_domain[0]); /* XXX SMP */
return 0;
nomem:
- if ( m->shadow_ht != NULL )
- xfree( m->shadow_ht );
- m->shadow_ht = NULL;
+ if ( d->arch.shadow_ht != NULL )
+ xfree(d->arch.shadow_ht);
+ d->arch.shadow_ht = NULL;
return -ENOMEM;
}
void __shadow_mode_disable(struct domain *d)
{
- struct mm_struct *m = &d->mm;
struct shadow_status *x, *n;
- free_shadow_state(m);
- m->shadow_mode = 0;
+ free_shadow_state(d);
+ d->arch.shadow_mode = 0;
SH_VLOG("freed tables count=%d l1=%d l2=%d",
- m->shadow_page_count, perfc_value(shadow_l1_pages),
+ d->arch.shadow_page_count, perfc_value(shadow_l1_pages),
perfc_value(shadow_l2_pages));
- n = m->shadow_ht_extras;
+ n = d->arch.shadow_ht_extras;
while ( (x = n) != NULL )
{
- m->shadow_extras_count--;
+ d->arch.shadow_extras_count--;
n = *((struct shadow_status **)(&x[shadow_ht_extra_size]));
xfree(x);
}
- m->shadow_ht_extras = NULL;
- ASSERT(m->shadow_extras_count == 0);
- SH_LOG("freed extras, now %d", m->shadow_extras_count);
+ d->arch.shadow_ht_extras = NULL;
+ ASSERT(d->arch.shadow_extras_count == 0);
+ SH_LOG("freed extras, now %d", d->arch.shadow_extras_count);
- if ( m->shadow_dirty_bitmap != NULL )
+ if ( d->arch.shadow_dirty_bitmap != NULL )
{
- xfree(m->shadow_dirty_bitmap);
- m->shadow_dirty_bitmap = 0;
- m->shadow_dirty_bitmap_size = 0;
+ xfree(d->arch.shadow_dirty_bitmap);
+ d->arch.shadow_dirty_bitmap = 0;
+ d->arch.shadow_dirty_bitmap_size = 0;
}
- xfree(m->shadow_ht);
- m->shadow_ht = NULL;
+ xfree(d->arch.shadow_ht);
+ d->arch.shadow_ht = NULL;
}
static int shadow_mode_table_op(
struct domain *d, dom0_shadow_control_t *sc)
{
unsigned int op = sc->op;
- struct mm_struct *m = &d->mm;
int i, rc = 0;
- ASSERT(spin_is_locked(&m->shadow_lock));
+ ASSERT(spin_is_locked(&d->arch.shadow_lock));
SH_VLOG("shadow mode table op %08lx %08lx count %d",
- pagetable_val(m->pagetable), pagetable_val(m->shadow_table),
- m->shadow_page_count);
+ pagetable_val(d->exec_domain[0]->arch.pagetable), /* XXX SMP */
+ pagetable_val(d->exec_domain[0]->arch.shadow_table), /* XXX SMP */
+ d->arch.shadow_page_count);
- shadow_audit(m, 1);
+ shadow_audit(d, 1);
switch ( op )
{
case DOM0_SHADOW_CONTROL_OP_FLUSH:
- free_shadow_state(m);
+ free_shadow_state(d);
- m->shadow_fault_count = 0;
- m->shadow_dirty_count = 0;
- m->shadow_dirty_net_count = 0;
- m->shadow_dirty_block_count = 0;
+ d->arch.shadow_fault_count = 0;
+ d->arch.shadow_dirty_count = 0;
+ d->arch.shadow_dirty_net_count = 0;
+ d->arch.shadow_dirty_block_count = 0;
break;
case DOM0_SHADOW_CONTROL_OP_CLEAN:
- clear_shadow_state(m);
+ clear_shadow_state(d);
- sc->stats.fault_count = m->shadow_fault_count;
- sc->stats.dirty_count = m->shadow_dirty_count;
- sc->stats.dirty_net_count = m->shadow_dirty_net_count;
- sc->stats.dirty_block_count = m->shadow_dirty_block_count;
+ sc->stats.fault_count = d->arch.shadow_fault_count;
+ sc->stats.dirty_count = d->arch.shadow_dirty_count;
+ sc->stats.dirty_net_count = d->arch.shadow_dirty_net_count;
+ sc->stats.dirty_block_count = d->arch.shadow_dirty_block_count;
- m->shadow_fault_count = 0;
- m->shadow_dirty_count = 0;
- m->shadow_dirty_net_count = 0;
- m->shadow_dirty_block_count = 0;
+ d->arch.shadow_fault_count = 0;
+ d->arch.shadow_dirty_count = 0;
+ d->arch.shadow_dirty_net_count = 0;
+ d->arch.shadow_dirty_block_count = 0;
if ( (d->max_pages > sc->pages) ||
(sc->dirty_bitmap == NULL) ||
- (m->shadow_dirty_bitmap == NULL) )
+ (d->arch.shadow_dirty_bitmap == NULL) )
{
rc = -EINVAL;
break;
@@ -297,34 +299,35 @@ static int shadow_mode_table_op(
if (copy_to_user(
sc->dirty_bitmap + (i/(8*sizeof(unsigned long))),
- m->shadow_dirty_bitmap +(i/(8*sizeof(unsigned long))),
+ d->arch.shadow_dirty_bitmap +(i/(8*sizeof(unsigned long))),
bytes))
{
// copy_to_user can fail when copying to guest app memory.
// app should zero buffer after mallocing, and pin it
rc = -EINVAL;
memset(
- m->shadow_dirty_bitmap + (i/(8*sizeof(unsigned long))),
+ d->arch.shadow_dirty_bitmap +
+ (i/(8*sizeof(unsigned long))),
0, (d->max_pages/8) - (i/(8*sizeof(unsigned long))));
break;
}
memset(
- m->shadow_dirty_bitmap + (i/(8*sizeof(unsigned long))),
+ d->arch.shadow_dirty_bitmap + (i/(8*sizeof(unsigned long))),
0, bytes);
}
break;
case DOM0_SHADOW_CONTROL_OP_PEEK:
- sc->stats.fault_count = m->shadow_fault_count;
- sc->stats.dirty_count = m->shadow_dirty_count;
- sc->stats.dirty_net_count = m->shadow_dirty_net_count;
- sc->stats.dirty_block_count = m->shadow_dirty_block_count;
+ sc->stats.fault_count = d->arch.shadow_fault_count;
+ sc->stats.dirty_count = d->arch.shadow_dirty_count;
+ sc->stats.dirty_net_count = d->arch.shadow_dirty_net_count;
+ sc->stats.dirty_block_count = d->arch.shadow_dirty_block_count;
if ( (d->max_pages > sc->pages) ||
(sc->dirty_bitmap == NULL) ||
- (m->shadow_dirty_bitmap == NULL) )
+ (d->arch.shadow_dirty_bitmap == NULL) )
{
rc = -EINVAL;
break;
@@ -332,7 +335,7 @@ static int shadow_mode_table_op(
sc->pages = d->max_pages;
if (copy_to_user(
- sc->dirty_bitmap, m->shadow_dirty_bitmap, (d->max_pages+7)/8))
+ sc->dirty_bitmap, d->arch.shadow_dirty_bitmap, (d->max_pages+7)/8))
{
rc = -EINVAL;
break;
@@ -345,9 +348,9 @@ static int shadow_mode_table_op(
break;
}
- SH_VLOG("shadow mode table op : page count %d", m->shadow_page_count);
- shadow_audit(m, 1);
- __shadow_mk_pagetable(m);
+ SH_VLOG("shadow mode table op : page count %d", d->arch.shadow_page_count);
+ shadow_audit(d, 1);
+ __shadow_mk_pagetable(d->exec_domain[0]); /* XXX SMP */
return rc;
}
@@ -356,7 +359,7 @@ int shadow_mode_control(struct domain *d, dom0_shadow_control_t *sc)
unsigned int op = sc->op;
int rc = 0;
- if ( unlikely(d == current) )
+ if ( unlikely(d == current->domain) )
{
DPRINTK("Don't try to do a shadow op on yourself!\n");
return -EINVAL;
@@ -365,7 +368,7 @@ int shadow_mode_control(struct domain *d, dom0_shadow_control_t *sc)
domain_pause(d);
synchronise_pagetables(~0UL);
- shadow_lock(&d->mm);
+ shadow_lock(d);
switch ( op )
{
@@ -388,23 +391,23 @@ int shadow_mode_control(struct domain *d, dom0_shadow_control_t *sc)
break;
}
- shadow_unlock(&d->mm);
+ shadow_unlock(d);
domain_unpause(d);
return rc;
}
-static inline struct pfn_info *alloc_shadow_page(struct mm_struct *m)
+static inline struct pfn_info *alloc_shadow_page(struct domain *d)
{
struct pfn_info *page = alloc_domheap_page(NULL);
- m->shadow_page_count++;
+ d->arch.shadow_page_count++;
if ( unlikely(page == NULL) )
{
printk("Couldn't alloc shadow page! count=%d\n",
- m->shadow_page_count);
+ d->arch.shadow_page_count);
SH_VLOG("Shadow tables l1=%d l2=%d",
perfc_value(shadow_l1_pages),
perfc_value(shadow_l2_pages));
@@ -417,7 +420,7 @@ static inline struct pfn_info *alloc_shadow_page(struct mm_struct *m)
void unshadow_table(unsigned long gpfn, unsigned int type)
{
unsigned long spfn;
- struct domain *d = frame_table[gpfn].u.inuse.domain;
+ struct domain *d = page_get_owner(&frame_table[gpfn]);
SH_VLOG("unshadow_table type=%08x gpfn=%08lx", type, gpfn);
@@ -428,56 +431,76 @@ void unshadow_table(unsigned long gpfn, unsigned int type)
* guests there won't be a race here as this CPU was the one that
* cmpxchg'ed the page to invalid.
*/
- spfn = __shadow_status(&d->mm, gpfn) & PSH_pfn_mask;
- delete_shadow_status(&d->mm, gpfn);
- free_shadow_page(&d->mm, &frame_table[spfn]);
+ spfn = __shadow_status(d, gpfn) & PSH_pfn_mask;
+ delete_shadow_status(d, gpfn);
+ free_shadow_page(d, &frame_table[spfn]);
+}
+
+#ifdef CONFIG_VMX
+void vmx_shadow_clear_state(struct domain *d)
+{
+ SH_VVLOG("vmx_clear_shadow_state: \n");
+ clear_shadow_state(d);
}
+#endif
+
unsigned long shadow_l2_table(
- struct mm_struct *m, unsigned long gpfn)
+ struct domain *d, unsigned long gpfn)
{
struct pfn_info *spfn_info;
unsigned long spfn;
- l2_pgentry_t *spl2e;
+ l2_pgentry_t *spl2e = 0;
+ unsigned long guest_gpfn;
+
+ __get_machine_to_phys(d, guest_gpfn, gpfn);
SH_VVLOG("shadow_l2_table( %08lx )", gpfn);
perfc_incrc(shadow_l2_table_count);
- if ( (spfn_info = alloc_shadow_page(m)) == NULL )
+ if ( (spfn_info = alloc_shadow_page(d)) == NULL )
BUG(); /* XXX Deal gracefully with failure. */
spfn_info->u.inuse.type_info = PGT_l2_page_table;
perfc_incr(shadow_l2_pages);
spfn = spfn_info - frame_table;
-
- /* Mark pfn as being shadowed; update field to point at shadow. */
- set_shadow_status(m, gpfn, spfn | PSH_shadowed);
+ /* Mark pfn as being shadowed; update field to point at shadow. */
+ set_shadow_status(d, guest_gpfn, spfn | PSH_shadowed);
- spl2e = (l2_pgentry_t *)map_domain_mem(spfn << PAGE_SHIFT);
-
- /*
- * We could proactively fill in PDEs for pages that are already shadowed.
- * However, we tried it and it didn't help performance. This is simpler.
- */
- memset(spl2e, 0, DOMAIN_ENTRIES_PER_L2_PAGETABLE * sizeof(l2_pgentry_t));
-
#ifdef __i386__
/* Install hypervisor and 2x linear p.t. mapings. */
- memcpy(&spl2e[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
- &idle_pg_table[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
- HYPERVISOR_ENTRIES_PER_L2_PAGETABLE * sizeof(l2_pgentry_t));
- spl2e[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry((gpfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
- spl2e[SH_LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry((spfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
- spl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry(__pa(frame_table[gpfn].u.inuse.domain->mm.perdomain_pt) |
- __PAGE_HYPERVISOR);
+ if ( d->arch.shadow_mode == SHM_full_32 )
+ {
+ vmx_update_shadow_state(d->exec_domain[0], gpfn, spfn);
+ }
+ else
+ {
+ spl2e = (l2_pgentry_t *)map_domain_mem(spfn << PAGE_SHIFT);
+ /*
+ * We could proactively fill in PDEs for pages that are already
+ * shadowed. However, we tried it and it didn't help performance.
+ * This is simpler.
+ */
+ memset(spl2e, 0, DOMAIN_ENTRIES_PER_L2_PAGETABLE*sizeof(l2_pgentry_t));
+
+ /* Install hypervisor and 2x linear p.t. mapings. */
+ memcpy(&spl2e[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
+ &idle_pg_table[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
+ HYPERVISOR_ENTRIES_PER_L2_PAGETABLE * sizeof(l2_pgentry_t));
+ spl2e[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
+ mk_l2_pgentry((gpfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
+ spl2e[SH_LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
+ mk_l2_pgentry((spfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
+ spl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
+ mk_l2_pgentry(__pa(page_get_owner(&frame_table[gpfn])->arch.mm_perdomain_pt) |
+ __PAGE_HYPERVISOR);
+ }
#endif
- unmap_domain_mem(spl2e);
+ if ( d->arch.shadow_mode != SHM_full_32 )
+ unmap_domain_mem(spl2e);
SH_VLOG("shadow_l2_table( %08lx -> %08lx)", gpfn, spfn);
return spfn;
@@ -485,22 +508,23 @@ unsigned long shadow_l2_table(
static void shadow_map_l1_into_current_l2(unsigned long va)
{
- struct mm_struct *m = &current->mm;
- unsigned long *gpl1e, *spl1e, gpde, spde, gl1pfn, sl1pfn, sl1ss;
+ struct exec_domain *ed = current;
+ struct domain *d = ed->domain;
+ unsigned long *gpl1e, *spl1e, gpl2e, spl2e, gl1pfn, sl1pfn=0, sl1ss;
struct pfn_info *sl1pfn_info;
int i;
- gpde = l2_pgentry_val(linear_l2_table[va >> L2_PAGETABLE_SHIFT]);
+ __guest_get_pl2e(ed, va, &gpl2e);
- gl1pfn = gpde >> PAGE_SHIFT;
+ gl1pfn = gpl2e >> PAGE_SHIFT;
- sl1ss = __shadow_status(m, gl1pfn);
+ sl1ss = __shadow_status(d, gl1pfn);
if ( !(sl1ss & PSH_shadowed) )
{
/* This L1 is NOT already shadowed so we need to shadow it. */
SH_VVLOG("4a: l1 not shadowed ( %08lx )", sl1pfn);
- sl1pfn_info = alloc_shadow_page(m);
+ sl1pfn_info = alloc_shadow_page(d);
sl1pfn_info->u.inuse.type_info = PGT_l1_page_table;
sl1pfn = sl1pfn_info - frame_table;
@@ -508,13 +532,12 @@ static void shadow_map_l1_into_current_l2(unsigned long va)
perfc_incrc(shadow_l1_table_count);
perfc_incr(shadow_l1_pages);
- set_shadow_status(m, gl1pfn, PSH_shadowed | sl1pfn);
+ set_shadow_status(d, gl1pfn, PSH_shadowed | sl1pfn);
- l2pde_general(m, &gpde, &spde, sl1pfn);
+ l2pde_general(d, &gpl2e, &spl2e, sl1pfn);
- linear_l2_table[va>>L2_PAGETABLE_SHIFT] = mk_l2_pgentry(gpde);
- shadow_linear_l2_table[va>>L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry(spde);
+ __guest_set_pl2e(ed, va, gpl2e);
+ __shadow_set_pl2e(ed, va, spl2e);
gpl1e = (unsigned long *) &(linear_pg_table[
(va>>L1_PAGETABLE_SHIFT) & ~(ENTRIES_PER_L1_PAGETABLE-1)]);
@@ -523,7 +546,7 @@ static void shadow_map_l1_into_current_l2(unsigned long va)
(va>>L1_PAGETABLE_SHIFT) & ~(ENTRIES_PER_L1_PAGETABLE-1)]);
for ( i = 0; i < ENTRIES_PER_L1_PAGETABLE; i++ )
- l1pte_propagate_from_guest(m, &gpl1e[i], &spl1e[i]);
+ l1pte_propagate_from_guest(d, &gpl1e[i], &spl1e[i]);
}
else
{
@@ -531,21 +554,47 @@ static void shadow_map_l1_into_current_l2(unsigned long va)
SH_VVLOG("4b: was shadowed, l2 missing ( %08lx )", sl1pfn);
sl1pfn = sl1ss & PSH_pfn_mask;
- l2pde_general(m, &gpde, &spde, sl1pfn);
-
- linear_l2_table[va >> L2_PAGETABLE_SHIFT] = mk_l2_pgentry(gpde);
- shadow_linear_l2_table[va >> L2_PAGETABLE_SHIFT] = mk_l2_pgentry(spde);
+ l2pde_general(d, &gpl2e, &spl2e, sl1pfn);
+ __guest_set_pl2e(ed, va, gpl2e);
+ __shadow_set_pl2e(ed, va, spl2e);
}
}
+#ifdef CONFIG_VMX
+void vmx_shadow_invlpg(struct domain *d, unsigned long va)
+{
+ unsigned long gpte, spte, host_pfn;
+
+ if (__put_user(0L, (unsigned long *)
+ &shadow_linear_pg_table[va >> PAGE_SHIFT])) {
+ vmx_shadow_clear_state(d);
+ return;
+ }
+
+ if (__get_user(gpte, (unsigned long *)
+ &linear_pg_table[va >> PAGE_SHIFT])) {
+ return;
+ }
+
+ host_pfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT];
+ spte = (host_pfn << PAGE_SHIFT) | (gpte & ~PAGE_MASK);
+
+ if (__put_user(spte, (unsigned long *)
+ &shadow_linear_pg_table[va >> PAGE_SHIFT])) {
+ return;
+ }
+}
+#endif
+
int shadow_fault(unsigned long va, long error_code)
{
unsigned long gpte, spte;
- struct mm_struct *m = &current->mm;
+ struct exec_domain *ed = current;
+ struct domain *d = ed->domain;
SH_VVLOG("shadow_fault( va=%08lx, code=%ld )", va, error_code );
- check_pagetable(m, current->mm.pagetable, "pre-sf");
+ check_pagetable(d, ed->arch.pagetable, "pre-sf");
/*
* STEP 1. A fast-reject set of checks with no locking.
@@ -574,20 +623,20 @@ int shadow_fault(unsigned long va, long error_code)
* STEP 2. Take the shadow lock and re-check the guest PTE.
*/
- shadow_lock(m);
+ shadow_lock(d);
if ( unlikely(__get_user(gpte, (unsigned long *)
&linear_pg_table[va >> PAGE_SHIFT])) )
{
SH_VVLOG("shadow_fault - EXIT: read gpte faulted" );
- shadow_unlock(m);
+ shadow_unlock(d);
return 0;
}
if ( unlikely(!(gpte & _PAGE_PRESENT)) )
{
SH_VVLOG("shadow_fault - EXIT: gpte not present (%lx)",gpte );
- shadow_unlock(m);
+ shadow_unlock(d);
return 0;
}
@@ -598,15 +647,15 @@ int shadow_fault(unsigned long va, long error_code)
{
/* Write fault on a read-only mapping. */
SH_VVLOG("shadow_fault - EXIT: wr fault on RO page (%lx)", gpte);
- shadow_unlock(m);
+ shadow_unlock(d);
return 0;
}
- l1pte_write_fault(m, &gpte, &spte);
+ l1pte_write_fault(d, &gpte, &spte);
}
else
{
- l1pte_read_fault(m, &gpte, &spte);
+ l1pte_read_fault(d, &gpte, &spte);
}
/*
@@ -631,11 +680,11 @@ int shadow_fault(unsigned long va, long error_code)
}
perfc_incrc(shadow_fixup_count);
- m->shadow_fault_count++;
+ d->arch.shadow_fault_count++;
- shadow_unlock(m);
+ shadow_unlock(d);
- check_pagetable(m, current->mm.pagetable, "post-sf");
+ check_pagetable(d, ed->arch.pagetable, "post-sf");
return EXCRET_fault_fixed;
}
@@ -653,7 +702,7 @@ void shadow_l1_normal_pt_update(
"prev_spfn=%08lx, prev_spl1e=%p\n",
pa, gpte, prev_spfn, prev_spl1e);
- spfn = __shadow_status(&current->mm, pa >> PAGE_SHIFT) & PSH_pfn_mask;
+ spfn = __shadow_status(current->domain, pa >> PAGE_SHIFT) & PSH_pfn_mask;
if ( spfn == prev_spfn )
{
@@ -668,7 +717,7 @@ void shadow_l1_normal_pt_update(
*prev_spl1e_ptr = spl1e;
}
- l1pte_propagate_from_guest(&current->mm, &gpte, &spte);
+ l1pte_propagate_from_guest(current->domain, &gpte, &spte);
spl1e[(pa & ~PAGE_MASK) / sizeof(l1_pgentry_t)] = mk_l1_pgentry(spte);
}
@@ -681,13 +730,13 @@ void shadow_l2_normal_pt_update(unsigned long pa, unsigned long gpte)
/* N.B. To get here, we know the l2 page *must* be shadowed. */
SH_VVLOG("shadow_l2_normal_pt_update pa=%08lx, gpte=%08lx",pa,gpte);
- spfn = __shadow_status(&current->mm, pa >> PAGE_SHIFT) & PSH_pfn_mask;
+ spfn = __shadow_status(current->domain, pa >> PAGE_SHIFT) & PSH_pfn_mask;
s_sh = (gpte & _PAGE_PRESENT) ?
- __shadow_status(&current->mm, gpte >> PAGE_SHIFT) : 0;
+ __shadow_status(current->domain, gpte >> PAGE_SHIFT) : 0;
/* XXXX Should mark guest pte as DIRTY and ACCESSED too! */
- l2pde_general(&current->mm, &gpte, &spte, s_sh);
+ l2pde_general(current->domain, &gpte, &spte, s_sh);
spl2e = (l2_pgentry_t *)map_domain_mem(spfn << PAGE_SHIFT);
spl2e[(pa & ~PAGE_MASK) / sizeof(l2_pgentry_t)] = mk_l2_pgentry(spte);
unmap_domain_mem(spl2e);
@@ -714,10 +763,11 @@ char * sh_check_name;
} while ( 0 )
static int check_pte(
- struct mm_struct *m, unsigned long gpte, unsigned long spte,
+ struct domain *d, unsigned long gpte, unsigned long spte,
int level, int i)
{
unsigned long mask, gpfn, spfn;
+ unsigned long guest_gpfn;
if ( (spte == 0) || (spte == 0xdeadface) || (spte == 0x00000E00) )
return 1; /* always safe */
@@ -761,8 +811,20 @@ static int check_pte(
if ( level < 2 )
FAIL("Shadow in L1 entry?");
- if ( __shadow_status(m, gpfn) != (PSH_shadowed | spfn) )
- FAIL("spfn problem g.sf=%08lx", __shadow_status(m, gpfn));
+ if (d->arch.shadow_mode == SHM_full_32) {
+
+ guest_gpfn = phys_to_machine_mapping[gpfn];
+
+ if ( __shadow_status(d, guest_gpfn) != (PSH_shadowed | spfn) )
+ FAIL("spfn problem g.sf=%08lx",
+ __shadow_status(d, guest_gpfn) );
+
+ } else {
+ if ( __shadow_status(d, gpfn) != (PSH_shadowed | spfn) )
+ FAIL("spfn problem g.sf=%08lx",
+ __shadow_status(d, gpfn) );
+ }
+
}
return 1;
@@ -770,7 +832,7 @@ static int check_pte(
static int check_l1_table(
- struct mm_struct *m, unsigned long va,
+ struct domain *d, unsigned long va,
unsigned long g2, unsigned long s2)
{
int i;
@@ -780,7 +842,7 @@ static int check_l1_table(
spl1e = map_domain_mem(s2 << PAGE_SHIFT);
for ( i = 0; i < ENTRIES_PER_L1_PAGETABLE; i++ )
- check_pte(m, gpl1e[i], spl1e[i], 1, i);
+ check_pte(d, gpl1e[i], spl1e[i], 1, i);
unmap_domain_mem(spl1e);
unmap_domain_mem(gpl1e);
@@ -794,12 +856,13 @@ static int check_l1_table(
BUG(); \
} while ( 0 )
-int check_pagetable(struct mm_struct *m, pagetable_t pt, char *s)
+int check_pagetable(struct domain *d, pagetable_t pt, char *s)
{
unsigned long gptbase = pagetable_val(pt);
unsigned long gpfn, spfn;
- int i;
+ unsigned long i;
l2_pgentry_t *gpl2e, *spl2e;
+ unsigned long host_gpfn = 0;
sh_check_name = s;
@@ -809,20 +872,29 @@ int check_pagetable(struct mm_struct *m, pagetable_t pt, char *s)
gpfn = gptbase >> PAGE_SHIFT;
- if ( !(__shadow_status(m, gpfn) & PSH_shadowed) )
+ __get_phys_to_machine(d, host_gpfn, gpfn);
+
+ if ( ! (__shadow_status(d, gpfn) & PSH_shadowed) )
{
printk("%s-PT %08lx not shadowed\n", s, gptbase);
- if ( __shadow_status(m, gpfn) != 0 )
- BUG();
- return 0;
- }
+
+ if( __shadow_status(d, gpfn) != 0 ) BUG();
+ return 0;
+ }
- spfn = __shadow_status(m, gpfn) & PSH_pfn_mask;
+ spfn = __shadow_status(d, gpfn) & PSH_pfn_mask;
- if ( __shadow_status(m, gpfn) != (PSH_shadowed | spfn) )
- FAILPT("ptbase shadow inconsistent1");
+ if ( ! __shadow_status(d, gpfn) == (PSH_shadowed | spfn) )
+ FAILPT("ptbase shadow inconsistent1");
+
+ if (d->arch.shadow_mode == SHM_full_32)
+ {
+ host_gpfn = phys_to_machine_mapping[gpfn];
+ gpl2e = (l2_pgentry_t *) map_domain_mem( host_gpfn << PAGE_SHIFT );
+
+ } else
+ gpl2e = (l2_pgentry_t *) map_domain_mem( gpfn << PAGE_SHIFT );
- gpl2e = (l2_pgentry_t *) map_domain_mem( gpfn << PAGE_SHIFT );
spl2e = (l2_pgentry_t *) map_domain_mem( spfn << PAGE_SHIFT );
if ( memcmp(&spl2e[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
@@ -830,7 +902,6 @@ int check_pagetable(struct mm_struct *m, pagetable_t pt, char *s)
((SH_LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT) -
DOMAIN_ENTRIES_PER_L2_PAGETABLE) * sizeof(l2_pgentry_t)) )
{
- printk("gpfn=%08lx spfn=%08lx\n", gpfn, spfn);
for ( i = DOMAIN_ENTRIES_PER_L2_PAGETABLE;
i < (SH_LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT);
i++ )
@@ -851,22 +922,23 @@ int check_pagetable(struct mm_struct *m, pagetable_t pt, char *s)
L2_PAGETABLE_SHIFT]),
(spfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
- if ( (l2_pgentry_val(spl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT]) !=
- ((__pa(frame_table[gpfn].u.inuse.domain->mm.perdomain_pt) |
+ if (d->arch.shadow_mode != SHM_full_32) {
+ if ( (l2_pgentry_val(spl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT]) !=
+ ((__pa(page_get_owner(&frame_table[gpfn])->arch.mm_perdomain_pt) |
__PAGE_HYPERVISOR))) )
- FAILPT("hypervisor per-domain map inconsistent");
-
+ FAILPT("hypervisor per-domain map inconsistent");
+ }
/* Check the whole L2. */
for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
- check_pte(m, l2_pgentry_val(gpl2e[i]), l2_pgentry_val(spl2e[i]), 2, i);
+ check_pte(d, l2_pgentry_val(gpl2e[i]), l2_pgentry_val(spl2e[i]), 2, i);
/* Go back and recurse. */
for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
{
if ( l2_pgentry_val(spl2e[i]) != 0 )
check_l1_table(
- m, i << L2_PAGETABLE_SHIFT,
+ d, i << L2_PAGETABLE_SHIFT,
l2_pgentry_val(gpl2e[i]) >> PAGE_SHIFT,
l2_pgentry_val(spl2e[i]) >> PAGE_SHIFT);
}
diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c
index 991b5c577a..fcf7d64646 100644
--- a/xen/arch/x86/smpboot.c
+++ b/xen/arch/x86/smpboot.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/*
* x86 SMP booting functions
*
@@ -409,9 +410,9 @@ void __init start_secondary(void)
* At this point, boot CPU has fully initialised the IDT. It is
* now safe to make ourselves a private copy.
*/
- idt_tables[cpu] = xmalloc(IDT_ENTRIES*8);
- memcpy(idt_tables[cpu], idt_table, IDT_ENTRIES*8);
- *(unsigned short *)(&idt_load[0]) = (IDT_ENTRIES*8)-1;
+ idt_tables[cpu] = xmalloc_array(idt_entry_t, IDT_ENTRIES);
+ memcpy(idt_tables[cpu], idt_table, IDT_ENTRIES*sizeof(idt_entry_t));
+ *(unsigned short *)(&idt_load[0]) = (IDT_ENTRIES*sizeof(idt_entry_t))-1;
*(unsigned long *)(&idt_load[2]) = (unsigned long)idt_tables[cpu];
__asm__ __volatile__ ( "lidt %0" : "=m" (idt_load) );
@@ -647,22 +648,26 @@ static void __init do_boot_cpu (int apicid)
*/
{
struct domain *idle;
+ struct exec_domain *ed;
unsigned long boot_error = 0;
int timeout, cpu;
- unsigned long start_eip, stack;
+ unsigned long start_eip;
+ void *stack;
cpu = ++cpucount;
if ( (idle = do_createdomain(IDLE_DOMAIN_ID, cpu)) == NULL )
panic("failed 'createdomain' for CPU %d", cpu);
- set_bit(DF_IDLETASK, &idle->flags);
+ ed = idle->exec_domain[0];
- idle->mm.pagetable = mk_pagetable(__pa(idle_pg_table));
+ set_bit(DF_IDLETASK, &idle->d_flags);
+
+ ed->arch.pagetable = mk_pagetable(__pa(idle_pg_table));
map_cpu_to_boot_apicid(cpu, apicid);
- idle_task[cpu] = idle;
+ idle_task[cpu] = ed;
/* start_eip had better be page-aligned! */
start_eip = setup_trampoline();
@@ -670,11 +675,15 @@ static void __init do_boot_cpu (int apicid)
/* So we see what's up. */
printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip);
- stack = __pa(alloc_xenheap_pages(1));
- stack_start.esp = stack + STACK_SIZE - STACK_RESERVED;
+ stack = (void *)alloc_xenheap_pages(STACK_ORDER);
+#if defined(__i386__)
+ stack_start.esp = __pa(stack) + STACK_SIZE - STACK_RESERVED;
+#elif defined(__x86_64__)
+ stack_start.esp = (unsigned long)stack + STACK_SIZE - STACK_RESERVED;
+#endif
/* Debug build: detect stack overflow by setting up a guard page. */
- memguard_guard_range(__va(stack), PAGE_SIZE);
+ memguard_guard_stack(stack);
/*
* This grunge runs the startup process for
@@ -736,7 +745,7 @@ static void __init do_boot_cpu (int apicid)
printk("CPU%d has booted.\n", cpu);
} else {
boot_error= 1;
- if (*((volatile unsigned long *)phys_to_virt(start_eip))
+ if (*((volatile unsigned int *)phys_to_virt(start_eip))
== 0xA5A5A5A5)
/* trampoline started but...? */
printk("Stuck ??\n");
diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index be9f477ba5..ebc772dee6 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -1,4 +1,4 @@
-/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*-
****************************************************************************
* (C) 2002-2003 - Rolf Neugebauer - Intel Research Cambridge
* (C) 2002-2003 University of Cambridge
@@ -50,7 +50,7 @@ static s_time_t stime_irq; /* System time at last 'time update' */
static unsigned long wc_sec, wc_usec; /* UTC time at last 'time update'. */
static rwlock_t time_lock = RW_LOCK_UNLOCKED;
-static void timer_interrupt(int irq, void *dev_id, struct xen_regs *regs)
+void timer_interrupt(int irq, void *dev_id, struct xen_regs *regs)
{
write_lock_irq(&time_lock);
@@ -274,12 +274,15 @@ s_time_t get_s_time(void)
}
-void update_dom_time(shared_info_t *si)
+void update_dom_time(struct domain *d)
{
+ shared_info_t *si = d->shared_info;
unsigned long flags;
read_lock_irqsave(&time_lock, flags);
+ spin_lock(&d->time_lock);
+
si->time_version1++;
wmb();
@@ -292,6 +295,8 @@ void update_dom_time(shared_info_t *si)
wmb();
si->time_version2++;
+ spin_unlock(&d->time_lock);
+
read_unlock_irqrestore(&time_lock, flags);
}
@@ -318,7 +323,7 @@ void do_settime(unsigned long secs, unsigned long usecs, u64 system_time_base)
write_unlock_irq(&time_lock);
- update_dom_time(current->shared_info);
+ update_dom_time(current->domain);
}
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 8e965c5f60..9cd16fdb27 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -1,5 +1,6 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
- * arch/i386/traps.c
+ * arch/x86/traps.c
*
* Modifications to Linux original are copyright (c) 2002-2004, K A Fraser
*
@@ -51,6 +52,7 @@
#include <asm/uaccess.h>
#include <asm/i387.h>
#include <asm/debugger.h>
+#include <asm/msr.h>
/*
* opt_nmi: one of 'ignore', 'dom0', or 'fatal'.
@@ -65,20 +67,12 @@ char opt_nmi[10] = "fatal";
#endif
string_param("nmi", opt_nmi);
-#if defined(__i386__)
-
-#define GUEST_FAULT(_r) (likely(VM86_MODE(_r) || !RING_0(_r)))
-
-#define DOUBLEFAULT_STACK_SIZE 1024
-static struct tss_struct doublefault_tss;
-static unsigned char doublefault_stack[DOUBLEFAULT_STACK_SIZE];
-
asmlinkage int hypercall(void);
/* Master table, and the one used by CPU0. */
-struct desc_struct idt_table[256] = { {0, 0}, };
+idt_entry_t idt_table[IDT_ENTRIES] = { {0, 0}, };
/* All other CPUs have their own copy. */
-struct desc_struct *idt_tables[NR_CPUS] = { 0 };
+idt_entry_t *idt_tables[NR_CPUS] = { 0 };
asmlinkage void divide_error(void);
asmlinkage void debug(void);
@@ -100,116 +94,6 @@ asmlinkage void alignment_check(void);
asmlinkage void spurious_interrupt_bug(void);
asmlinkage void machine_check(void);
-int kstack_depth_to_print = 8*20;
-
-static inline int kernel_text_address(unsigned long addr)
-{
- if (addr >= (unsigned long) &_stext &&
- addr <= (unsigned long) &_etext)
- return 1;
- return 0;
-
-}
-
-void show_guest_stack()
-{
- int i;
- execution_context_t *ec = get_execution_context();
- unsigned long *stack = (unsigned long *)ec->esp;
- printk("Guest EIP is %lx\n",ec->eip);
-
- for ( i = 0; i < kstack_depth_to_print; i++ )
- {
- if ( ((long)stack & (STACK_SIZE-1)) == 0 )
- break;
- if ( i && ((i % 8) == 0) )
- printk("\n ");
- printk("%08lx ", *stack++);
- }
- printk("\n");
-
-}
-
-void show_trace(unsigned long *esp)
-{
- unsigned long *stack, addr;
- int i;
-
- printk("Call Trace from ESP=%p: ", esp);
- stack = esp;
- i = 0;
- while (((long) stack & (STACK_SIZE-1)) != 0) {
- addr = *stack++;
- if (kernel_text_address(addr)) {
- if (i && ((i % 6) == 0))
- printk("\n ");
- printk("[<%08lx>] ", addr);
- i++;
- }
- }
- printk("\n");
-}
-
-void show_stack(unsigned long *esp)
-{
- unsigned long *stack;
- int i;
-
- printk("Stack trace from ESP=%p:\n", esp);
-
- stack = esp;
- for ( i = 0; i < kstack_depth_to_print; i++ )
- {
- if ( ((long)stack & (STACK_SIZE-1)) == 0 )
- break;
- if ( i && ((i % 8) == 0) )
- printk("\n ");
- if ( kernel_text_address(*stack) )
- printk("[%08lx] ", *stack++);
- else
- printk("%08lx ", *stack++);
- }
- printk("\n");
-
- show_trace( esp );
-}
-
-void show_registers(struct xen_regs *regs)
-{
- unsigned long esp;
- unsigned short ss, ds, es, fs, gs;
-
- if ( GUEST_FAULT(regs) )
- {
- esp = regs->esp;
- ss = regs->ss & 0xffff;
- ds = regs->ds & 0xffff;
- es = regs->es & 0xffff;
- fs = regs->fs & 0xffff;
- gs = regs->gs & 0xffff;
- }
- else
- {
- esp = (unsigned long)(&regs->esp);
- ss = __HYPERVISOR_DS;
- ds = __HYPERVISOR_DS;
- es = __HYPERVISOR_DS;
- fs = __HYPERVISOR_DS;
- gs = __HYPERVISOR_DS;
- }
-
- printk("CPU: %d\nEIP: %04x:[<%08x>] \nEFLAGS: %08x\n",
- smp_processor_id(), 0xffff & regs->cs, regs->eip, regs->eflags);
- printk("eax: %08x ebx: %08x ecx: %08x edx: %08x\n",
- regs->eax, regs->ebx, regs->ecx, regs->edx);
- printk("esi: %08x edi: %08x ebp: %08x esp: %08lx\n",
- regs->esi, regs->edi, regs->ebp, esp);
- printk("ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n",
- ds, es, fs, gs, ss);
-
- show_stack((unsigned long *)&regs->esp);
-}
-
/*
* This is called for faults at very unexpected times (e.g., when interrupts
* are disabled). In such situations we can't do much that is safe. We try to
@@ -232,8 +116,8 @@ asmlinkage void fatal_trap(int trapnr, struct xen_regs *regs)
if ( trapnr == TRAP_page_fault )
{
- __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (cr2) : );
- printk("Faulting linear address might be %08lx\n", cr2);
+ __asm__ __volatile__ ("mov %%cr2,%0" : "=r" (cr2) : );
+ printk("Faulting linear address might be %0lx %lx\n", cr2, cr2);
}
printk("************************************\n");
@@ -255,8 +139,8 @@ static inline int do_trap(int trapnr, char *str,
struct xen_regs *regs,
int use_error_code)
{
- struct domain *d = current;
- struct trap_bounce *tb = &d->thread.trap_bounce;
+ struct exec_domain *ed = current;
+ struct trap_bounce *tb = &ed->arch.trap_bounce;
trap_info_t *ti;
unsigned long fixup;
@@ -265,7 +149,7 @@ static inline int do_trap(int trapnr, char *str,
if ( !GUEST_FAULT(regs) )
goto xen_fault;
- ti = current->thread.traps + trapnr;
+ ti = current->arch.traps + trapnr;
tb->flags = TBF_EXCEPTION;
tb->cs = ti->cs;
tb->eip = ti->address;
@@ -275,14 +159,14 @@ static inline int do_trap(int trapnr, char *str,
tb->error_code = regs->error_code;
}
if ( TI_GET_IF(ti) )
- d->shared_info->vcpu_data[0].evtchn_upcall_mask = 1;
+ ed->vcpu_info->evtchn_upcall_mask = 1;
return 0;
xen_fault:
if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
{
- DPRINTK("Trap %d: %08x -> %08lx\n", trapnr, regs->eip, fixup);
+ DPRINTK("Trap %d: %p -> %p\n", trapnr, regs->eip, fixup);
regs->eip = fixup;
return 0;
}
@@ -322,8 +206,8 @@ DO_ERROR_NOCODE(19, "simd error", simd_coprocessor_error)
asmlinkage int do_int3(struct xen_regs *regs)
{
- struct domain *d = current;
- struct trap_bounce *tb = &d->thread.trap_bounce;
+ struct exec_domain *ed = current;
+ struct trap_bounce *tb = &ed->arch.trap_bounce;
trap_info_t *ti;
DEBUGGER_trap_entry(TRAP_int3, regs);
@@ -335,48 +219,16 @@ asmlinkage int do_int3(struct xen_regs *regs)
panic("CPU%d FATAL TRAP: vector = 3 (Int3)\n", smp_processor_id());
}
- ti = current->thread.traps + 3;
+ ti = current->arch.traps + 3;
tb->flags = TBF_EXCEPTION;
tb->cs = ti->cs;
tb->eip = ti->address;
if ( TI_GET_IF(ti) )
- d->shared_info->vcpu_data[0].evtchn_upcall_mask = 1;
+ ed->vcpu_info->evtchn_upcall_mask = 1;
return 0;
}
-asmlinkage void do_double_fault(void)
-{
- struct tss_struct *tss = &doublefault_tss;
- unsigned int cpu = ((tss->back_link>>3)-__FIRST_TSS_ENTRY)>>1;
-
- /* Disable the NMI watchdog. It's useless now. */
- watchdog_on = 0;
-
- /* Find information saved during fault and dump it to the console. */
- tss = &init_tss[cpu];
- printk("CPU: %d\nEIP: %04x:[<%08x>] \nEFLAGS: %08x\n",
- cpu, tss->cs, tss->eip, tss->eflags);
- printk("CR3: %08x\n", tss->__cr3);
- printk("eax: %08x ebx: %08x ecx: %08x edx: %08x\n",
- tss->eax, tss->ebx, tss->ecx, tss->edx);
- printk("esi: %08x edi: %08x ebp: %08x esp: %08x\n",
- tss->esi, tss->edi, tss->ebp, tss->esp);
- printk("ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n",
- tss->ds, tss->es, tss->fs, tss->gs, tss->ss);
- printk("************************************\n");
- printk("CPU%d DOUBLE FAULT -- system shutdown\n", cpu);
- printk("System needs manual reset.\n");
- printk("************************************\n");
-
- /* Lock up the console to prevent spurious output from other CPUs. */
- console_force_lock();
-
- /* Wait for manual reset. */
- for ( ; ; )
- __asm__ __volatile__ ( "hlt" );
-}
-
asmlinkage void do_machine_check(struct xen_regs *regs)
{
fatal_trap(TRAP_machine_check, regs);
@@ -385,27 +237,31 @@ asmlinkage void do_machine_check(struct xen_regs *regs)
void propagate_page_fault(unsigned long addr, u16 error_code)
{
trap_info_t *ti;
- struct domain *d = current;
- struct trap_bounce *tb = &d->thread.trap_bounce;
+ struct exec_domain *ed = current;
+ struct trap_bounce *tb = &ed->arch.trap_bounce;
- ti = d->thread.traps + 14;
+ ti = ed->arch.traps + 14;
tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE | TBF_EXCEPTION_CR2;
tb->cr2 = addr;
tb->error_code = error_code;
tb->cs = ti->cs;
tb->eip = ti->address;
if ( TI_GET_IF(ti) )
- d->shared_info->vcpu_data[0].evtchn_upcall_mask = 1;
+ ed->vcpu_info->evtchn_upcall_mask = 1;
+
+ ed->arch.guest_cr2 = addr;
}
asmlinkage int do_page_fault(struct xen_regs *regs)
{
unsigned long off, addr, fixup;
- struct domain *d = current;
+ struct exec_domain *ed = current;
+ struct domain *d = ed->domain;
extern int map_ldt_shadow_page(unsigned int);
- int cpu = d->processor;
+ int cpu = ed->processor;
+ int ret;
- __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (addr) : );
+ __asm__ __volatile__ ("mov %%cr2,%0" : "=r" (addr) : );
DEBUGGER_trap_entry(TRAP_page_fault, regs);
@@ -413,11 +269,13 @@ asmlinkage int do_page_fault(struct xen_regs *regs)
if ( likely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables)) )
{
+ LOCK_BIGLOCK(d);
if ( unlikely(ptwr_info[cpu].ptinfo[PTWR_PT_ACTIVE].l1va) &&
unlikely((addr >> L2_PAGETABLE_SHIFT) ==
ptwr_info[cpu].ptinfo[PTWR_PT_ACTIVE].l2_idx) )
{
ptwr_flush(PTWR_PT_ACTIVE);
+ UNLOCK_BIGLOCK(d);
return EXCRET_fault_fixed;
}
@@ -425,26 +283,31 @@ asmlinkage int do_page_fault(struct xen_regs *regs)
((regs->error_code & 3) == 3) && /* write-protection fault */
ptwr_do_page_fault(addr) )
{
- if ( unlikely(d->mm.shadow_mode) )
+ if ( unlikely(d->arch.shadow_mode) )
(void)shadow_fault(addr, regs->error_code);
+ UNLOCK_BIGLOCK(d);
return EXCRET_fault_fixed;
}
+ UNLOCK_BIGLOCK(d);
}
- if ( unlikely(d->mm.shadow_mode) &&
+ if ( unlikely(d->arch.shadow_mode) &&
(addr < PAGE_OFFSET) && shadow_fault(addr, regs->error_code) )
return EXCRET_fault_fixed;
- if ( unlikely(addr >= LDT_VIRT_START) &&
- (addr < (LDT_VIRT_START + (d->mm.ldt_ents*LDT_ENTRY_SIZE))) )
+ if ( unlikely(addr >= LDT_VIRT_START(ed)) &&
+ (addr < (LDT_VIRT_START(ed) + (ed->arch.ldt_ents*LDT_ENTRY_SIZE))) )
{
/*
* Copy a mapping from the guest's LDT, if it is valid. Otherwise we
* send the fault up to the guest OS to be handled.
*/
- off = addr - LDT_VIRT_START;
- addr = d->mm.ldt_base + off;
- if ( likely(map_ldt_shadow_page(off >> PAGE_SHIFT)) )
+ LOCK_BIGLOCK(d);
+ off = addr - LDT_VIRT_START(ed);
+ addr = ed->arch.ldt_base + off;
+ ret = map_ldt_shadow_page(off >> PAGE_SHIFT);
+ UNLOCK_BIGLOCK(d);
+ if ( likely(ret) )
return EXCRET_fault_fixed; /* successfully copied the mapping */
}
@@ -459,48 +322,156 @@ asmlinkage int do_page_fault(struct xen_regs *regs)
if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
{
perfc_incrc(copy_user_faults);
- if ( !d->mm.shadow_mode )
- DPRINTK("Page fault: %08x -> %08lx\n", regs->eip, fixup);
+ if ( !d->arch.shadow_mode )
+ DPRINTK("Page fault: %p -> %p\n", regs->eip, fixup);
regs->eip = fixup;
return 0;
}
DEBUGGER_trap_fatal(TRAP_page_fault, regs);
- if ( addr >= PAGE_OFFSET )
+ show_registers(regs);
+ show_page_walk(addr);
+ panic("CPU%d FATAL PAGE FAULT\n"
+ "[error_code=%04x]\n"
+ "Faulting linear address might be %p\n",
+ smp_processor_id(), regs->error_code, addr);
+ return 0;
+}
+
+static int emulate_privileged_op(struct xen_regs *regs)
+{
+ extern long do_fpu_taskswitch(void);
+ extern void *decode_reg(struct xen_regs *regs, u8 b);
+
+ struct exec_domain *ed = current;
+ unsigned long *reg, eip = regs->eip;
+ u8 opcode;
+
+ if ( get_user(opcode, (u8 *)eip) )
+ goto page_fault;
+ eip += 1;
+ if ( (opcode & 0xff) != 0x0f )
+ goto fail;
+
+ if ( get_user(opcode, (u8 *)eip) )
+ goto page_fault;
+ eip += 1;
+
+ switch ( opcode )
{
- unsigned long page;
- page = l2_pgentry_val(idle_pg_table[addr >> L2_PAGETABLE_SHIFT]);
- printk("*pde = %08lx\n", page);
- if ( page & _PAGE_PRESENT )
+ case 0x06: /* CLTS */
+ (void)do_fpu_taskswitch();
+ break;
+
+ case 0x09: /* WBINVD */
+ if ( !IS_CAPABLE_PHYSDEV(ed->domain) )
{
- page &= PAGE_MASK;
- page = ((unsigned long *) __va(page))[(addr&0x3ff000)>>PAGE_SHIFT];
- printk(" *pte = %08lx\n", page);
+ DPRINTK("Non-physdev domain attempted WBINVD.\n");
+ goto fail;
}
-#ifdef MEMORY_GUARD
- if ( !(regs->error_code & 1) )
- printk(" -- POSSIBLY AN ACCESS TO FREED MEMORY? --\n");
-#endif
+ wbinvd();
+ break;
+
+ case 0x20: /* MOV CR?,<reg> */
+ if ( get_user(opcode, (u8 *)eip) )
+ goto page_fault;
+ eip += 1;
+ if ( (opcode & 0xc0) != 0xc0 )
+ goto fail;
+ reg = decode_reg(regs, opcode & 7);
+ switch ( (opcode >> 3) & 7 )
+ {
+ case 0: /* Read CR0 */
+ *reg =
+ (read_cr0() & ~X86_CR0_TS) |
+ (test_bit(EDF_GUEST_STTS, &ed->ed_flags) ? X86_CR0_TS : 0);
+ break;
+
+ case 2: /* Read CR2 */
+ *reg = ed->arch.guest_cr2;
+ break;
+
+ case 3: /* Read CR3 */
+ *reg = pagetable_val(ed->arch.pagetable);
+ break;
+
+ default:
+ goto fail;
+ }
+ break;
+
+ case 0x22: /* MOV <reg>,CR? */
+ if ( get_user(opcode, (u8 *)eip) )
+ goto page_fault;
+ eip += 1;
+ if ( (opcode & 0xc0) != 0xc0 )
+ goto fail;
+ reg = decode_reg(regs, opcode & 7);
+ switch ( (opcode >> 3) & 7 )
+ {
+ case 0: /* Write CR0 */
+ if ( *reg & X86_CR0_TS ) /* XXX ignore all but TS bit */
+ (void)do_fpu_taskswitch;
+ break;
+
+ case 2: /* Write CR2 */
+ ed->arch.guest_cr2 = *reg;
+ break;
+
+ case 3: /* Write CR3 */
+ LOCK_BIGLOCK(ed->domain);
+ (void)new_guest_cr3(*reg);
+ UNLOCK_BIGLOCK(ed->domain);
+ break;
+
+ default:
+ goto fail;
+ }
+ break;
+
+ case 0x30: /* WRMSR */
+ if ( !IS_PRIV(ed->domain) )
+ {
+ DPRINTK("Non-priv domain attempted WRMSR.\n");
+ goto fail;
+ }
+ wrmsr(regs->ecx, regs->eax, regs->edx);
+ break;
+
+ case 0x32: /* RDMSR */
+ if ( !IS_PRIV(ed->domain) )
+ {
+ DPRINTK("Non-priv domain attempted RDMSR.\n");
+ goto fail;
+ }
+ rdmsr(regs->ecx, regs->eax, regs->edx);
+ break;
+
+ default:
+ goto fail;
}
- show_registers(regs);
- panic("CPU%d FATAL PAGE FAULT\n"
- "[error_code=%04x]\n"
- "Faulting linear address might be %08lx\n",
- smp_processor_id(), regs->error_code, addr);
+ regs->eip = eip;
+ return EXCRET_fault_fixed;
+
+ fail:
return 0;
+
+ page_fault:
+ propagate_page_fault(eip, 0);
+ return EXCRET_fault_fixed;
}
asmlinkage int do_general_protection(struct xen_regs *regs)
{
- struct domain *d = current;
- struct trap_bounce *tb = &d->thread.trap_bounce;
+ struct exec_domain *ed = current;
+ struct trap_bounce *tb = &ed->arch.trap_bounce;
trap_info_t *ti;
unsigned long fixup;
DEBUGGER_trap_entry(TRAP_gp_fault, regs);
-
+
if ( regs->error_code & 1 )
goto hardware_gp;
@@ -530,7 +501,7 @@ asmlinkage int do_general_protection(struct xen_regs *regs)
if ( (regs->error_code & 3) == 2 )
{
/* This fault must be due to <INT n> instruction. */
- ti = current->thread.traps + (regs->error_code>>3);
+ ti = current->arch.traps + (regs->error_code>>3);
if ( TI_GET_DPL(ti) >= (VM86_MODE(regs) ? 3 : (regs->cs & 3)) )
{
tb->flags = TBF_EXCEPTION;
@@ -539,29 +510,35 @@ asmlinkage int do_general_protection(struct xen_regs *regs)
}
}
+ /* Emulate some simple privileged instructions when exec'ed in ring 1. */
+ if ( (regs->error_code == 0) &&
+ RING_1(regs) &&
+ emulate_privileged_op(regs) )
+ return 0;
+
#if defined(__i386__)
- if ( VM_ASSIST(d, VMASST_TYPE_4gb_segments) &&
+ if ( VM_ASSIST(ed->domain, VMASST_TYPE_4gb_segments) &&
(regs->error_code == 0) &&
gpf_emulate_4gb(regs) )
return 0;
#endif
/* Pass on GPF as is. */
- ti = current->thread.traps + 13;
+ ti = current->arch.traps + 13;
tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
tb->error_code = regs->error_code;
finish_propagation:
tb->cs = ti->cs;
tb->eip = ti->address;
if ( TI_GET_IF(ti) )
- d->shared_info->vcpu_data[0].evtchn_upcall_mask = 1;
+ ed->vcpu_info->evtchn_upcall_mask = 1;
return 0;
gp_in_kernel:
if ( likely((fixup = search_exception_table(regs->eip)) != 0) )
{
- DPRINTK("GPF (%04x): %08x -> %08lx\n",
+ DPRINTK("GPF (%04x): %p -> %p\n",
regs->error_code, regs->eip, fixup);
regs->eip = fixup;
return 0;
@@ -617,10 +594,10 @@ static void nmi_softirq(void)
return;
if ( test_and_clear_bit(0, &nmi_softirq_reason) )
- send_guest_virq(dom0, VIRQ_PARITY_ERR);
+ send_guest_virq(dom0->exec_domain[0], VIRQ_PARITY_ERR);
if ( test_and_clear_bit(1, &nmi_softirq_reason) )
- send_guest_virq(dom0, VIRQ_IO_ERR);
+ send_guest_virq(dom0->exec_domain[0], VIRQ_IO_ERR);
}
asmlinkage int math_state_restore(struct xen_regs *regs)
@@ -628,21 +605,21 @@ asmlinkage int math_state_restore(struct xen_regs *regs)
/* Prevent recursion. */
clts();
- if ( !test_bit(DF_USEDFPU, &current->flags) )
+ if ( !test_bit(EDF_USEDFPU, &current->ed_flags) )
{
- if ( test_bit(DF_DONEFPUINIT, &current->flags) )
+ if ( test_bit(EDF_DONEFPUINIT, &current->ed_flags) )
restore_fpu(current);
else
init_fpu();
- set_bit(DF_USEDFPU, &current->flags); /* so we fnsave on switch_to() */
+ set_bit(EDF_USEDFPU, &current->ed_flags); /* so we fnsave on switch_to() */
}
- if ( test_and_clear_bit(DF_GUEST_STTS, &current->flags) )
+ if ( test_and_clear_bit(EDF_GUEST_STTS, &current->ed_flags) )
{
- struct trap_bounce *tb = &current->thread.trap_bounce;
+ struct trap_bounce *tb = &current->arch.trap_bounce;
tb->flags = TBF_EXCEPTION;
- tb->cs = current->thread.traps[7].cs;
- tb->eip = current->thread.traps[7].address;
+ tb->cs = current->arch.traps[7].cs;
+ tb->eip = current->arch.traps[7].address;
}
return EXCRET_fault_fixed;
@@ -650,19 +627,19 @@ asmlinkage int math_state_restore(struct xen_regs *regs)
asmlinkage int do_debug(struct xen_regs *regs)
{
- unsigned int condition;
- struct domain *d = current;
- struct trap_bounce *tb = &d->thread.trap_bounce;
+ unsigned long condition;
+ struct exec_domain *d = current;
+ struct trap_bounce *tb = &d->arch.trap_bounce;
DEBUGGER_trap_entry(TRAP_debug, regs);
- __asm__ __volatile__("movl %%db6,%0" : "=r" (condition));
+ __asm__ __volatile__("mov %%db6,%0" : "=r" (condition));
/* Mask out spurious debug traps due to lazy DR7 setting */
if ( (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) &&
- (d->thread.debugreg[7] == 0) )
+ (d->arch.debugreg[7] == 0) )
{
- __asm__("movl %0,%%db7" : : "r" (0));
+ __asm__("mov %0,%%db7" : : "r" (0UL));
goto out;
}
@@ -680,11 +657,11 @@ asmlinkage int do_debug(struct xen_regs *regs)
}
/* Save debug status register where guest OS can peek at it */
- d->thread.debugreg[6] = condition;
+ d->arch.debugreg[6] = condition;
tb->flags = TBF_EXCEPTION;
- tb->cs = d->thread.traps[1].cs;
- tb->eip = d->thread.traps[1].address;
+ tb->cs = d->arch.traps[1].cs;
+ tb->eip = d->arch.traps[1].address;
out:
return EXCRET_not_a_fault;
@@ -702,85 +679,35 @@ asmlinkage void smp_deferred_nmi(struct xen_regs regs)
do_nmi(&regs, 0);
}
-#define _set_gate(gate_addr,type,dpl,addr) \
-do { \
- int __d0, __d1; \
- __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
- "movw %4,%%dx\n\t" \
- "movl %%eax,%0\n\t" \
- "movl %%edx,%1" \
- :"=m" (*((long *) (gate_addr))), \
- "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
- :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
- "3" ((char *) (addr)),"2" (__HYPERVISOR_CS << 16)); \
-} while (0)
-
void set_intr_gate(unsigned int n, void *addr)
{
_set_gate(idt_table+n,14,0,addr);
}
-static void __init set_system_gate(unsigned int n, void *addr)
+void set_system_gate(unsigned int n, void *addr)
{
_set_gate(idt_table+n,14,3,addr);
}
-static void set_task_gate(unsigned int n, unsigned int sel)
+void set_task_gate(unsigned int n, unsigned int sel)
{
idt_table[n].a = sel << 16;
idt_table[n].b = 0x8500;
}
-#define _set_seg_desc(gate_addr,type,dpl,base,limit) {\
- *((gate_addr)+1) = ((base) & 0xff000000) | \
- (((base) & 0x00ff0000)>>16) | \
- ((limit) & 0xf0000) | \
- ((dpl)<<13) | \
- (0x00408000) | \
- ((type)<<8); \
- *(gate_addr) = (((base) & 0x0000ffff)<<16) | \
- ((limit) & 0x0ffff); }
-
-#define _set_tssldt_desc(n,addr,limit,type) \
-__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
- "movw %%ax,2(%2)\n\t" \
- "rorl $16,%%eax\n\t" \
- "movb %%al,4(%2)\n\t" \
- "movb %4,5(%2)\n\t" \
- "movb $0,6(%2)\n\t" \
- "movb %%ah,7(%2)\n\t" \
- "rorl $16,%%eax" \
- : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type))
-
void set_tss_desc(unsigned int n, void *addr)
{
_set_tssldt_desc(
gdt_table + __TSS(n),
- (int)addr,
+ (unsigned long)addr,
offsetof(struct tss_struct, __cacheline_filler) - 1,
- 0x89);
+ 9);
}
void __init trap_init(void)
{
- /*
- * Make a separate task for double faults. This will get us debug output if
- * we blow the kernel stack.
- */
- struct tss_struct *tss = &doublefault_tss;
- memset(tss, 0, sizeof(*tss));
- tss->ds = __HYPERVISOR_DS;
- tss->es = __HYPERVISOR_DS;
- tss->ss = __HYPERVISOR_DS;
- tss->esp = (unsigned long)
- &doublefault_stack[DOUBLEFAULT_STACK_SIZE];
- tss->__cr3 = __pa(idle_pg_table);
- tss->cs = __HYPERVISOR_CS;
- tss->eip = (unsigned long)do_double_fault;
- tss->eflags = 2;
- tss->bitmap = IOBMP_INVALID_OFFSET;
- _set_tssldt_desc(gdt_table+__DOUBLEFAULT_TSS_ENTRY,
- (int)tss, 235, 0x89);
+ extern void doublefault_init(void);
+ doublefault_init();
/*
* Note that interrupt gates are always used, rather than trap gates. We
@@ -798,7 +725,6 @@ void __init trap_init(void)
set_intr_gate(TRAP_bounds,&bounds);
set_intr_gate(TRAP_invalid_op,&invalid_op);
set_intr_gate(TRAP_no_device,&device_not_available);
- set_task_gate(TRAP_double_fault,__DOUBLEFAULT_TSS_ENTRY<<3);
set_intr_gate(TRAP_copro_seg,&coprocessor_segment_overrun);
set_intr_gate(TRAP_invalid_tss,&invalid_TSS);
set_intr_gate(TRAP_no_segment,&segment_not_present);
@@ -812,8 +738,9 @@ void __init trap_init(void)
set_intr_gate(TRAP_simd_error,&simd_coprocessor_error);
set_intr_gate(TRAP_deferred_nmi,&deferred_nmi);
- /* Only ring 1 can access Xen services. */
- _set_gate(idt_table+HYPERCALL_VECTOR,14,1,&hypercall);
+#if defined(__i386__)
+ _set_gate(idt_table+HYPERCALL_VECTOR, 14, 1, &hypercall);
+#endif
/* CPU0 uses the master IDT. */
idt_tables[0] = idt_table;
@@ -833,13 +760,18 @@ void __init trap_init(void)
long do_set_trap_table(trap_info_t *traps)
{
trap_info_t cur;
- trap_info_t *dst = current->thread.traps;
+ trap_info_t *dst = current->arch.traps;
+
+ LOCK_BIGLOCK(current->domain);
for ( ; ; )
{
if ( hypercall_preempt_check() )
+ {
+ UNLOCK_BIGLOCK(current->domain);
return hypercall_create_continuation(
__HYPERVISOR_set_trap_table, 1, traps);
+ }
if ( copy_from_user(&cur, traps, sizeof(cur)) ) return -EFAULT;
@@ -851,6 +783,8 @@ long do_set_trap_table(trap_info_t *traps)
traps++;
}
+ UNLOCK_BIGLOCK(current->domain);
+
return 0;
}
@@ -860,80 +794,29 @@ long do_set_callbacks(unsigned long event_selector,
unsigned long failsafe_selector,
unsigned long failsafe_address)
{
- struct domain *d = current;
+ struct exec_domain *d = current;
if ( !VALID_CODESEL(event_selector) || !VALID_CODESEL(failsafe_selector) )
return -EPERM;
- d->thread.event_selector = event_selector;
- d->thread.event_address = event_address;
- d->thread.failsafe_selector = failsafe_selector;
- d->thread.failsafe_address = failsafe_address;
+ d->arch.event_selector = event_selector;
+ d->arch.event_address = event_address;
+ d->arch.failsafe_selector = failsafe_selector;
+ d->arch.failsafe_address = failsafe_address;
return 0;
}
-long set_fast_trap(struct domain *p, int idx)
-{
- trap_info_t *ti;
-
- /* Index 0 is special: it disables fast traps. */
- if ( idx == 0 )
- {
- if ( p == current )
- CLEAR_FAST_TRAP(&p->thread);
- SET_DEFAULT_FAST_TRAP(&p->thread);
- return 0;
- }
-
- /*
- * We only fast-trap vectors 0x20-0x2f, and vector 0x80.
- * The former range is used by Windows and MS-DOS.
- * Vector 0x80 is used by Linux and the BSD variants.
- */
- if ( (idx != 0x80) && ((idx < 0x20) || (idx > 0x2f)) )
- return -1;
-
- ti = p->thread.traps + idx;
-
- /*
- * We can't virtualise interrupt gates, as there's no way to get
- * the CPU to automatically clear the events_mask variable.
- */
- if ( TI_GET_IF(ti) )
- return -1;
-
- if ( p == current )
- CLEAR_FAST_TRAP(&p->thread);
-
- p->thread.fast_trap_idx = idx;
- p->thread.fast_trap_desc.a = (ti->cs << 16) | (ti->address & 0xffff);
- p->thread.fast_trap_desc.b =
- (ti->address & 0xffff0000) | 0x8f00 | (TI_GET_DPL(ti)&3)<<13;
-
- if ( p == current )
- SET_FAST_TRAP(&p->thread);
-
- return 0;
-}
-
-
-long do_set_fast_trap(int idx)
-{
- return set_fast_trap(current, idx);
-}
-
-
long do_fpu_taskswitch(void)
{
- set_bit(DF_GUEST_STTS, &current->flags);
+ set_bit(EDF_GUEST_STTS, &current->ed_flags);
stts();
return 0;
}
-long set_debugreg(struct domain *p, int reg, unsigned long value)
+long set_debugreg(struct exec_domain *p, int reg, unsigned long value)
{
int i;
@@ -942,22 +825,22 @@ long set_debugreg(struct domain *p, int reg, unsigned long value)
case 0:
if ( value > (PAGE_OFFSET-4) ) return -EPERM;
if ( p == current )
- __asm__ ( "movl %0, %%db0" : : "r" (value) );
+ __asm__ ( "mov %0, %%db0" : : "r" (value) );
break;
case 1:
if ( value > (PAGE_OFFSET-4) ) return -EPERM;
if ( p == current )
- __asm__ ( "movl %0, %%db1" : : "r" (value) );
+ __asm__ ( "mov %0, %%db1" : : "r" (value) );
break;
case 2:
if ( value > (PAGE_OFFSET-4) ) return -EPERM;
if ( p == current )
- __asm__ ( "movl %0, %%db2" : : "r" (value) );
+ __asm__ ( "mov %0, %%db2" : : "r" (value) );
break;
case 3:
if ( value > (PAGE_OFFSET-4) ) return -EPERM;
if ( p == current )
- __asm__ ( "movl %0, %%db3" : : "r" (value) );
+ __asm__ ( "mov %0, %%db3" : : "r" (value) );
break;
case 6:
/*
@@ -967,7 +850,7 @@ long set_debugreg(struct domain *p, int reg, unsigned long value)
value &= 0xffffefff; /* reserved bits => 0 */
value |= 0xffff0ff0; /* reserved bits => 1 */
if ( p == current )
- __asm__ ( "movl %0, %%db6" : : "r" (value) );
+ __asm__ ( "mov %0, %%db6" : : "r" (value) );
break;
case 7:
/*
@@ -988,13 +871,13 @@ long set_debugreg(struct domain *p, int reg, unsigned long value)
if ( ((value >> (i+16)) & 3) == 2 ) return -EPERM;
}
if ( p == current )
- __asm__ ( "movl %0, %%db7" : : "r" (value) );
+ __asm__ ( "mov %0, %%db7" : : "r" (value) );
break;
default:
return -EINVAL;
}
- p->thread.debugreg[reg] = value;
+ p->arch.debugreg[reg] = value;
return 0;
}
@@ -1006,13 +889,5 @@ long do_set_debugreg(int reg, unsigned long value)
unsigned long do_get_debugreg(int reg)
{
if ( (reg < 0) || (reg > 7) ) return -EINVAL;
- return current->thread.debugreg[reg];
+ return current->arch.debugreg[reg];
}
-
-#else
-
-asmlinkage void fatal_trap(int trapnr, struct xen_regs *regs)
-{
-}
-
-#endif /* __i386__ */
diff --git a/xen/arch/x86/vmx.c b/xen/arch/x86/vmx.c
new file mode 100644
index 0000000000..67c08d073f
--- /dev/null
+++ b/xen/arch/x86/vmx.c
@@ -0,0 +1,939 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+/*
+ * vmx.c: handling VMX architecture-related VM exits
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, 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 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 <xen/config.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/sched.h>
+#include <asm/current.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/shadow.h>
+#include <asm/regs.h>
+#include <asm/cpufeature.h>
+#include <asm/processor.h>
+#include <asm/types.h>
+#include <asm/msr.h>
+#include <asm/spinlock.h>
+#include <asm/vmx.h>
+#include <asm/vmx_vmcs.h>
+#include <public/io/ioreq.h>
+
+int vmcs_size;
+unsigned int opt_vmx_debug_level;
+
+extern long evtchn_send(int lport);
+extern long do_block(void);
+
+#define VECTOR_DB 1
+#define VECTOR_BP 3
+#define VECTOR_GP 13
+#define VECTOR_PG 14
+
+int start_vmx()
+{
+ struct vmcs_struct *vmcs;
+ unsigned long ecx;
+ u64 phys_vmcs; /* debugging */
+
+ vmcs_size = VMCS_SIZE;
+ /*
+ * Xen does not fill x86_capability words except 0.
+ */
+ ecx = cpuid_ecx(1);
+ boot_cpu_data.x86_capability[4] = ecx;
+
+ if (!(test_bit(X86_FEATURE_VMXE, &boot_cpu_data.x86_capability)))
+ return 0;
+
+ set_in_cr4(X86_CR4_VMXE); /* Enable VMXE */
+
+ if (!(vmcs = alloc_vmcs())) {
+ printk("Failed to allocate VMCS\n");
+ return 0;
+ }
+
+ phys_vmcs = (u64) virt_to_phys(vmcs);
+
+ if (!(__vmxon(phys_vmcs))) {
+ printk("VMXON is done\n");
+ }
+
+ return 1;
+}
+
+void stop_vmx()
+{
+ if (read_cr4() & X86_CR4_VMXE)
+ __vmxoff();
+}
+
+/*
+ * Not all cases recevie valid value in the VM-exit instruction length field.
+ */
+#define __get_instruction_length(len) \
+ __vmread(INSTRUCTION_LEN, &(len)); \
+ if ((len) < 1 || (len) > 15) \
+ __vmx_bug(&regs);
+
+static void inline __update_guest_eip(unsigned long inst_len)
+{
+ unsigned long current_eip;
+
+ __vmread(GUEST_EIP, &current_eip);
+ __vmwrite(GUEST_EIP, current_eip + inst_len);
+}
+
+
+#include <asm/domain_page.h>
+
+static int vmx_do_page_fault(unsigned long va, unsigned long error_code)
+{
+ unsigned long eip, pfn;
+ unsigned int index;
+ unsigned long gpde = 0, gpte, gpa;
+ int result;
+ struct exec_domain *ed = current;
+
+#if VMX_DEBUG
+ {
+ __vmread(GUEST_EIP, &eip);
+ VMX_DBG_LOG(DBG_LEVEL_VMMU,
+ "vmx_do_page_fault = 0x%lx, eip = %lx, erro_code = %lx\n",
+ va, eip, error_code);
+ }
+#endif
+ /*
+ * Set up guest page directory cache to make linear_pt_table[] work.
+ */
+ __guest_get_pl2e(ed, va, &gpde);
+ if (!(gpde & _PAGE_PRESENT))
+ return 0;
+
+ index = (va >> L2_PAGETABLE_SHIFT);
+ if (!l2_pgentry_val(ed->arch.guest_pl2e_cache[index])) {
+ pfn = phys_to_machine_mapping[gpde >> PAGE_SHIFT];
+
+ VMX_DBG_LOG(DBG_LEVEL_VMMU, "vmx_do_page_fault: pagetable = %lx\n",
+ pagetable_val(ed->arch.pagetable));
+
+ ed->arch.guest_pl2e_cache[index] =
+ mk_l2_pgentry((pfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
+ }
+
+ if (unlikely(__get_user(gpte, (unsigned long *)
+ &linear_pg_table[va >> PAGE_SHIFT])))
+ return 0;
+
+ gpa = (gpte & PAGE_MASK) | (va & (PAGE_SIZE - 1));
+
+ if (mmio_space(gpa))
+ handle_mmio(va, gpte, gpa);
+
+ if ((result = shadow_fault(va, error_code)))
+ return result;
+
+ return 0; /* failed to resolve, i.e raise #PG */
+}
+
+static void vmx_do_general_protection_fault(struct xen_regs *regs)
+{
+ unsigned long eip, error_code;
+ unsigned long intr_fields;
+
+ __vmread(GUEST_EIP, &eip);
+ __vmread(VM_EXIT_INTR_ERROR_CODE, &error_code);
+
+ VMX_DBG_LOG(DBG_LEVEL_1,
+ "vmx_general_protection_fault: eip = %lx, erro_code = %lx\n",
+ eip, error_code);
+
+ VMX_DBG_LOG(DBG_LEVEL_1,
+ "eax=%lx, ebx=%lx, ecx=%lx, edx=%lx, esi=%lx, edi=%lx\n",
+ regs->eax, regs->ebx, regs->ecx, regs->edx, regs->esi, regs->edi);
+
+ /* Reflect it back into the guest */
+ intr_fields = (INTR_INFO_VALID_MASK |
+ INTR_TYPE_EXCEPTION |
+ INTR_INFO_DELIEVER_CODE_MASK |
+ VECTOR_GP);
+ __vmwrite(VM_ENTRY_INTR_INFO_FIELD, intr_fields);
+ __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
+}
+
+static void vmx_vmexit_do_cpuid(unsigned long input, struct xen_regs *regs)
+{
+ int eax, ebx, ecx, edx;
+ unsigned long eip;
+
+ __vmread(GUEST_EIP, &eip);
+
+ VMX_DBG_LOG(DBG_LEVEL_1,
+ "do_cpuid: (eax) %lx, (ebx) %lx, (ecx) %lx, (edx) %lx,"
+ " (esi) %lx, (edi) %lx\n",
+ regs->eax, regs->ebx, regs->ecx, regs->edx,
+ regs->esi, regs->edi);
+
+ cpuid(input, &eax, &ebx, &ecx, &edx);
+
+ if (input == 1) {
+ clear_bit(X86_FEATURE_PSE, &edx);
+ clear_bit(X86_FEATURE_PAE, &edx);
+ clear_bit(X86_FEATURE_PSE36, &edx);
+ }
+
+ regs->eax = (unsigned long) eax;
+ regs->ebx = (unsigned long) ebx;
+ regs->ecx = (unsigned long) ecx;
+ regs->edx = (unsigned long) edx;
+
+ VMX_DBG_LOG(DBG_LEVEL_1,
+ "vmx_vmexit_do_cpuid: eip: %lx, input: %lx, out:eax=%x, ebx=%x, ecx=%x, edx=%x\n",
+ eip, input, eax, ebx, ecx, edx);
+
+}
+
+#define CASE_GET_REG_P(REG, reg) \
+ case REG_ ## REG: reg_p = &(regs->reg); break
+
+static void vmx_dr_access (unsigned long exit_qualification, struct xen_regs *regs)
+{
+ unsigned int reg;
+ unsigned long *reg_p = 0;
+ struct exec_domain *ed = current;
+ unsigned long eip;
+
+ __vmread(GUEST_EIP, &eip);
+
+ reg = exit_qualification & DEBUG_REG_ACCESS_NUM;
+
+ VMX_DBG_LOG(DBG_LEVEL_1,
+ "vmx_dr_access : eip=%lx, reg=%d, exit_qualification = %lx\n",
+ eip, reg, exit_qualification);
+
+ switch(exit_qualification & DEBUG_REG_ACCESS_REG) {
+ CASE_GET_REG_P(EAX, eax);
+ CASE_GET_REG_P(ECX, ecx);
+ CASE_GET_REG_P(EDX, edx);
+ CASE_GET_REG_P(EBX, ebx);
+ CASE_GET_REG_P(EBP, ebp);
+ CASE_GET_REG_P(ESI, esi);
+ CASE_GET_REG_P(EDI, edi);
+ case REG_ESP:
+ break;
+ default:
+ __vmx_bug(regs);
+ }
+
+ switch (exit_qualification & DEBUG_REG_ACCESS_TYPE) {
+ case TYPE_MOV_TO_DR:
+ /* don't need to check the range */
+ if (reg != REG_ESP)
+ ed->arch.debugreg[reg] = *reg_p;
+ else {
+ unsigned long value;
+ __vmread(GUEST_ESP, &value);
+ ed->arch.debugreg[reg] = value;
+ }
+ break;
+ case TYPE_MOV_FROM_DR:
+ if (reg != REG_ESP)
+ *reg_p = ed->arch.debugreg[reg];
+ else {
+ __vmwrite(GUEST_ESP, ed->arch.debugreg[reg]);
+ }
+ break;
+ }
+}
+
+/*
+ * Invalidate the TLB for va. Invalidate the shadow page corresponding
+ * the address va.
+ */
+static void vmx_vmexit_do_invlpg(unsigned long va)
+{
+ unsigned long eip;
+ struct exec_domain *ed = current;
+ unsigned int index;
+
+ __vmread(GUEST_EIP, &eip);
+
+ VMX_DBG_LOG(DBG_LEVEL_VMMU, "vmx_vmexit_do_invlpg:eip=%08lx, va=%08lx\n",
+ eip, va);
+
+ /*
+ * We do the safest things first, then try to update the shadow
+ * copying from guest
+ */
+ vmx_shadow_invlpg(ed->domain, va);
+ index = (va >> L2_PAGETABLE_SHIFT);
+ ed->arch.guest_pl2e_cache[index] =
+ mk_l2_pgentry(0); /* invalidate pgd cache */
+}
+
+static inline void guest_pl2e_cache_invalidate(struct exec_domain *ed)
+{
+ /*
+ * Need to optimize this
+ */
+ memset(ed->arch.guest_pl2e_cache, 0, PAGE_SIZE);
+}
+
+inline unsigned long gva_to_gpa(unsigned long gva)
+{
+ unsigned long gpde, gpte, pfn, index;
+ struct exec_domain *ed = current;
+
+ __guest_get_pl2e(ed, gva, &gpde);
+ index = (gva >> L2_PAGETABLE_SHIFT);
+
+ pfn = phys_to_machine_mapping[gpde >> PAGE_SHIFT];
+
+ ed->arch.guest_pl2e_cache[index] =
+ mk_l2_pgentry((pfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
+
+ if ( unlikely(__get_user(gpte, (unsigned long *)
+ &linear_pg_table[gva >> PAGE_SHIFT])) )
+ {
+ printk("gva_to_gpa EXIT: read gpte faulted" );
+ return 0;
+ }
+
+ if ( !(gpte & _PAGE_PRESENT) )
+ {
+ printk("gva_to_gpa - EXIT: gpte not present (%lx)",gpte );
+ return 0;
+ }
+
+ return (gpte & PAGE_MASK) + (gva & ~PAGE_MASK);
+}
+
+static void vmx_io_instruction(struct xen_regs *regs,
+ unsigned long exit_qualification, unsigned long inst_len)
+{
+ struct exec_domain *d = current;
+ vcpu_iodata_t *vio;
+ ioreq_t *p;
+ unsigned long addr;
+ unsigned long eip;
+
+ __vmread(GUEST_EIP, &eip);
+
+ VMX_DBG_LOG(DBG_LEVEL_1,
+ "vmx_io_instruction: eip=%08lx, exit_qualification = %lx\n",
+ eip, exit_qualification);
+
+ if (test_bit(6, &exit_qualification))
+ addr = (exit_qualification >> 16) & (0xffff);
+ else
+ addr = regs->edx & 0xffff;
+
+ if (addr == 0x80) {
+ __update_guest_eip(inst_len);
+ return;
+ }
+
+ vio = (vcpu_iodata_t *) d->arch.arch_vmx.vmx_platform.shared_page_va;
+ if (vio == 0) {
+ VMX_DBG_LOG(DBG_LEVEL_1, "bad shared page: %lx\n", (unsigned long) vio);
+ domain_crash();
+ }
+ p = &vio->vp_ioreq;
+ p->dir = test_bit(3, &exit_qualification);
+ set_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags);
+
+ p->pdata_valid = 0;
+ p->count = 1;
+ p->size = (exit_qualification & 7) + 1;
+
+ if (test_bit(4, &exit_qualification)) {
+ unsigned long eflags;
+
+ __vmread(GUEST_EFLAGS, &eflags);
+ p->df = (eflags & X86_EFLAGS_DF) ? 1 : 0;
+ p->pdata_valid = 1;
+ p->u.pdata = (void *) ((p->dir == IOREQ_WRITE) ?
+ regs->esi
+ : regs->edi);
+ p->u.pdata = (void *) gva_to_gpa(p->u.data);
+ if (test_bit(5, &exit_qualification))
+ p->count = regs->ecx;
+ if ((p->u.data & PAGE_MASK) !=
+ ((p->u.data + p->count * p->size - 1) & PAGE_MASK)) {
+ printk("stringio crosses page boundary!\n");
+ if (p->u.data & (p->size - 1)) {
+ printk("Not aligned I/O!\n");
+ domain_crash();
+ }
+ p->count = (PAGE_SIZE - (p->u.data & ~PAGE_MASK)) / p->size;
+ } else {
+ __update_guest_eip(inst_len);
+ }
+ } else if (p->dir == IOREQ_WRITE) {
+ p->u.data = regs->eax;
+ __update_guest_eip(inst_len);
+ } else
+ __update_guest_eip(inst_len);
+
+ p->addr = addr;
+ p->port_mm = 0;
+ p->state = STATE_IOREQ_READY;
+ evtchn_send(IOPACKET_PORT);
+ do_block();
+}
+
+#define CASE_GET_REG(REG, reg) \
+ case REG_ ## REG: value = regs->reg; break
+
+/*
+ * Write to control registers
+ */
+static void mov_to_cr(int gp, int cr, struct xen_regs *regs)
+{
+ unsigned long value;
+ unsigned long old_cr;
+ struct exec_domain *d = current;
+
+ switch (gp) {
+ CASE_GET_REG(EAX, eax);
+ CASE_GET_REG(ECX, ecx);
+ CASE_GET_REG(EDX, edx);
+ CASE_GET_REG(EBX, ebx);
+ CASE_GET_REG(EBP, ebp);
+ CASE_GET_REG(ESI, esi);
+ CASE_GET_REG(EDI, edi);
+ case REG_ESP:
+ __vmread(GUEST_ESP, &value);
+ break;
+ default:
+ printk("invalid gp: %d\n", gp);
+ __vmx_bug(regs);
+ }
+
+ VMX_DBG_LOG(DBG_LEVEL_1, "mov_to_cr: CR%d, value = %lx, \n", cr, value);
+ VMX_DBG_LOG(DBG_LEVEL_1, "current = %lx, \n", (unsigned long) current);
+
+ switch(cr) {
+ case 0:
+ {
+ unsigned long old_base_pfn = 0, pfn;
+
+ /*
+ * CR0:
+ * We don't want to lose PE and PG.
+ */
+ __vmwrite(GUEST_CR0, (value | X86_CR0_PE | X86_CR0_PG));
+ __vmwrite(CR0_READ_SHADOW, value);
+
+ if (value & (X86_CR0_PE | X86_CR0_PG) &&
+ !test_bit(VMX_CPU_STATE_PG_ENABLED, &d->arch.arch_vmx.cpu_state)) {
+ /*
+ * Enable paging
+ */
+ set_bit(VMX_CPU_STATE_PG_ENABLED, &d->arch.arch_vmx.cpu_state);
+ /*
+ * The guest CR3 must be pointing to the guest physical.
+ */
+ if (!(pfn = phys_to_machine_mapping[
+ d->arch.arch_vmx.cpu_cr3 >> PAGE_SHIFT]))
+ {
+ VMX_DBG_LOG(DBG_LEVEL_VMMU, "Invalid CR3 value = %lx\n",
+ d->arch.arch_vmx.cpu_cr3);
+ domain_crash(); /* need to take a clean path */
+ }
+ old_base_pfn = pagetable_val(d->arch.pagetable) >> PAGE_SHIFT;
+ /*
+ * Now mm.pagetable points to machine physical.
+ */
+ d->arch.pagetable = mk_pagetable(pfn << PAGE_SHIFT);
+
+ VMX_DBG_LOG(DBG_LEVEL_VMMU, "New mm.pagetable = %lx\n",
+ (unsigned long) (pfn << PAGE_SHIFT));
+
+ shadow_lock(d->domain);
+ shadow_mode_enable(d->domain, SHM_full_32);
+ shadow_unlock(d->domain);
+
+ __vmwrite(GUEST_CR3, pagetable_val(d->arch.shadow_table));
+ /*
+ * mm->shadow_table should hold the next CR3 for shadow
+ */
+ VMX_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx, pfn = %lx\n",
+ d->arch.arch_vmx.cpu_cr3, pfn);
+ put_page_and_type(&frame_table[old_base_pfn]);
+
+ }
+ break;
+ }
+ case 3:
+ {
+ unsigned long pfn;
+
+ /*
+ * If paging is not enabled yet, simply copy the valut to CR3.
+ */
+ if (!test_bit(VMX_CPU_STATE_PG_ENABLED, &d->arch.arch_vmx.cpu_state)) {
+ d->arch.arch_vmx.cpu_cr3 = value;
+ return;
+ }
+
+ guest_pl2e_cache_invalidate(d);
+ /*
+ * We make a new one if the shadow does not exist.
+ */
+ if (value == d->arch.arch_vmx.cpu_cr3) {
+ /*
+ * This is simple TLB flush, implying the guest has
+ * removed some translation or changed page attributes.
+ * We simply invalidate the shadow.
+ */
+ pfn = phys_to_machine_mapping[value >> PAGE_SHIFT];
+ if ((pfn << PAGE_SHIFT) != pagetable_val(d->arch.pagetable))
+ __vmx_bug(regs);
+ vmx_shadow_clear_state(d->domain);
+ shadow_invalidate(d);
+ } else {
+ /*
+ * If different, make a shadow. Check if the PDBR is valid
+ * first.
+ */
+ VMX_DBG_LOG(DBG_LEVEL_VMMU, "CR3 value = %lx\n", value);
+ if ((value >> PAGE_SHIFT) > d->domain->max_pages)
+ {
+ VMX_DBG_LOG(DBG_LEVEL_VMMU,
+ "Invalid CR3 value=%lx\n", value);
+ domain_crash(); /* need to take a clean path */
+ }
+ pfn = phys_to_machine_mapping[value >> PAGE_SHIFT];
+ vmx_shadow_clear_state(d->domain);
+ d->arch.pagetable = mk_pagetable(pfn << PAGE_SHIFT);
+ shadow_mk_pagetable(d);
+ /*
+ * mm->shadow_table should hold the next CR3 for shadow
+ */
+ d->arch.arch_vmx.cpu_cr3 = value;
+ VMX_DBG_LOG(DBG_LEVEL_VMMU, "Update CR3 value = %lx\n",
+ value);
+ __vmwrite(GUEST_CR3, pagetable_val(d->arch.shadow_table));
+ }
+ break;
+ }
+ case 4:
+ /* CR4 */
+ if (value & X86_CR4_PAE)
+ __vmx_bug(regs); /* not implemented */
+ __vmread(CR4_READ_SHADOW, &old_cr);
+
+ __vmwrite(GUEST_CR4, (value | X86_CR4_VMXE));
+ __vmwrite(CR4_READ_SHADOW, value);
+
+ /*
+ * Writing to CR4 to modify the PSE, PGE, or PAE flag invalidates
+ * all TLB entries except global entries.
+ */
+ if ((old_cr ^ value) & (X86_CR4_PSE | X86_CR4_PGE | X86_CR4_PAE)) {
+ vmx_shadow_clear_state(d->domain);
+ shadow_invalidate(d);
+ guest_pl2e_cache_invalidate(d);
+ }
+ break;
+ default:
+ printk("invalid cr: %d\n", gp);
+ __vmx_bug(regs);
+ }
+}
+
+#define CASE_SET_REG(REG, reg) \
+ case REG_ ## REG: \
+ regs->reg = value; \
+ break
+
+/*
+ * Read from control registers. CR0 and CR4 are read from the shadow.
+ */
+static void mov_from_cr(int cr, int gp, struct xen_regs *regs)
+{
+ unsigned long value;
+ struct exec_domain *d = current;
+
+ if (cr != 3)
+ __vmx_bug(regs);
+
+ value = (unsigned long) d->arch.arch_vmx.cpu_cr3;
+ ASSERT(value);
+
+ switch (gp) {
+ CASE_SET_REG(EAX, eax);
+ CASE_SET_REG(ECX, ecx);
+ CASE_SET_REG(EDX, edx);
+ CASE_SET_REG(EBX, ebx);
+ CASE_SET_REG(EBP, ebp);
+ CASE_SET_REG(ESI, esi);
+ CASE_SET_REG(EDI, edi);
+ case REG_ESP:
+ __vmwrite(GUEST_ESP, value);
+ regs->esp = value;
+ break;
+ default:
+ printk("invalid gp: %d\n", gp);
+ __vmx_bug(regs);
+ }
+
+ VMX_DBG_LOG(DBG_LEVEL_VMMU, "mov_from_cr: CR%d, value = %lx, \n", cr, value);
+}
+
+static void vmx_cr_access (unsigned long exit_qualification, struct xen_regs *regs)
+{
+ unsigned int gp, cr;
+ unsigned long value;
+
+ switch (exit_qualification & CONTROL_REG_ACCESS_TYPE) {
+ case TYPE_MOV_TO_CR:
+ gp = exit_qualification & CONTROL_REG_ACCESS_REG;
+ cr = exit_qualification & CONTROL_REG_ACCESS_NUM;
+ mov_to_cr(gp, cr, regs);
+ break;
+ case TYPE_MOV_FROM_CR:
+ gp = exit_qualification & CONTROL_REG_ACCESS_REG;
+ cr = exit_qualification & CONTROL_REG_ACCESS_NUM;
+ mov_from_cr(cr, gp, regs);
+ break;
+ case TYPE_CLTS:
+ __vmread(GUEST_CR0, &value);
+ value &= ~X86_CR0_TS; /* clear TS */
+ __vmwrite(GUEST_CR0, value);
+
+ __vmread(CR0_READ_SHADOW, &value);
+ value &= ~X86_CR0_TS; /* clear TS */
+ __vmwrite(CR0_READ_SHADOW, value);
+ break;
+ default:
+ __vmx_bug(regs);
+ break;
+ }
+}
+
+static inline void vmx_do_msr_read(struct xen_regs *regs)
+{
+ VMX_DBG_LOG(DBG_LEVEL_1, "vmx_do_msr_read: ecx=%lx, eax=%lx, edx=%lx",
+ regs->ecx, regs->eax, regs->edx);
+
+ rdmsr(regs->ecx, regs->eax, regs->edx);
+
+ VMX_DBG_LOG(DBG_LEVEL_1, "vmx_do_msr_read returns: "
+ "ecx=%lx, eax=%lx, edx=%lx",
+ regs->ecx, regs->eax, regs->edx);
+}
+
+/*
+ * Need to use this exit to rescheule
+ */
+static inline void vmx_vmexit_do_hlt()
+{
+#if VMX_DEBUG
+ unsigned long eip;
+ __vmread(GUEST_EIP, &eip);
+#endif
+ VMX_DBG_LOG(DBG_LEVEL_1, "vmx_vmexit_do_hlt:eip=%08lx\n", eip);
+ __enter_scheduler();
+}
+
+static inline void vmx_vmexit_do_mwait()
+{
+#if VMX_DEBUG
+ unsigned long eip;
+ __vmread(GUEST_EIP, &eip);
+#endif
+ VMX_DBG_LOG(DBG_LEVEL_1, "vmx_vmexit_do_mwait:eip=%08lx\n", eip);
+ __enter_scheduler();
+}
+
+#define BUF_SIZ 256
+#define MAX_LINE 80
+char print_buf[BUF_SIZ];
+static int index;
+
+static void vmx_print_line(const char c, struct exec_domain *d)
+{
+
+ if (index == MAX_LINE || c == '\n') {
+ if (index == MAX_LINE) {
+ print_buf[index++] = c;
+ }
+ print_buf[index] = '\0';
+ printk("(GUEST: %u) %s\n", d->domain->id, (char *) &print_buf);
+ index = 0;
+ }
+ else
+ print_buf[index++] = c;
+}
+
+#ifdef XEN_DEBUGGER
+void save_xen_regs(struct xen_regs *regs)
+{
+ __vmread(GUEST_SS_SELECTOR, &regs->xss);
+ __vmread(GUEST_ESP, &regs->esp);
+ __vmread(GUEST_EFLAGS, &regs->eflags);
+ __vmread(GUEST_CS_SELECTOR, &regs->xcs);
+ __vmread(GUEST_EIP, &regs->eip);
+
+ __vmread(GUEST_GS_SELECTOR, &regs->xgs);
+ __vmread(GUEST_FS_SELECTOR, &regs->xfs);
+ __vmread(GUEST_ES_SELECTOR, &regs->xes);
+ __vmread(GUEST_DS_SELECTOR, &regs->xds);
+}
+
+void restore_xen_regs(struct xen_regs *regs)
+{
+ __vmwrite(GUEST_SS_SELECTOR, regs->xss);
+ __vmwrite(GUEST_ESP, regs->esp);
+ __vmwrite(GUEST_EFLAGS, regs->eflags);
+ __vmwrite(GUEST_CS_SELECTOR, regs->xcs);
+ __vmwrite(GUEST_EIP, regs->eip);
+
+ __vmwrite(GUEST_GS_SELECTOR, regs->xgs);
+ __vmwrite(GUEST_FS_SELECTOR, regs->xfs);
+ __vmwrite(GUEST_ES_SELECTOR, regs->xes);
+ __vmwrite(GUEST_DS_SELECTOR, regs->xds);
+}
+#endif
+
+asmlinkage void vmx_vmexit_handler(struct xen_regs regs)
+{
+ unsigned int exit_reason, idtv_info_field;
+ unsigned long exit_qualification, eip, inst_len = 0;
+ struct exec_domain *d = current;
+ int error;
+
+ if ((error = __vmread(VM_EXIT_REASON, &exit_reason)))
+ __vmx_bug(&regs);
+
+ __vmread(IDT_VECTORING_INFO_FIELD, &idtv_info_field);
+ if (idtv_info_field & INTR_INFO_VALID_MASK) {
+ __vmwrite(VM_ENTRY_INTR_INFO_FIELD, idtv_info_field);
+ if ((idtv_info_field & 0xff) == 14) {
+ unsigned long error_code;
+
+ __vmread(VM_EXIT_INTR_ERROR_CODE, &error_code);
+ printk("#PG error code: %lx\n", error_code);
+ }
+ VMX_DBG_LOG(DBG_LEVEL_1, "idtv_info_field=%x\n",
+ idtv_info_field);
+ }
+
+ /* don't bother H/W interrutps */
+ if (exit_reason != EXIT_REASON_EXTERNAL_INTERRUPT &&
+ exit_reason != EXIT_REASON_VMCALL &&
+ exit_reason != EXIT_REASON_IO_INSTRUCTION)
+ VMX_DBG_LOG(DBG_LEVEL_0, "exit reason = %x\n", exit_reason);
+
+ if (exit_reason & VMX_EXIT_REASONS_FAILED_VMENTRY) {
+ __vmread(EXIT_QUALIFICATION, &exit_qualification);
+ __vmread(GUEST_EIP, &eip);
+ domain_crash();
+ return;
+ }
+
+ switch (exit_reason) {
+ case EXIT_REASON_EXCEPTION_NMI:
+ {
+ /*
+ * We don't set the software-interrupt exiting (INT n).
+ * (1) We can get an exception (e.g. #PG) in the guest, or
+ * (2) NMI
+ */
+ int error;
+ unsigned int vector;
+ unsigned long va;
+ unsigned long error_code;
+
+ if ((error = __vmread(VM_EXIT_INTR_INFO, &vector))
+ && !(vector & INTR_INFO_VALID_MASK))
+ __vmx_bug(&regs);
+ vector &= 0xff;
+
+ switch (vector) {
+#ifdef XEN_DEBUGGER
+ case VECTOR_DB:
+ {
+ save_xen_regs(&regs);
+ pdb_handle_exception(1, &regs, 1);
+ restore_xen_regs(&regs);
+ break;
+ }
+ case VECTOR_BP:
+ {
+ save_xen_regs(&regs);
+ pdb_handle_exception(3, &regs, 1);
+ restore_xen_regs(&regs);
+ break;
+ }
+#endif
+ case VECTOR_GP:
+ {
+ vmx_do_general_protection_fault(&regs);
+ break;
+ }
+ case VECTOR_PG:
+ {
+ __vmread(EXIT_QUALIFICATION, &va);
+ __vmread(VM_EXIT_INTR_ERROR_CODE, &error_code);
+ VMX_DBG_LOG(DBG_LEVEL_VMMU,
+ "eax=%lx, ebx=%lx, ecx=%lx, edx=%lx, esi=%lx, edi=%lx\n",
+ regs.eax, regs.ebx, regs.ecx, regs.edx, regs.esi,
+ regs.edi);
+ d->arch.arch_vmx.vmx_platform.mpci.inst_decoder_regs = &regs;
+
+ if (!(error = vmx_do_page_fault(va, error_code))) {
+ /*
+ * Inject #PG using Interruption-Information Fields
+ */
+ unsigned long intr_fields;
+
+ intr_fields = (INTR_INFO_VALID_MASK |
+ INTR_TYPE_EXCEPTION |
+ INTR_INFO_DELIEVER_CODE_MASK |
+ VECTOR_PG);
+ __vmwrite(VM_ENTRY_INTR_INFO_FIELD, intr_fields);
+ __vmwrite(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code);
+ d->arch.arch_vmx.cpu_cr2 = va;
+ }
+ break;
+ }
+ default:
+ __vmx_bug(&regs);
+ break;
+ }
+ break;
+ }
+ case EXIT_REASON_EXTERNAL_INTERRUPT:
+ {
+ extern int vector_irq[];
+ extern asmlinkage void do_IRQ(struct xen_regs);
+ extern void smp_apic_timer_interrupt(struct xen_regs *);
+ extern void timer_interrupt(int, void *, struct xen_regs *);
+ unsigned int vector;
+
+ if ((error = __vmread(VM_EXIT_INTR_INFO, &vector))
+ && !(vector & INTR_INFO_VALID_MASK))
+ __vmx_bug(&regs);
+
+ vector &= 0xff;
+ local_irq_disable();
+
+ if (vector == LOCAL_TIMER_VECTOR) {
+ smp_apic_timer_interrupt(&regs);
+ } else {
+ regs.entry_vector = (vector == FIRST_DEVICE_VECTOR?
+ 0 : vector_irq[vector]);
+ do_IRQ(regs);
+ }
+ break;
+ }
+ case EXIT_REASON_PENDING_INTERRUPT:
+ __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
+ MONITOR_CPU_BASED_EXEC_CONTROLS);
+ vmx_intr_assist(d);
+ break;
+ case EXIT_REASON_TASK_SWITCH:
+ __vmx_bug(&regs);
+ break;
+ case EXIT_REASON_CPUID:
+ __get_instruction_length(inst_len);
+ vmx_vmexit_do_cpuid(regs.eax, &regs);
+ __update_guest_eip(inst_len);
+ break;
+ case EXIT_REASON_HLT:
+ __get_instruction_length(inst_len);
+ __update_guest_eip(inst_len);
+ vmx_vmexit_do_hlt();
+ break;
+ case EXIT_REASON_INVLPG:
+ {
+ unsigned long va;
+
+ __vmread(EXIT_QUALIFICATION, &va);
+ vmx_vmexit_do_invlpg(va);
+ __get_instruction_length(inst_len);
+ __update_guest_eip(inst_len);
+ break;
+ }
+ case EXIT_REASON_VMCALL:
+ __get_instruction_length(inst_len);
+ __vmread(GUEST_EIP, &eip);
+ __vmread(EXIT_QUALIFICATION, &exit_qualification);
+
+ vmx_print_line(regs.eax, d); /* provides the current domain */
+ __update_guest_eip(inst_len);
+ break;
+ case EXIT_REASON_CR_ACCESS:
+ {
+ __vmread(GUEST_EIP, &eip);
+ __get_instruction_length(inst_len);
+ __vmread(EXIT_QUALIFICATION, &exit_qualification);
+
+ VMX_DBG_LOG(DBG_LEVEL_1, "eip = %lx, inst_len =%lx, exit_qualification = %lx\n",
+ eip, inst_len, exit_qualification);
+ vmx_cr_access(exit_qualification, &regs);
+ __update_guest_eip(inst_len);
+ break;
+ }
+ case EXIT_REASON_DR_ACCESS:
+ __vmread(EXIT_QUALIFICATION, &exit_qualification);
+ vmx_dr_access(exit_qualification, &regs);
+ __get_instruction_length(inst_len);
+ __update_guest_eip(inst_len);
+ break;
+ case EXIT_REASON_IO_INSTRUCTION:
+ __vmread(EXIT_QUALIFICATION, &exit_qualification);
+ __get_instruction_length(inst_len);
+ vmx_io_instruction(&regs, exit_qualification, inst_len);
+ break;
+ case EXIT_REASON_MSR_READ:
+ __get_instruction_length(inst_len);
+ vmx_do_msr_read(&regs);
+ __update_guest_eip(inst_len);
+ break;
+ case EXIT_REASON_MSR_WRITE:
+ __vmread(GUEST_EIP, &eip);
+ VMX_DBG_LOG(DBG_LEVEL_1, "MSR_WRITE: eip=%08lx, eax=%08lx, edx=%08lx",
+ eip, regs.eax, regs.edx);
+ /* just ignore this point */
+ __get_instruction_length(inst_len);
+ __update_guest_eip(inst_len);
+ break;
+ case EXIT_REASON_MWAIT_INSTRUCTION:
+ __get_instruction_length(inst_len);
+ __update_guest_eip(inst_len);
+ vmx_vmexit_do_mwait();
+ break;
+ default:
+ __vmx_bug(&regs); /* should not happen */
+ }
+ return;
+}
+
+asmlinkage void load_cr2(void)
+{
+ struct exec_domain *d = current;
+
+ local_irq_disable();
+ asm volatile("movl %0,%%cr2": :"r" (d->arch.arch_vmx.cpu_cr2));
+}
diff --git a/xen/arch/x86/vmx_io.c b/xen/arch/x86/vmx_io.c
new file mode 100644
index 0000000000..d3585c2fc5
--- /dev/null
+++ b/xen/arch/x86/vmx_io.c
@@ -0,0 +1,388 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+/*
+ * vmx_io.c: handling I/O, interrupts related VMX entry/exit
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, 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 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 <xen/config.h>
+#include <xen/init.h>
+#include <xen/mm.h>
+#include <xen/lib.h>
+#include <xen/errno.h>
+
+#include <asm/cpufeature.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/vmx.h>
+#include <asm/vmx_vmcs.h>
+#include <xen/event.h>
+#include <public/io/ioreq.h>
+#include <asm/vmx_platform.h>
+
+extern long do_block();
+
+#if defined (__i386__)
+static void load_xen_regs(struct xen_regs *regs)
+{
+ /*
+ * Write the guest register value into VMCS
+ */
+ __vmwrite(GUEST_SS_SELECTOR, regs->ss);
+ __vmwrite(GUEST_ESP, regs->esp);
+ __vmwrite(GUEST_EFLAGS, regs->eflags);
+ __vmwrite(GUEST_CS_SELECTOR, regs->cs);
+ __vmwrite(GUEST_EIP, regs->eip);
+}
+
+static void set_reg_value (int size, int index, int seg, struct xen_regs *regs, long value)
+{
+ switch (size) {
+ case BYTE:
+ switch (index) {
+ case 0:
+ regs->eax &= 0xFFFFFF00;
+ regs->eax |= (value & 0xFF);
+ break;
+ case 1:
+ regs->ecx &= 0xFFFFFF00;
+ regs->ecx |= (value & 0xFF);
+ break;
+ case 2:
+ regs->edx &= 0xFFFFFF00;
+ regs->edx |= (value & 0xFF);
+ break;
+ case 3:
+ regs->ebx &= 0xFFFFFF00;
+ regs->ebx |= (value & 0xFF);
+ break;
+ case 4:
+ regs->eax &= 0xFFFF00FF;
+ regs->eax |= ((value & 0xFF) << 8);
+ break;
+ case 5:
+ regs->ecx &= 0xFFFF00FF;
+ regs->ecx |= ((value & 0xFF) << 8);
+ break;
+ case 6:
+ regs->edx &= 0xFFFF00FF;
+ regs->edx |= ((value & 0xFF) << 8);
+ break;
+ case 7:
+ regs->ebx &= 0xFFFF00FF;
+ regs->ebx |= ((value & 0xFF) << 8);
+ break;
+ default:
+ printk("size:%x, index:%x are invalid!\n", size, index);
+ break;
+
+ }
+ break;
+ case WORD:
+ switch (index) {
+ case 0:
+ regs->eax &= 0xFFFF0000;
+ regs->eax |= (value & 0xFFFF);
+ break;
+ case 1:
+ regs->ecx &= 0xFFFF0000;
+ regs->ecx |= (value & 0xFFFF);
+ break;
+ case 2:
+ regs->edx &= 0xFFFF0000;
+ regs->edx |= (value & 0xFFFF);
+ break;
+ case 3:
+ regs->ebx &= 0xFFFF0000;
+ regs->ebx |= (value & 0xFFFF);
+ break;
+ case 4:
+ regs->esp &= 0xFFFF0000;
+ regs->esp |= (value & 0xFFFF);
+ break;
+
+ case 5:
+ regs->ebp &= 0xFFFF0000;
+ regs->ebp |= (value & 0xFFFF);
+ break;
+ case 6:
+ regs->esi &= 0xFFFF0000;
+ regs->esi |= (value & 0xFFFF);
+ break;
+ case 7:
+ regs->edi &= 0xFFFF0000;
+ regs->edi |= (value & 0xFFFF);
+ break;
+ default:
+ printk("size:%x, index:%x are invalid!\n", size, index);
+ break;
+ }
+ break;
+ case LONG:
+ switch (index) {
+ case 0:
+ regs->eax = value;
+ break;
+ case 1:
+ regs->ecx = value;
+ break;
+ case 2:
+ regs->edx = value;
+ break;
+ case 3:
+ regs->ebx = value;
+ break;
+ case 4:
+ regs->esp = value;
+ break;
+ case 5:
+ regs->ebp = value;
+ break;
+ case 6:
+ regs->esi = value;
+ break;
+ case 7:
+ regs->edi = value;
+ break;
+ default:
+ printk("size:%x, index:%x are invalid!\n", size, index);
+ break;
+ }
+ break;
+ default:
+ printk("size:%x, index:%x are invalid!\n", size, index);
+ break;
+ }
+}
+#endif
+
+void vmx_io_assist(struct exec_domain *ed)
+{
+ vcpu_iodata_t *vio;
+ ioreq_t *p;
+ struct domain *d = ed->domain;
+ execution_context_t *ec = get_execution_context();
+ unsigned long old_eax;
+ int sign;
+ struct mi_per_cpu_info *mpci_p;
+ struct xen_regs *inst_decoder_regs;
+
+ mpci_p = &ed->arch.arch_vmx.vmx_platform.mpci;
+ inst_decoder_regs = mpci_p->inst_decoder_regs;
+
+ /* clear the pending event */
+ ed->vcpu_info->evtchn_upcall_pending = 0;
+ /* clear the pending bit for port 2 */
+ clear_bit(IOPACKET_PORT>>5, &ed->vcpu_info->evtchn_pending_sel);
+ clear_bit(IOPACKET_PORT, &d->shared_info->evtchn_pending[0]);
+
+ vio = (vcpu_iodata_t *) ed->arch.arch_vmx.vmx_platform.shared_page_va;
+ if (vio == 0) {
+ VMX_DBG_LOG(DBG_LEVEL_1,
+ "bad shared page: %lx\n", (unsigned long) vio);
+ domain_crash();
+ }
+ p = &vio->vp_ioreq;
+ /* clear IO wait VMX flag */
+ if (test_bit(ARCH_VMX_IO_WAIT, &ed->arch.arch_vmx.flags)) {
+ if (p->state != STATE_IORESP_READY) {
+ printk("got a false I/O reponse\n");
+ do_block();
+ } else {
+ p->state = STATE_INVALID;
+ }
+ clear_bit(ARCH_VMX_IO_WAIT, &ed->arch.arch_vmx.flags);
+ } else {
+ return;
+ }
+
+ sign = (p->df) ? -1 : 1;
+ if (p->port_mm) {
+ if (p->pdata_valid) {
+ ec->esi += sign * p->count * p->size;
+ ec->edi += sign * p->count * p->size;
+ } else {
+ if (p->dir == IOREQ_WRITE) {
+ return;
+ }
+ int size = -1, index = -1;
+
+ size = operand_size(ed->arch.arch_vmx.vmx_platform.mpci.mmio_target);
+ index = operand_index(ed->arch.arch_vmx.vmx_platform.mpci.mmio_target);
+
+ if (ed->arch.arch_vmx.vmx_platform.mpci.mmio_target & WZEROEXTEND) {
+ p->u.data = p->u.data & 0xffff;
+ }
+ set_reg_value(size, index, 0, (struct xen_regs *)ec, p->u.data);
+
+ }
+ load_xen_regs((struct xen_regs *)ec);
+ return;
+ }
+
+ if (p->dir == IOREQ_WRITE) {
+ if (p->pdata_valid) {
+ ec->esi += sign * p->count * p->size;
+ ec->ecx -= p->count;
+ }
+ return;
+ } else {
+ if (p->pdata_valid) {
+ ec->edi += sign * p->count * p->size;
+ ec->ecx -= p->count;
+ return;
+ }
+ }
+
+ old_eax = ec->eax;
+
+ switch(p->size) {
+ case 1:
+ ec->eax = (old_eax & 0xffffff00) | (p->u.data & 0xff);
+ break;
+ case 2:
+ ec->eax = (old_eax & 0xffff0000) | (p->u.data & 0xffff);
+ break;
+ case 4:
+ ec->eax = (p->u.data & 0xffffffff);
+ break;
+ default:
+ BUG();
+ }
+}
+
+static inline int __fls(unsigned long word)
+{
+ int bit;
+
+ __asm__("bsrl %1,%0"
+ :"=r" (bit)
+ :"rm" (word));
+ return word ? bit : -1;
+}
+
+
+/* Simple minded Local APIC priority implementation. Fix later */
+static __inline__ int find_highest_irq(unsigned long *pintr)
+{
+ if (pintr[7])
+ return __fls(pintr[7]) + (256-32*1);
+ if (pintr[6])
+ return __fls(pintr[6]) + (256-32*2);
+ if (pintr[5])
+ return __fls(pintr[5]) + (256-32*3);
+ if (pintr[4])
+ return __fls(pintr[4]) + (256-32*4);
+ if (pintr[3])
+ return __fls(pintr[3]) + (256-32*5);
+ if (pintr[2])
+ return __fls(pintr[2]) + (256-32*6);
+ if (pintr[1])
+ return __fls(pintr[1]) + (256-32*7);
+ return __fls(pintr[0]);
+}
+
+/*
+ * Return 0-255 for pending irq.
+ * -1 when no pending.
+ */
+static inline int find_highest_pending_irq(struct exec_domain *d)
+{
+ vcpu_iodata_t *vio;
+
+ vio = (vcpu_iodata_t *) d->arch.arch_vmx.vmx_platform.shared_page_va;
+ if (vio == 0) {
+ VMX_DBG_LOG(DBG_LEVEL_1,
+ "bad shared page: %lx\n", (unsigned long) vio);
+ domain_crash();
+ }
+
+ return find_highest_irq(&vio->vp_intr[0]);
+}
+
+static inline void clear_highest_bit(struct exec_domain *d, int vector)
+{
+ vcpu_iodata_t *vio;
+
+ vio = (vcpu_iodata_t *) d->arch.arch_vmx.vmx_platform.shared_page_va;
+ if (vio == 0) {
+ VMX_DBG_LOG(DBG_LEVEL_1,
+ "bad shared page: %lx\n", (unsigned long) vio);
+ domain_crash();
+ }
+
+ clear_bit(vector, &vio->vp_intr[0]);
+}
+
+static inline int irq_masked(unsigned long eflags)
+{
+ return ((eflags & X86_EFLAGS_IF) == 0);
+}
+
+void vmx_intr_assist(struct exec_domain *d)
+{
+ int highest_vector = find_highest_pending_irq(d);
+ unsigned long intr_fields, eflags;
+
+ if (highest_vector == -1)
+ return;
+
+ __vmread(VM_ENTRY_INTR_INFO_FIELD, &intr_fields);
+ if (intr_fields & INTR_INFO_VALID_MASK) {
+ VMX_DBG_LOG(DBG_LEVEL_1, "vmx_intr_assist: intr_fields: %lx\n",
+ intr_fields);
+ return;
+ }
+
+ __vmread(GUEST_EFLAGS, &eflags);
+ if (irq_masked(eflags)) {
+ VMX_DBG_LOG(DBG_LEVEL_1, "guesting pending: %x, eflags: %lx\n",
+ highest_vector, eflags);
+ return;
+ }
+
+ clear_highest_bit(d, highest_vector);
+ intr_fields = (INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR | highest_vector);
+ __vmwrite(VM_ENTRY_INTR_INFO_FIELD, intr_fields);
+
+ __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
+
+ return;
+}
+
+void vmx_do_resume(struct exec_domain *d)
+{
+ __vmwrite(HOST_CR3, pagetable_val(d->arch.monitor_table));
+ __vmwrite(GUEST_CR3, pagetable_val(d->arch.shadow_table));
+ __vmwrite(HOST_ESP, (unsigned long) get_stack_top());
+
+ if (event_pending(d)) {
+ if (test_bit(IOPACKET_PORT, &d->domain->shared_info->evtchn_pending[0]))
+ vmx_io_assist(d);
+
+ else if (test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags)) {
+ printk("got an event while blocked on I/O\n");
+ do_block();
+ }
+
+ /* Assumption: device model will not inject an interrupt
+ * while an ioreq_t is pending i.e. the response and
+ * interrupt can come together. But an interrupt without
+ * a response to ioreq_t is not ok.
+ */
+ }
+ if (!test_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags))
+ vmx_intr_assist(d);
+}
diff --git a/xen/arch/x86/vmx_platform.c b/xen/arch/x86/vmx_platform.c
new file mode 100644
index 0000000000..5be1c182be
--- /dev/null
+++ b/xen/arch/x86/vmx_platform.c
@@ -0,0 +1,555 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+/*
+ * vmx_platform.c: handling x86 platform related MMIO instructions
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, 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 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 <xen/config.h>
+#include <xen/types.h>
+#include <xen/mm.h>
+#include <asm/shadow.h>
+#include <asm/domain_page.h>
+#include <asm/page.h>
+#include <xen/event.h>
+#include <xen/trace.h>
+#include <asm/vmx.h>
+#include <asm/vmx_platform.h>
+#include <public/io/ioreq.h>
+
+#include <xen/lib.h>
+#include <xen/sched.h>
+#include <asm/current.h>
+
+#define DECODE_success 1
+#define DECODE_failure 0
+
+#if defined (__x86_64__)
+static void store_xen_regs(struct xen_regs *regs)
+{
+
+}
+
+static long get_reg_value(int size, int index, int seg, struct xen_regs *regs)
+{
+ return 0;
+}
+#elif defined (__i386__)
+static void store_xen_regs(struct xen_regs *regs)
+{
+ __vmread(GUEST_SS_SELECTOR, &regs->ss);
+ __vmread(GUEST_ESP, &regs->esp);
+ __vmread(GUEST_EFLAGS, &regs->eflags);
+ __vmread(GUEST_CS_SELECTOR, &regs->cs);
+ __vmread(GUEST_EIP, &regs->eip);
+}
+
+static long get_reg_value(int size, int index, int seg, struct xen_regs *regs)
+{
+ /*
+ * Reference the db_reg[] table
+ */
+ switch (size) {
+ case BYTE:
+ switch (index) {
+ case 0: //%al
+ return (char)(regs->eax & 0xFF);
+ case 1: //%cl
+ return (char)(regs->ecx & 0xFF);
+ case 2: //%dl
+ return (char)(regs->edx & 0xFF);
+ case 3: //%bl
+ return (char)(regs->ebx & 0xFF);
+ case 4: //%ah
+ return (char)((regs->eax & 0xFF00) >> 8);
+ case 5: //%ch
+ return (char)((regs->ecx & 0xFF00) >> 8);
+ case 6: //%dh
+ return (char)((regs->edx & 0xFF00) >> 8);
+ case 7: //%bh
+ return (char)((regs->ebx & 0xFF00) >> 8);
+ default:
+ printk("(get_reg_value)size case 0 error\n");
+ return -1;
+ }
+ case WORD:
+ switch (index) {
+ case 0: //%ax
+ return (short)(regs->eax & 0xFFFF);
+ case 1: //%cx
+ return (short)(regs->ecx & 0xFFFF);
+ case 2: //%dx
+ return (short)(regs->edx & 0xFFFF);
+ case 3: //%bx
+ return (short)(regs->ebx & 0xFFFF);
+ case 4: //%sp
+ return (short)(regs->esp & 0xFFFF);
+ break;
+ case 5: //%bp
+ return (short)(regs->ebp & 0xFFFF);
+ case 6: //%si
+ return (short)(regs->esi & 0xFFFF);
+ case 7: //%di
+ return (short)(regs->edi & 0xFFFF);
+ default:
+ printk("(get_reg_value)size case 1 error\n");
+ return -1;
+ }
+ case LONG:
+ switch (index) {
+ case 0: //%eax
+ return regs->eax;
+ case 1: //%ecx
+ return regs->ecx;
+ case 2: //%edx
+ return regs->edx;
+
+ case 3: //%ebx
+ return regs->ebx;
+ case 4: //%esp
+ return regs->esp;
+ case 5: //%ebp
+ return regs->ebp;
+ case 6: //%esi
+ return regs->esi;
+ case 7: //%edi
+ return regs->edi;
+ default:
+ printk("(get_reg_value)size case 2 error\n");
+ return -1;
+ }
+ default:
+ printk("(get_reg_value)size case error\n");
+ return -1;
+ }
+}
+#endif
+
+static inline unsigned char *check_prefix(unsigned char *inst, struct instruction *thread_inst)
+{
+ while (1) {
+ switch (*inst) {
+ case 0xf3: //REPZ
+ case 0xf2: //REPNZ
+ case 0xf0: //LOCK
+ case 0x2e: //CS
+ case 0x36: //SS
+ case 0x3e: //DS
+ case 0x26: //ES
+ case 0x64: //FS
+ case 0x65: //GS
+ break;
+ case 0x66: //32bit->16bit
+ thread_inst->op_size = WORD;
+ break;
+ case 0x67:
+ break;
+ default:
+ return inst;
+ }
+ inst++;
+ }
+}
+
+static inline unsigned long get_immediate(const unsigned char *inst, int op_size)
+{
+ int mod, reg, rm;
+ unsigned long val = 0;
+ int i;
+
+ mod = (*inst >> 6) & 3;
+ reg = (*inst >> 3) & 7;
+ rm = *inst & 7;
+
+ inst++; //skip ModR/M byte
+ if (mod != 3 && rm == 4) {
+ inst++; //skip SIB byte
+ }
+
+ switch(mod) {
+ case 0:
+ if (rm == 5) {
+ inst = inst + 4; //disp32, skip 4 bytes
+ }
+ break;
+ case 1:
+ inst++; //disp8, skip 1 byte
+ break;
+ case 2:
+ inst = inst + 4; //disp32, skip 4 bytes
+ }
+ for (i = 0; i < op_size; i++) {
+ val |= (*inst++ & 0xff) << (8 * i);
+ }
+
+ return val;
+}
+
+static inline int get_index(const unsigned char *inst)
+{
+ int mod, reg, rm;
+
+ mod = (*inst >> 6) & 3;
+ reg = (*inst >> 3) & 7;
+ rm = *inst & 7;
+
+ //Only one operand in the instruction is register
+ if (mod == 3) {
+ return rm;
+ } else {
+ return reg;
+ }
+ return 0;
+}
+
+static int vmx_decode(const unsigned char *inst, struct instruction *thread_inst)
+{
+ int index;
+
+ switch(*inst) {
+ case 0x88:
+ /* mov r8 to m8 */
+ thread_inst->op_size = BYTE;
+ index = get_index((inst + 1));
+ thread_inst->operand[0] = mk_operand(BYTE, index, 0, REGISTER);
+ break;
+ case 0x89:
+ /* mov r32/16 to m32/16 */
+ index = get_index((inst + 1));
+ if (thread_inst->op_size == WORD) {
+ thread_inst->operand[0] = mk_operand(WORD, index, 0, REGISTER);
+ } else {
+ thread_inst->op_size = LONG;
+ thread_inst->operand[0] = mk_operand(LONG, index, 0, REGISTER);
+ }
+ break;
+ case 0x8a:
+ /* mov m8 to r8 */
+ thread_inst->op_size = BYTE;
+ index = get_index((inst + 1));
+ thread_inst->operand[1] = mk_operand(BYTE, index, 0, REGISTER);
+ break;
+ case 0x8b:
+ /* mov r32/16 to m32/16 */
+ index = get_index((inst + 1));
+ if (thread_inst->op_size == WORD) {
+ thread_inst->operand[1] = mk_operand(WORD, index, 0, REGISTER);
+ } else {
+ thread_inst->op_size = LONG;
+ thread_inst->operand[1] = mk_operand(LONG, index, 0, REGISTER);
+ }
+ break;
+ case 0x8c:
+ case 0x8e:
+ printk("%x, This opcode hasn't been handled yet!", *inst);
+ return DECODE_failure;
+ /* Not handle it yet. */
+
+ case 0xa0:
+ /* mov byte to al */
+ thread_inst->op_size = BYTE;
+ thread_inst->operand[1] = mk_operand(BYTE, 0, 0, REGISTER);
+ break;
+ case 0xa1:
+ /* mov word/doubleword to ax/eax */
+ if (thread_inst->op_size == WORD) {
+ thread_inst->operand[1] = mk_operand(WORD, 0, 0, REGISTER);
+ } else {
+ thread_inst->op_size = LONG;
+ thread_inst->operand[1] = mk_operand(LONG, 0, 0, REGISTER);
+ }
+ break;
+ case 0xa2:
+ /* mov al to (seg:offset) */
+ thread_inst->op_size = BYTE;
+ thread_inst->operand[0] = mk_operand(BYTE, 0, 0, REGISTER);
+ break;
+ case 0xa3:
+ /* mov ax/eax to (seg:offset) */
+ if (thread_inst->op_size == WORD) {
+ thread_inst->operand[0] = mk_operand(WORD, 0, 0, REGISTER);
+ } else {
+ thread_inst->op_size = LONG;
+ thread_inst->operand[0] = mk_operand(LONG, 0, 0, REGISTER);
+ }
+ break;
+ case 0xa4:
+ /* movsb */
+ thread_inst->op_size = BYTE;
+ strcpy(thread_inst->i_name, "movs");
+
+ return DECODE_success;
+ case 0xa5:
+ /* movsw/movsl */
+ if (thread_inst->op_size == WORD) {
+ } else {
+ thread_inst->op_size = LONG;
+ }
+
+ strcpy(thread_inst->i_name, "movs");
+
+ return DECODE_success;
+
+ case 0xc6:
+ /* mov imm8 to m8 */
+ thread_inst->op_size = BYTE;
+ thread_inst->operand[0] = mk_operand(BYTE, 0, 0, IMMEDIATE);
+ thread_inst->immediate = get_immediate((inst+1), thread_inst->op_size);
+ break;
+ case 0xc7:
+ /* mov imm16/32 to m16/32 */
+ if (thread_inst->op_size == WORD) {
+ thread_inst->operand[0] = mk_operand(WORD, 0, 0, IMMEDIATE);
+ } else {
+ thread_inst->op_size = LONG;
+ thread_inst->operand[0] = mk_operand(LONG, 0, 0, IMMEDIATE);
+ }
+ thread_inst->immediate = get_immediate((inst+1), thread_inst->op_size);
+ break;
+
+ case 0x0f:
+ break;
+ default:
+ printk("%x, This opcode hasn't been handled yet!", *inst);
+ return DECODE_failure;
+ }
+
+ strcpy(thread_inst->i_name, "mov");
+ if (*inst != 0x0f) {
+ return DECODE_success;
+ }
+
+ inst++;
+ switch (*inst) {
+
+ /* movz */
+ case 0xb7:
+ index = get_index((inst + 1));
+ thread_inst->operand[1] = mk_operand(LONG, index, 0, REGISTER);
+ strcpy(thread_inst->i_name, "movzw");
+
+ return DECODE_success;
+ default:
+ printk("0f %x, This opcode hasn't been handled yet!", *inst);
+ return DECODE_failure;
+ }
+
+ /* will never reach here */
+ return DECODE_failure;
+}
+
+static int inst_copy_from_guest(char *buf, unsigned long guest_eip, int inst_len)
+{
+ unsigned long gpte;
+ unsigned long mfn;
+ unsigned long ma;
+ unsigned char * inst_start;
+
+ if (inst_len > MAX_INST_LEN || inst_len <= 0) {
+ return 0;
+ }
+
+ if ((guest_eip & PAGE_MASK) == ((guest_eip + inst_len) & PAGE_MASK)) {
+ if ( unlikely(__get_user(gpte, (unsigned long *)
+ &linear_pg_table[guest_eip >> PAGE_SHIFT])) )
+ {
+ printk("inst_copy_from_guest- EXIT: read gpte faulted" );
+ return 0;
+ }
+ mfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT];
+ ma = (mfn << PAGE_SHIFT) | (guest_eip & (PAGE_SIZE - 1));
+ inst_start = (unsigned char *)map_domain_mem(ma);
+
+ memcpy(buf, inst_start, inst_len);
+ unmap_domain_mem(inst_start);
+ } else {
+ // Todo: In two page frames
+ }
+
+ return inst_len;
+}
+
+static void init_instruction(struct instruction *mmio_inst)
+{
+ memset(mmio_inst->i_name, '0', I_NAME_LEN);
+ mmio_inst->op_size = 0;
+ mmio_inst->offset = 0;
+ mmio_inst->immediate = 0;
+ mmio_inst->seg_sel = 0;
+ mmio_inst->op_num = 0;
+
+ mmio_inst->operand[0] = 0;
+ mmio_inst->operand[1] = 0;
+ mmio_inst->operand[2] = 0;
+
+ mmio_inst->flags = 0;
+}
+
+static int read_from_mmio(struct instruction *inst_p)
+{
+ // Only for mov instruction now!!!
+ if (inst_p->operand[1] & REGISTER)
+ return 1;
+
+ return 0;
+}
+
+// dir: 1 read from mmio
+// 0 write to mmio
+static void send_mmio_req(unsigned long gpa,
+ struct instruction *inst_p, long value, int dir, int pvalid)
+{
+ struct exec_domain *d = current;
+ vcpu_iodata_t *vio;
+ ioreq_t *p;
+ struct mi_per_cpu_info *mpci_p;
+ struct xen_regs *inst_decoder_regs;
+ extern inline unsigned long gva_to_gpa(unsigned long gva);
+ extern long evtchn_send(int lport);
+ extern long do_block(void);
+
+ mpci_p = &current->arch.arch_vmx.vmx_platform.mpci;
+ inst_decoder_regs = mpci_p->inst_decoder_regs;
+ vio = (vcpu_iodata_t *) d->arch.arch_vmx.vmx_platform.shared_page_va;
+
+ if (vio == NULL) {
+ printk("bad shared page\n");
+ domain_crash();
+ }
+ p = &vio->vp_ioreq;
+
+ set_bit(ARCH_VMX_IO_WAIT, &d->arch.arch_vmx.flags);
+ p->dir = dir;
+ p->pdata_valid = pvalid;
+ p->count = 1;
+
+ p->port_mm = 1;
+ p->size = inst_p->op_size;
+ p->addr = gpa;
+ p->u.data = value;
+
+ // p->state = STATE_UPSTREAM_SENDING;
+ p->state = STATE_IOREQ_READY;
+
+ // Try to use ins/outs' framework
+ if (pvalid) {
+ // Handle "movs"
+ p->u.pdata = (void *) ((p->dir == IOREQ_WRITE) ?
+ inst_decoder_regs->esi
+ : inst_decoder_regs->edi);
+ p->u.pdata = (void *) gva_to_gpa(p->u.data);
+ p->count = inst_decoder_regs->ecx;
+ inst_decoder_regs->ecx = 0;
+ p->df = (inst_decoder_regs->eflags & EF_DF) ? 1 : 0;
+ }
+
+ evtchn_send(IOPACKET_PORT);
+ do_block();
+
+}
+
+void handle_mmio(unsigned long va, unsigned long gpte, unsigned long gpa)
+{
+ unsigned long eip;
+ unsigned long inst_len;
+ struct mi_per_cpu_info *mpci_p;
+ struct xen_regs *inst_decoder_regs;
+ struct instruction mmio_inst;
+ unsigned char inst[MAX_INST_LEN];
+ int ret;
+
+ mpci_p = &current->arch.arch_vmx.vmx_platform.mpci;
+ inst_decoder_regs = mpci_p->inst_decoder_regs;
+
+ __vmread(GUEST_EIP, &eip);
+ __vmread(INSTRUCTION_LEN, &inst_len);
+
+ memset(inst, '0', MAX_INST_LEN);
+ ret = inst_copy_from_guest(inst, eip, inst_len);
+ if (ret != inst_len) {
+ printk("handle_mmio - EXIT: get guest instruction fault\n");
+ domain_crash();
+ }
+
+ init_instruction(&mmio_inst);
+
+ if (vmx_decode(check_prefix(inst, &mmio_inst), &mmio_inst) == DECODE_failure)
+ domain_crash();
+
+ __vmwrite(GUEST_EIP, eip + inst_len);
+ store_xen_regs(inst_decoder_regs);
+
+ // Only handle "mov" and "movs" instructions!
+ if (!strncmp(mmio_inst.i_name, "movzw", 5)) {
+ long value = 0;
+ int index;
+
+ if (read_from_mmio(&mmio_inst)) {
+ // Send the request and waiting for return value.
+ mpci_p->mmio_target = mmio_inst.operand[1] | WZEROEXTEND;
+ mmio_inst.op_size = WORD;
+ send_mmio_req(gpa, &mmio_inst, value, 1, 0);
+ } else {
+ // Write to MMIO
+ if (mmio_inst.operand[0] & IMMEDIATE) {
+ value = mmio_inst.immediate;
+ } else if (mmio_inst.operand[0] & REGISTER) {
+ index = operand_index(mmio_inst.operand[0]);
+ value = get_reg_value(WORD, index, 0, inst_decoder_regs);
+ } else {
+ domain_crash();
+ }
+ mmio_inst.op_size = WORD;
+ send_mmio_req(gpa, &mmio_inst, value, 0, 0);
+ return;
+ }
+ }
+
+ if (!strncmp(mmio_inst.i_name, "movs", 4)) {
+ int tmp_dir;
+
+ tmp_dir = ((va == inst_decoder_regs->edi) ? IOREQ_WRITE : IOREQ_READ);
+ send_mmio_req(gpa, &mmio_inst, 0, tmp_dir, 1);
+ return;
+ }
+
+ if (!strncmp(mmio_inst.i_name, "mov", 3)) {
+ long value = 0;
+ int size, index;
+
+ if (read_from_mmio(&mmio_inst)) {
+ // Send the request and waiting for return value.
+ mpci_p->mmio_target = mmio_inst.operand[1];
+ send_mmio_req(gpa, &mmio_inst, value, 1, 0);
+ } else {
+ // Write to MMIO
+ if (mmio_inst.operand[0] & IMMEDIATE) {
+ value = mmio_inst.immediate;
+ } else if (mmio_inst.operand[0] & REGISTER) {
+ size = operand_size(mmio_inst.operand[0]);
+ index = operand_index(mmio_inst.operand[0]);
+ value = get_reg_value(size, index, 0, inst_decoder_regs);
+ } else {
+ domain_crash();
+ }
+ send_mmio_req(gpa, &mmio_inst, value, 0, 0);
+ return;
+ }
+ domain_crash();
+ }
+ domain_crash();
+}
+
diff --git a/xen/arch/x86/vmx_vmcs.c b/xen/arch/x86/vmx_vmcs.c
new file mode 100644
index 0000000000..72096c7043
--- /dev/null
+++ b/xen/arch/x86/vmx_vmcs.c
@@ -0,0 +1,504 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+/*
+ * vmx_vmcs.c: VMCS management
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, 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 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 <xen/config.h>
+#include <xen/init.h>
+#include <xen/mm.h>
+#include <xen/lib.h>
+#include <xen/errno.h>
+
+#include <asm/cpufeature.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/vmx.h>
+#include <xen/event.h>
+#include <xen/kernel.h>
+#include <public/io/ioreq.h>
+#include <asm/domain_page.h>
+
+struct vmcs_struct *alloc_vmcs(void)
+{
+ struct vmcs_struct *vmcs;
+ unsigned int cpu_sig = cpuid_eax(0x00000001);
+
+ vmcs = (struct vmcs_struct *) alloc_xenheap_pages(get_order(vmcs_size));
+ memset((char *) vmcs, 0, vmcs_size); /* don't remove this */
+
+ vmcs->vmcs_revision_id = (cpu_sig > 0xf41)? 3 : 1;
+ return vmcs;
+}
+
+void free_vmcs(struct vmcs_struct *vmcs)
+{
+ int order;
+
+ order = (vmcs_size >> PAGE_SHIFT) - 1;
+ free_xenheap_pages((unsigned long) vmcs, order);
+}
+
+static inline int construct_vmcs_controls(void)
+{
+ int error = 0;
+
+ error |= __vmwrite(PIN_BASED_VM_EXEC_CONTROL,
+ MONITOR_PIN_BASED_EXEC_CONTROLS);
+
+ error |= __vmwrite(CPU_BASED_VM_EXEC_CONTROL,
+ MONITOR_CPU_BASED_EXEC_CONTROLS);
+
+ error |= __vmwrite(VM_EXIT_CONTROLS, MONITOR_VM_EXIT_CONTROLS);
+ error |= __vmwrite(VM_ENTRY_CONTROLS, MONITOR_VM_ENTRY_CONTROLS);
+
+ return error;
+}
+
+#define GUEST_SEGMENT_LIMIT 0xffffffff
+#define HOST_SEGMENT_LIMIT 0xffffffff
+
+struct host_execution_env {
+ /* selectors */
+ unsigned short ldtr_selector;
+ unsigned short tr_selector;
+ unsigned short ds_selector;
+ unsigned short cs_selector;
+ /* limits */
+ unsigned short gdtr_limit;
+ unsigned short ldtr_limit;
+ unsigned short idtr_limit;
+ unsigned short tr_limit;
+ /* base */
+ unsigned long gdtr_base;
+ unsigned long ldtr_base;
+ unsigned long idtr_base;
+ unsigned long tr_base;
+ unsigned long ds_base;
+ unsigned long cs_base;
+ /* control registers */
+ unsigned long cr3;
+ unsigned long cr0;
+ unsigned long cr4;
+ unsigned long dr7;
+};
+
+#define round_pgdown(_p) ((_p)&PAGE_MASK) /* coped from domain.c */
+
+int vmx_setup_platform(struct exec_domain *d, execution_context_t *context)
+{
+ int i;
+ unsigned int n;
+ unsigned long *p, mpfn, offset, addr;
+ struct e820entry *e820p;
+ unsigned long gpfn = 0;
+
+ context->ebx = 0; /* Linux expects ebx to be 0 for boot proc */
+
+ n = context->ecx;
+ if (n > 32) {
+ VMX_DBG_LOG(DBG_LEVEL_1, "Too many e820 entries: %d\n", n);
+ return -1;
+ }
+
+ addr = context->edi;
+ offset = (addr & ~PAGE_MASK);
+ addr = round_pgdown(addr);
+ mpfn = phys_to_machine_mapping[addr >> PAGE_SHIFT];
+ p = map_domain_mem(mpfn << PAGE_SHIFT);
+
+ e820p = (struct e820entry *) ((unsigned long) p + offset);
+
+ for (i = 0; i < n; i++) {
+ if (e820p[i].type == E820_SHARED_PAGE) {
+ gpfn = (e820p[i].addr >> PAGE_SHIFT);
+ break;
+ }
+ }
+
+ if (gpfn == 0) {
+ VMX_DBG_LOG(DBG_LEVEL_1, "No shared Page ?\n");
+ return -1;
+ }
+ unmap_domain_mem(p);
+
+ mpfn = phys_to_machine_mapping[gpfn];
+ p = map_domain_mem(mpfn << PAGE_SHIFT);
+ d->arch.arch_vmx.vmx_platform.shared_page_va = (unsigned long) p;
+
+ return 0;
+}
+
+
+/*
+ * Add <guest pfn, machine pfn> mapping to per-domain mapping. Full
+ * virtualization does not need per-domain mapping.
+ */
+static int add_mapping_perdomain(struct exec_domain *d, unsigned long gpfn,
+ unsigned long mpfn)
+{
+ struct pfn_info *page;
+ unsigned long pfn = 0;
+
+ /*
+ * We support up to 4GB memory for a guest at this point
+ */
+ if (gpfn > ENTRIES_PER_L2_PAGETABLE * ENTRIES_PER_L1_PAGETABLE)
+ return -1;
+
+ if (!(l1_pgentry_val(d->domain->arch.mm_perdomain_pt[
+ gpfn >> (L2_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT)]) & _PAGE_PRESENT))
+ {
+ page = (struct pfn_info *) alloc_domheap_page(NULL);
+ if (!page) {
+ return -1;
+ }
+
+ pfn = (unsigned long) (page - frame_table);
+ d->domain->arch.mm_perdomain_pt[gpfn >> (L2_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT)] =
+ mk_l1_pgentry((pfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
+ }
+ phys_to_machine_mapping[gpfn] = mpfn;
+
+ return 0;
+}
+
+void vmx_do_launch(struct exec_domain *ed)
+{
+/* Update CR3, GDT, LDT, TR */
+ unsigned int tr, cpu, error = 0;
+ struct host_execution_env host_env;
+ struct Xgt_desc_struct desc;
+ struct list_head *list_ent;
+ l2_pgentry_t *mpl2e, *guest_pl2e_cache;
+ unsigned long i, pfn = 0;
+ struct pfn_info *page;
+ execution_context_t *ec = get_execution_context();
+ struct domain *d = ed->domain;
+
+ cpu = smp_processor_id();
+ d->arch.min_pfn = d->arch.max_pfn = 0;
+
+ spin_lock(&d->page_alloc_lock);
+ list_ent = d->page_list.next;
+
+ mpl2e = (l2_pgentry_t *)map_domain_mem(pagetable_val(ed->arch.monitor_table));
+
+ for ( i = 0; list_ent != &d->page_list; i++ )
+ {
+ pfn = list_entry(list_ent, struct pfn_info, list) - frame_table;
+ d->arch.min_pfn = min(d->arch.min_pfn, pfn);
+ d->arch.max_pfn = max(d->arch.max_pfn, pfn);
+ list_ent = frame_table[pfn].list.next;
+ add_mapping_perdomain(ed, i, pfn);
+ }
+
+ spin_unlock(&d->page_alloc_lock);
+
+ page = (struct pfn_info *) alloc_domheap_page(NULL);
+ pfn = (unsigned long) (page - frame_table);
+
+ /*
+ * make linear_pt_table work for guest ptes
+ */
+ mpl2e[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
+ mk_l2_pgentry((pfn << PAGE_SHIFT)| __PAGE_HYPERVISOR);
+
+ guest_pl2e_cache = map_domain_mem(pfn << PAGE_SHIFT);
+ memset(guest_pl2e_cache, 0, PAGE_SIZE); /* clean it up */
+ ed->arch.guest_pl2e_cache = guest_pl2e_cache;
+
+ unmap_domain_mem(mpl2e);
+
+ vmx_setup_platform(ed, ec);
+
+ __asm__ __volatile__ ("sgdt (%%eax) \n" :: "a"(&desc) : "memory");
+ host_env.gdtr_limit = desc.size;
+ host_env.gdtr_base = desc.address;
+
+ error |= __vmwrite(HOST_GDTR_BASE, host_env.gdtr_base);
+
+ error |= __vmwrite(GUEST_LDTR_SELECTOR, 0);
+ error |= __vmwrite(GUEST_LDTR_BASE, 0);
+ error |= __vmwrite(GUEST_LDTR_LIMIT, 0);
+
+ __asm__ __volatile__ ("str (%%eax) \n" :: "a"(&tr) : "memory");
+ host_env.tr_selector = tr;
+ host_env.tr_limit = sizeof(struct tss_struct);
+ host_env.tr_base = (unsigned long) &init_tss[cpu];
+
+ error |= __vmwrite(HOST_TR_SELECTOR, host_env.tr_selector);
+ error |= __vmwrite(HOST_TR_BASE, host_env.tr_base);
+ error |= __vmwrite(GUEST_TR_BASE, 0);
+ error |= __vmwrite(GUEST_TR_LIMIT, 0xff);
+
+ ed->arch.shadow_table = ed->arch.pagetable;
+ __vmwrite(GUEST_CR3, pagetable_val(ed->arch.pagetable));
+ __vmwrite(HOST_CR3, pagetable_val(ed->arch.monitor_table));
+ __vmwrite(HOST_ESP, (unsigned long) get_stack_top());
+
+ ed->arch.schedule_tail = arch_vmx_do_resume;
+}
+
+/*
+ * Initially set the same environement as host.
+ */
+static inline int
+construct_init_vmcs_guest(execution_context_t *context,
+ full_execution_context_t *full_context,
+ struct host_execution_env *host_env)
+{
+ int error = 0;
+ union vmcs_arbytes arbytes;
+ unsigned long dr7;
+ unsigned long eflags, shadow_cr;
+
+ /* MSR */
+ error |= __vmwrite(VM_EXIT_MSR_LOAD_ADDR, 0);
+ error |= __vmwrite(VM_EXIT_MSR_STORE_ADDR, 0);
+
+ error |= __vmwrite(VM_EXIT_MSR_STORE_COUNT, 0);
+ error |= __vmwrite(VM_EXIT_MSR_LOAD_COUNT, 0);
+ error |= __vmwrite(VM_ENTRY_MSR_LOAD_COUNT, 0);
+ /* interrupt */
+ error |= __vmwrite(VM_ENTRY_INTR_INFO_FIELD, 0);
+ /* mask */
+ error |= __vmwrite(CR0_GUEST_HOST_MASK, 0xffffffff);
+ error |= __vmwrite(CR4_GUEST_HOST_MASK, 0xffffffff);
+
+ error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MASK, 0);
+ error |= __vmwrite(PAGE_FAULT_ERROR_CODE_MATCH, 0);
+
+ /* TSC */
+ error |= __vmwrite(TSC_OFFSET, 0);
+ error |= __vmwrite(CR3_TARGET_COUNT, 0);
+
+ /* Guest Selectors */
+ error |= __vmwrite(GUEST_CS_SELECTOR, context->cs);
+ error |= __vmwrite(GUEST_ES_SELECTOR, context->es);
+ error |= __vmwrite(GUEST_SS_SELECTOR, context->ss);
+ error |= __vmwrite(GUEST_DS_SELECTOR, context->ds);
+ error |= __vmwrite(GUEST_FS_SELECTOR, context->fs);
+ error |= __vmwrite(GUEST_GS_SELECTOR, context->gs);
+
+ /* Guest segment Limits */
+ error |= __vmwrite(GUEST_CS_LIMIT, GUEST_SEGMENT_LIMIT);
+ error |= __vmwrite(GUEST_ES_LIMIT, GUEST_SEGMENT_LIMIT);
+ error |= __vmwrite(GUEST_SS_LIMIT, GUEST_SEGMENT_LIMIT);
+ error |= __vmwrite(GUEST_DS_LIMIT, GUEST_SEGMENT_LIMIT);
+ error |= __vmwrite(GUEST_FS_LIMIT, GUEST_SEGMENT_LIMIT);
+ error |= __vmwrite(GUEST_GS_LIMIT, GUEST_SEGMENT_LIMIT);
+
+ error |= __vmwrite(GUEST_IDTR_LIMIT, host_env->idtr_limit);
+
+ /* AR bytes */
+ arbytes.bytes = 0;
+ arbytes.fields.seg_type = 0x3; /* type = 3 */
+ arbytes.fields.s = 1; /* code or data, i.e. not system */
+ arbytes.fields.dpl = 0; /* DPL = 3 */
+ arbytes.fields.p = 1; /* segment present */
+ arbytes.fields.default_ops_size = 1; /* 32-bit */
+ arbytes.fields.g = 1;
+ arbytes.fields.null_bit = 0; /* not null */
+
+ error |= __vmwrite(GUEST_ES_AR_BYTES, arbytes.bytes);
+ error |= __vmwrite(GUEST_SS_AR_BYTES, arbytes.bytes);
+ error |= __vmwrite(GUEST_DS_AR_BYTES, arbytes.bytes);
+ error |= __vmwrite(GUEST_FS_AR_BYTES, arbytes.bytes);
+ error |= __vmwrite(GUEST_GS_AR_BYTES, arbytes.bytes);
+
+ arbytes.fields.seg_type = 0xb; /* type = 0xb */
+ error |= __vmwrite(GUEST_CS_AR_BYTES, arbytes.bytes);
+
+ error |= __vmwrite(GUEST_GDTR_BASE, context->edx);
+ context->edx = 0;
+ error |= __vmwrite(GUEST_GDTR_LIMIT, context->eax);
+ context->eax = 0;
+
+ arbytes.fields.s = 0; /* not code or data segement */
+ arbytes.fields.seg_type = 0x2; /* LTD */
+ arbytes.fields.default_ops_size = 0; /* 16-bit */
+ arbytes.fields.g = 0;
+ error |= __vmwrite(GUEST_LDTR_AR_BYTES, arbytes.bytes);
+
+ arbytes.fields.seg_type = 0xb; /* 32-bit TSS (busy) */
+ error |= __vmwrite(GUEST_TR_AR_BYTES, arbytes.bytes);
+
+ error |= __vmwrite(GUEST_CR0, host_env->cr0); /* same CR0 */
+
+ /* Initally PG, PE are not set*/
+ shadow_cr = host_env->cr0;
+ shadow_cr &= ~(X86_CR0_PE | X86_CR0_PG);
+ error |= __vmwrite(CR0_READ_SHADOW, shadow_cr);
+ /* CR3 is set in vmx_final_setup_guestos */
+ error |= __vmwrite(GUEST_CR4, host_env->cr4);
+ shadow_cr = host_env->cr4;
+ shadow_cr &= ~(X86_CR4_PGE | X86_CR4_VMXE);
+ error |= __vmwrite(CR4_READ_SHADOW, shadow_cr);
+
+ error |= __vmwrite(GUEST_ES_BASE, host_env->ds_base);
+ error |= __vmwrite(GUEST_CS_BASE, host_env->cs_base);
+ error |= __vmwrite(GUEST_SS_BASE, host_env->ds_base);
+ error |= __vmwrite(GUEST_DS_BASE, host_env->ds_base);
+ error |= __vmwrite(GUEST_FS_BASE, host_env->ds_base);
+ error |= __vmwrite(GUEST_GS_BASE, host_env->ds_base);
+ error |= __vmwrite(GUEST_IDTR_BASE, host_env->idtr_base);
+
+ error |= __vmwrite(GUEST_ESP, context->esp);
+ error |= __vmwrite(GUEST_EIP, context->eip);
+
+ eflags = context->eflags & ~VMCS_EFLAGS_RESERVED_0; /* clear 0s */
+ eflags |= VMCS_EFLAGS_RESERVED_1; /* set 1s */
+
+ error |= __vmwrite(GUEST_EFLAGS, eflags);
+
+ error |= __vmwrite(GUEST_INTERRUPTIBILITY_INFO, 0);
+ __asm__ __volatile__ ("mov %%dr7, %0\n" : "=r" (dr7));
+ error |= __vmwrite(GUEST_DR7, dr7);
+ error |= __vmwrite(GUEST_VMCS0, 0xffffffff);
+ error |= __vmwrite(GUEST_VMCS1, 0xffffffff);
+
+ return error;
+}
+
+static inline int construct_vmcs_host(struct host_execution_env *host_env)
+{
+ int error = 0;
+ unsigned long crn;
+ struct Xgt_desc_struct desc;
+
+ /* Host Selectors */
+ host_env->ds_selector = __HYPERVISOR_DS;
+ error |= __vmwrite(HOST_ES_SELECTOR, host_env->ds_selector);
+ error |= __vmwrite(HOST_SS_SELECTOR, host_env->ds_selector);
+ error |= __vmwrite(HOST_DS_SELECTOR, host_env->ds_selector);
+ error |= __vmwrite(HOST_FS_SELECTOR, host_env->ds_selector);
+ error |= __vmwrite(HOST_GS_SELECTOR, host_env->ds_selector);
+
+ host_env->cs_selector = __HYPERVISOR_CS;
+ error |= __vmwrite(HOST_CS_SELECTOR, host_env->cs_selector);
+
+ host_env->ds_base = 0;
+ host_env->cs_base = 0;
+ error |= __vmwrite(HOST_FS_BASE, host_env->ds_base);
+ error |= __vmwrite(HOST_GS_BASE, host_env->ds_base);
+
+/* Debug */
+ __asm__ __volatile__ ("sidt (%%eax) \n" :: "a"(&desc) : "memory");
+ host_env->idtr_limit = desc.size;
+ host_env->idtr_base = desc.address;
+ error |= __vmwrite(HOST_IDTR_BASE, host_env->idtr_base);
+
+ __asm__ __volatile__ ("movl %%cr0,%0" : "=r" (crn) : );
+ host_env->cr0 = crn;
+ error |= __vmwrite(HOST_CR0, crn); /* same CR0 */
+
+ /* CR3 is set in vmx_final_setup_hostos */
+ __asm__ __volatile__ ("movl %%cr4,%0" : "=r" (crn) : );
+ host_env->cr4 = crn;
+ error |= __vmwrite(HOST_CR4, crn);
+ error |= __vmwrite(HOST_EIP, (unsigned long) vmx_asm_vmexit_handler);
+
+ return error;
+}
+
+/*
+ * Need to extend to support full virtualization.
+ * The variable use_host_env indicates if the new VMCS needs to use
+ * the same setups as the host has (xenolinux).
+ */
+
+int construct_vmcs(struct arch_vmx_struct *arch_vmx,
+ execution_context_t *context,
+ full_execution_context_t *full_context,
+ int use_host_env)
+{
+ int error;
+ u64 vmcs_phys_ptr;
+
+ struct host_execution_env host_env;
+
+ if (use_host_env != VMCS_USE_HOST_ENV)
+ return -EINVAL;
+
+ memset(&host_env, 0, sizeof(struct host_execution_env));
+
+ vmcs_phys_ptr = (u64) virt_to_phys(arch_vmx->vmcs);
+
+ if ((error = __vmpclear (vmcs_phys_ptr))) {
+ printk("construct_vmcs: VMCLEAR failed\n");
+ return -EINVAL;
+ }
+ if ((error = load_vmcs(arch_vmx, vmcs_phys_ptr))) {
+ printk("construct_vmcs: load_vmcs failed: VMCS = %lx\n",
+ (unsigned long) vmcs_phys_ptr);
+ return -EINVAL;
+ }
+ if ((error = construct_vmcs_controls())) {
+ printk("construct_vmcs: construct_vmcs_controls failed\n");
+ return -EINVAL;
+ }
+ /* host selectors */
+ if ((error = construct_vmcs_host(&host_env))) {
+ printk("construct_vmcs: construct_vmcs_host failed\n");
+ return -EINVAL;
+ }
+ /* guest selectors */
+ if ((error = construct_init_vmcs_guest(context, full_context, &host_env))) {
+ printk("construct_vmcs: construct_vmcs_guest failed\n");
+ return -EINVAL;
+ }
+
+ if ((error |= __vmwrite(EXCEPTION_BITMAP,
+ MONITOR_DEFAULT_EXCEPTION_BITMAP))) {
+ printk("construct_vmcs: setting Exception bitmap failed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int load_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
+{
+ int error;
+
+ if ((error = __vmptrld(phys_ptr))) {
+ clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
+ return error;
+ }
+ set_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
+ return 0;
+}
+
+int store_vmcs(struct arch_vmx_struct *arch_vmx, u64 phys_ptr)
+{
+ /* take the current VMCS */
+ __vmptrst(phys_ptr);
+ clear_bit(ARCH_VMX_VMCS_LOADED, &arch_vmx->flags);
+ return 0;
+}
+
+void vm_launch_fail(unsigned long eflags)
+{
+ BUG();
+}
+
+void vm_resume_fail(unsigned long eflags)
+{
+ BUG();
+}
+
diff --git a/xen/arch/x86/x86_32/asm-offsets.c b/xen/arch/x86/x86_32/asm-offsets.c
index a85aa15db4..839893b793 100644
--- a/xen/arch/x86/x86_32/asm-offsets.c
+++ b/xen/arch/x86/x86_32/asm-offsets.c
@@ -37,20 +37,18 @@ void __dummy__(void)
DEFINE(XREGS_user_sizeof, sizeof(struct xen_regs));
BLANK();
- OFFSET(DOMAIN_processor, struct domain, processor);
- OFFSET(DOMAIN_shared_info, struct domain, shared_info);
- OFFSET(DOMAIN_event_sel, struct domain, thread.event_selector);
- OFFSET(DOMAIN_event_addr, struct domain, thread.event_address);
- OFFSET(DOMAIN_failsafe_sel, struct domain, thread.failsafe_selector);
- OFFSET(DOMAIN_failsafe_addr, struct domain, thread.failsafe_address);
- OFFSET(DOMAIN_trap_bounce, struct domain, thread.trap_bounce);
- OFFSET(DOMAIN_thread_flags, struct domain, thread.flags);
+ OFFSET(EDOMAIN_processor, struct exec_domain, processor);
+ OFFSET(EDOMAIN_vcpu_info, struct exec_domain, vcpu_info);
+ OFFSET(EDOMAIN_event_sel, struct exec_domain, arch.event_selector);
+ OFFSET(EDOMAIN_event_addr, struct exec_domain, arch.event_address);
+ OFFSET(EDOMAIN_failsafe_sel, struct exec_domain, arch.failsafe_selector);
+ OFFSET(EDOMAIN_failsafe_addr, struct exec_domain, arch.failsafe_address);
+ OFFSET(EDOMAIN_trap_bounce, struct exec_domain, arch.trap_bounce);
+ OFFSET(EDOMAIN_thread_flags, struct exec_domain, arch.flags);
BLANK();
- OFFSET(SHINFO_upcall_pending, shared_info_t,
- vcpu_data[0].evtchn_upcall_pending);
- OFFSET(SHINFO_upcall_mask, shared_info_t,
- vcpu_data[0].evtchn_upcall_mask);
+ OFFSET(VCPUINFO_upcall_pending, vcpu_info_t, evtchn_upcall_pending);
+ OFFSET(VCPUINFO_upcall_mask, vcpu_info_t, evtchn_upcall_mask);
BLANK();
OFFSET(TRAPBOUNCE_error_code, struct trap_bounce, error_code);
diff --git a/xen/arch/x86/x86_32/domain_build.c b/xen/arch/x86/x86_32/domain_build.c
new file mode 100644
index 0000000000..e8db6ac1eb
--- /dev/null
+++ b/xen/arch/x86/x86_32/domain_build.c
@@ -0,0 +1,402 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+/******************************************************************************
+ * domain_build.c
+ *
+ * Copyright (c) 2002-2005, K A Fraser
+ */
+
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/sched.h>
+#include <xen/smp.h>
+#include <xen/delay.h>
+#include <asm/regs.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/desc.h>
+#include <asm/i387.h>
+#include <xen/event.h>
+#include <xen/elf.h>
+#include <xen/kernel.h>
+
+/* No ring-3 access in initial page tables. */
+#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
+#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+
+#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
+#define round_pgdown(_p) ((_p)&PAGE_MASK)
+
+int construct_dom0(struct domain *d,
+ unsigned long alloc_start,
+ unsigned long alloc_end,
+ unsigned long _image_start, unsigned long image_len,
+ unsigned long _initrd_start, unsigned long initrd_len,
+ char *cmdline)
+{
+ char *dst;
+ int i, rc;
+ unsigned long pfn, mfn;
+ unsigned long nr_pages = (alloc_end - alloc_start) >> PAGE_SHIFT;
+ unsigned long nr_pt_pages;
+ unsigned long count;
+ l2_pgentry_t *l2tab, *l2start;
+ l1_pgentry_t *l1tab = NULL, *l1start = NULL;
+ struct pfn_info *page = NULL;
+ start_info_t *si;
+ struct exec_domain *ed = d->exec_domain[0];
+ char *image_start = (char *)_image_start; /* use lowmem mappings */
+ char *initrd_start = (char *)_initrd_start; /* use lowmem mappings */
+
+ /*
+ * This fully describes the memory layout of the initial domain. All
+ * *_start address are page-aligned, except v_start (and v_end) which are
+ * superpage-aligned.
+ */
+ struct domain_setup_info dsi;
+ unsigned long vinitrd_start;
+ unsigned long vinitrd_end;
+ unsigned long vphysmap_start;
+ unsigned long vphysmap_end;
+ unsigned long vstartinfo_start;
+ unsigned long vstartinfo_end;
+ unsigned long vstack_start;
+ unsigned long vstack_end;
+ unsigned long vpt_start;
+ unsigned long vpt_end;
+ unsigned long v_end;
+
+ /* Machine address of next candidate page-table page. */
+ unsigned long mpt_alloc;
+
+ extern void physdev_init_dom0(struct domain *);
+
+ /* Sanity! */
+ if ( d->id != 0 )
+ BUG();
+ if ( test_bit(DF_CONSTRUCTED, &d->d_flags) )
+ BUG();
+
+ memset(&dsi, 0, sizeof(struct domain_setup_info));
+
+ printk("*** LOADING DOMAIN 0 ***\n");
+
+ /*
+ * This is all a bit grim. We've moved the modules to the "safe" physical
+ * memory region above MAP_DIRECTMAP_ADDRESS (48MB). Later in this
+ * routine we're going to copy it down into the region that's actually
+ * been allocated to domain 0. This is highly likely to be overlapping, so
+ * we use a forward copy.
+ *
+ * MAP_DIRECTMAP_ADDRESS should be safe. The worst case is a machine with
+ * 4GB and lots of network/disk cards that allocate loads of buffers.
+ * We'll have to revisit this if we ever support PAE (64GB).
+ */
+
+ rc = parseelfimage(image_start, image_len, &dsi);
+ if ( rc != 0 )
+ return rc;
+
+ /* Set up domain options */
+ if ( dsi.use_writable_pagetables )
+ vm_assist(d, VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
+
+ /* Align load address to 4MB boundary. */
+ dsi.v_start &= ~((1UL<<22)-1);
+
+ /*
+ * Why do we need this? The number of page-table frames depends on the
+ * size of the bootstrap address space. But the size of the address space
+ * depends on the number of page-table frames (since each one is mapped
+ * read-only). We have a pair of simultaneous equations in two unknowns,
+ * which we solve by exhaustive search.
+ */
+ vinitrd_start = round_pgup(dsi.v_kernend);
+ vinitrd_end = vinitrd_start + initrd_len;
+ vphysmap_start = round_pgup(vinitrd_end);
+ vphysmap_end = vphysmap_start + (nr_pages * sizeof(unsigned long));
+ vpt_start = round_pgup(vphysmap_end);
+ for ( nr_pt_pages = 2; ; nr_pt_pages++ )
+ {
+ vpt_end = vpt_start + (nr_pt_pages * PAGE_SIZE);
+ vstartinfo_start = vpt_end;
+ vstartinfo_end = vstartinfo_start + PAGE_SIZE;
+ vstack_start = vstartinfo_end;
+ vstack_end = vstack_start + PAGE_SIZE;
+ v_end = (vstack_end + (1UL<<22)-1) & ~((1UL<<22)-1);
+ if ( (v_end - vstack_end) < (512UL << 10) )
+ v_end += 1UL << 22; /* Add extra 4MB to get >= 512kB padding. */
+ if ( (((v_end - dsi.v_start + ((1UL<<L2_PAGETABLE_SHIFT)-1)) >>
+ L2_PAGETABLE_SHIFT) + 1) <= nr_pt_pages )
+ break;
+ }
+
+ printk("PHYSICAL MEMORY ARRANGEMENT:\n"
+ " Kernel image: %p->%p\n"
+ " Initrd image: %p->%p\n"
+ " Dom0 alloc.: %p->%p\n",
+ _image_start, _image_start + image_len,
+ _initrd_start, _initrd_start + initrd_len,
+ alloc_start, alloc_end);
+ printk("VIRTUAL MEMORY ARRANGEMENT:\n"
+ " Loaded kernel: %p->%p\n"
+ " Init. ramdisk: %p->%p\n"
+ " Phys-Mach map: %p->%p\n"
+ " Page tables: %p->%p\n"
+ " Start info: %p->%p\n"
+ " Boot stack: %p->%p\n"
+ " TOTAL: %p->%p\n",
+ dsi.v_kernstart, dsi.v_kernend,
+ vinitrd_start, vinitrd_end,
+ vphysmap_start, vphysmap_end,
+ vpt_start, vpt_end,
+ vstartinfo_start, vstartinfo_end,
+ vstack_start, vstack_end,
+ dsi.v_start, v_end);
+ printk(" ENTRY ADDRESS: %p\n", dsi.v_kernentry);
+
+ if ( (v_end - dsi.v_start) > (nr_pages * PAGE_SIZE) )
+ {
+ printk("Initial guest OS requires too much space\n"
+ "(%luMB is greater than %luMB limit)\n",
+ (v_end-dsi.v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
+ return -ENOMEM;
+ }
+
+ /*
+ * Protect the lowest 1GB of memory. We use a temporary mapping there
+ * from which we copy the kernel and ramdisk images.
+ */
+ if ( dsi.v_start < (1UL<<30) )
+ {
+ printk("Initial loading isn't allowed to lowest 1GB of memory.\n");
+ return -EINVAL;
+ }
+
+ /* Paranoia: scrub DOM0's memory allocation. */
+ printk("Scrubbing DOM0 RAM: ");
+ dst = (char *)alloc_start;
+ while ( dst < (char *)alloc_end )
+ {
+#define SCRUB_BYTES (100 * 1024 * 1024) /* 100MB */
+ printk(".");
+ touch_nmi_watchdog();
+ if ( ((char *)alloc_end - dst) > SCRUB_BYTES )
+ {
+ memset(dst, 0, SCRUB_BYTES);
+ dst += SCRUB_BYTES;
+ }
+ else
+ {
+ memset(dst, 0, (char *)alloc_end - dst);
+ break;
+ }
+ }
+ printk("done.\n");
+
+ /* Construct a frame-allocation list for the initial domain. */
+ for ( mfn = (alloc_start>>PAGE_SHIFT);
+ mfn < (alloc_end>>PAGE_SHIFT);
+ mfn++ )
+ {
+ page = &frame_table[mfn];
+ page_set_owner(page, d);
+ page->u.inuse.type_info = 0;
+ page->count_info = PGC_allocated | 1;
+ list_add_tail(&page->list, &d->page_list);
+ d->tot_pages++; d->max_pages++;
+ }
+
+ mpt_alloc = (vpt_start - dsi.v_start) + alloc_start;
+
+ SET_GDT_ENTRIES(ed, DEFAULT_GDT_ENTRIES);
+ SET_GDT_ADDRESS(ed, DEFAULT_GDT_ADDRESS);
+
+ /*
+ * We're basically forcing default RPLs to 1, so that our "what privilege
+ * level are we returning to?" logic works.
+ */
+ ed->arch.failsafe_selector = FLAT_GUESTOS_CS;
+ ed->arch.event_selector = FLAT_GUESTOS_CS;
+ ed->arch.guestos_ss = FLAT_GUESTOS_SS;
+ for ( i = 0; i < 256; i++ )
+ ed->arch.traps[i].cs = FLAT_GUESTOS_CS;
+
+ /* WARNING: The new domain must have its 'processor' field filled in! */
+ l2start = l2tab = (l2_pgentry_t *)mpt_alloc; mpt_alloc += PAGE_SIZE;
+ memcpy(l2tab, &idle_pg_table[0], PAGE_SIZE);
+ l2tab[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
+ mk_l2_pgentry((unsigned long)l2start | __PAGE_HYPERVISOR);
+ l2tab[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT] =
+ mk_l2_pgentry(__pa(d->arch.mm_perdomain_pt) | __PAGE_HYPERVISOR);
+ ed->arch.pagetable = mk_pagetable((unsigned long)l2start);
+
+ l2tab += l2_table_offset(dsi.v_start);
+ mfn = alloc_start >> PAGE_SHIFT;
+ for ( count = 0; count < ((v_end-dsi.v_start)>>PAGE_SHIFT); count++ )
+ {
+ if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) )
+ {
+ l1start = l1tab = (l1_pgentry_t *)mpt_alloc;
+ mpt_alloc += PAGE_SIZE;
+ *l2tab++ = mk_l2_pgentry((unsigned long)l1start | L2_PROT);
+ clear_page(l1tab);
+ if ( count == 0 )
+ l1tab += l1_table_offset(dsi.v_start);
+ }
+ *l1tab++ = mk_l1_pgentry((mfn << PAGE_SHIFT) | L1_PROT);
+
+ page = &frame_table[mfn];
+ if ( !get_page_and_type(page, d, PGT_writable_page) )
+ BUG();
+
+ mfn++;
+ }
+
+ /* Pages that are part of page tables must be read only. */
+ l2tab = l2start + l2_table_offset(vpt_start);
+ l1start = l1tab = (l1_pgentry_t *)l2_pgentry_to_phys(*l2tab);
+ l1tab += l1_table_offset(vpt_start);
+ for ( count = 0; count < nr_pt_pages; count++ )
+ {
+ *l1tab = mk_l1_pgentry(l1_pgentry_val(*l1tab) & ~_PAGE_RW);
+ page = &frame_table[l1_pgentry_to_pagenr(*l1tab)];
+ if ( count == 0 )
+ {
+ page->u.inuse.type_info &= ~PGT_type_mask;
+ page->u.inuse.type_info |= PGT_l2_page_table;
+
+ /*
+ * No longer writable: decrement the type_count.
+ * Installed as CR3: increment both the ref_count and type_count.
+ * Net: just increment the ref_count.
+ */
+ get_page(page, d); /* an extra ref because of readable mapping */
+
+ /* Get another ref to L2 page so that it can be pinned. */
+ if ( !get_page_and_type(page, d, PGT_l2_page_table) )
+ BUG();
+ set_bit(_PGT_pinned, &page->u.inuse.type_info);
+ }
+ else
+ {
+ page->u.inuse.type_info &= ~PGT_type_mask;
+ page->u.inuse.type_info |= PGT_l1_page_table;
+ page->u.inuse.type_info |=
+ ((dsi.v_start>>L2_PAGETABLE_SHIFT)+(count-1))<<PGT_va_shift;
+
+ /*
+ * No longer writable: decrement the type_count.
+ * This is an L1 page, installed in a validated L2 page:
+ * increment both the ref_count and type_count.
+ * Net: just increment the ref_count.
+ */
+ get_page(page, d); /* an extra ref because of readable mapping */
+ }
+ if ( !((unsigned long)++l1tab & (PAGE_SIZE - 1)) )
+ l1start = l1tab = (l1_pgentry_t *)l2_pgentry_to_phys(*++l2tab);
+ }
+
+ /* Set up shared-info area. */
+ update_dom_time(d);
+ d->shared_info->domain_time = 0;
+ /* Mask all upcalls... */
+ for ( i = 0; i < MAX_VIRT_CPUS; i++ )
+ d->shared_info->vcpu_data[i].evtchn_upcall_mask = 1;
+ d->shared_info->n_vcpu = smp_num_cpus;
+
+ /* Install the new page tables. */
+ __cli();
+ write_ptbase(ed);
+
+ /* Copy the OS image. */
+ (void)loadelfimage(image_start);
+
+ /* Copy the initial ramdisk. */
+ if ( initrd_len != 0 )
+ memcpy((void *)vinitrd_start, initrd_start, initrd_len);
+
+ /* Set up start info area. */
+ si = (start_info_t *)vstartinfo_start;
+ memset(si, 0, PAGE_SIZE);
+ si->nr_pages = d->tot_pages;
+ si->shared_info = virt_to_phys(d->shared_info);
+ si->flags = SIF_PRIVILEGED | SIF_INITDOMAIN;
+ si->pt_base = vpt_start;
+ si->nr_pt_frames = nr_pt_pages;
+ si->mfn_list = vphysmap_start;
+
+ /* Write the phys->machine and machine->phys table entries. */
+ for ( pfn = 0; pfn < d->tot_pages; pfn++ )
+ {
+ mfn = pfn + (alloc_start>>PAGE_SHIFT);
+#ifndef NDEBUG
+#define REVERSE_START ((v_end - dsi.v_start) >> PAGE_SHIFT)
+ if ( pfn > REVERSE_START )
+ mfn = (alloc_end>>PAGE_SHIFT) - (pfn - REVERSE_START);
+#endif
+ ((unsigned long *)vphysmap_start)[pfn] = mfn;
+ machine_to_phys_mapping[mfn] = pfn;
+ }
+
+ if ( initrd_len != 0 )
+ {
+ si->mod_start = vinitrd_start;
+ si->mod_len = initrd_len;
+ printk("Initrd len 0x%lx, start at 0x%p\n",
+ si->mod_len, si->mod_start);
+ }
+
+ dst = si->cmd_line;
+ if ( cmdline != NULL )
+ {
+ for ( i = 0; i < 255; i++ )
+ {
+ if ( cmdline[i] == '\0' )
+ break;
+ *dst++ = cmdline[i];
+ }
+ }
+ *dst = '\0';
+
+ /* Reinstate the caller's page tables. */
+ write_ptbase(current);
+ __sti();
+
+ /* Destroy low mappings - they were only for our convenience. */
+ for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
+ if ( l2_pgentry_val(l2start[i]) & _PAGE_PSE )
+ l2start[i] = mk_l2_pgentry(0);
+ zap_low_mappings(); /* Do the same for the idle page tables. */
+
+ /* DOM0 gets access to everything. */
+ physdev_init_dom0(d);
+
+ set_bit(DF_CONSTRUCTED, &d->d_flags);
+
+ new_thread(ed, dsi.v_kernentry, vstack_end, vstartinfo_start);
+
+#if 0 /* XXXXX DO NOT CHECK IN ENABLED !!! (but useful for testing so leave) */
+ shadow_lock(&d->mm);
+ shadow_mode_enable(d, SHM_test);
+ shadow_unlock(&d->mm);
+#endif
+
+ return 0;
+}
+
+int elf_sanity_check(Elf_Ehdr *ehdr)
+{
+ if ( !IS_ELF(*ehdr) ||
+ (ehdr->e_ident[EI_CLASS] != ELFCLASS32) ||
+ (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) ||
+ (ehdr->e_type != ET_EXEC) ||
+ (ehdr->e_machine != EM_386) )
+ {
+ printk("DOM0 image is not i386-compatible executable Elf image.\n");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/xen/arch/x86/x86_32/entry.S b/xen/arch/x86/x86_32/entry.S
index 1afeded9c9..d9a084ba95 100644
--- a/xen/arch/x86/x86_32/entry.S
+++ b/xen/arch/x86/x86_32/entry.S
@@ -66,9 +66,117 @@
andl $~3,reg; \
movl (reg),reg;
+#ifdef CONFIG_VMX
+/*
+ * At VMExit time the processor saves the guest selectors, esp, eip,
+ * and eflags. Therefore we don't save them, but simply decrement
+ * the kernel stack pointer to make it consistent with the stack frame
+ * at usual interruption time. The eflags of the host is not saved by VMX,
+ * and we set it to the fixed value.
+ *
+ * We also need the room, especially because orig_eax field is used
+ * by do_IRQ(). Compared the xen_regs, we skip pushing for the following:
+ * (10) u32 gs;
+ * (9) u32 fs;
+ * (8) u32 ds;
+ * (7) u32 es;
+ * <- get_stack_top() (= HOST_ESP)
+ * (6) u32 ss;
+ * (5) u32 esp;
+ * (4) u32 eflags;
+ * (3) u32 cs;
+ * (2) u32 eip;
+ * (2/1) u16 entry_vector;
+ * (1/1) u16 error_code;
+ * However, get_stack_top() acturally returns 20 bytes below the real
+ * top of the stack to allow space for:
+ * domain pointer, DS, ES, FS, GS. Therefore, we effectively skip 6 registers.
+ */
+#define VMX_MONITOR_EFLAGS 0x202 /* IF on */
+#define NR_SKIPPED_REGS 6 /* See the above explanation */
+#define VMX_SAVE_ALL_NOSEGREGS \
+ pushl $VMX_MONITOR_EFLAGS; \
+ popf; \
+ subl $(NR_SKIPPED_REGS*4), %esp; \
+ pushl %eax; \
+ pushl %ebp; \
+ pushl %edi; \
+ pushl %esi; \
+ pushl %edx; \
+ pushl %ecx; \
+ pushl %ebx;
+
+ENTRY(vmx_asm_vmexit_handler)
+ /* selectors are restored/saved by VMX */
+ VMX_SAVE_ALL_NOSEGREGS
+ call SYMBOL_NAME(vmx_vmexit_handler)
+ jmp vmx_asm_do_resume
+
+ENTRY(vmx_asm_do_launch)
+ popl %ebx
+ popl %ecx
+ popl %edx
+ popl %esi
+ popl %edi
+ popl %ebp
+ popl %eax
+ addl $(NR_SKIPPED_REGS*4), %esp
+ /* VMLUANCH */
+ .byte 0x0f,0x01,0xc2
+ pushf
+ call SYMBOL_NAME(vm_launch_fail)
+ hlt
+
+ ALIGN
+
+ENTRY(vmx_asm_do_resume)
+vmx_test_all_events:
+ GET_CURRENT(%ebx)
+/* test_all_events: */
+ xorl %ecx,%ecx
+ notl %ecx
+ cli # tests must not race interrupts
+/*test_softirqs:*/
+ movl EDOMAIN_processor(%ebx),%eax
+ shl $6,%eax # sizeof(irq_cpustat) == 64
+ test %ecx,SYMBOL_NAME(irq_stat)(%eax,1)
+ jnz vmx_process_softirqs
+
+vmx_restore_all_guest:
+ call SYMBOL_NAME(load_cr2)
+ /*
+ * Check if we are going back to VMX-based VM
+ * By this time, all the setups in the VMCS must be complete.
+ */
+ popl %ebx
+ popl %ecx
+ popl %edx
+ popl %esi
+ popl %edi
+ popl %ebp
+ popl %eax
+ addl $(NR_SKIPPED_REGS*4), %esp
+ /* VMRESUME */
+ .byte 0x0f,0x01,0xc3
+ pushf
+ call SYMBOL_NAME(vm_resume_fail)
+ /* Should never reach here */
+ hlt
+
+ ALIGN
+vmx_process_softirqs:
+ sti
+ call SYMBOL_NAME(do_softirq)
+ jmp vmx_test_all_events
+#endif
+
+ENTRY(continue_nonidle_task)
+ GET_CURRENT(%ebx)
+ jmp test_all_events
+
ALIGN
restore_all_guest:
- testb $TF_failsafe_return,DOMAIN_thread_flags(%ebx)
+ testb $TF_failsafe_return,EDOMAIN_thread_flags(%ebx)
jnz failsafe_callback
testl $X86_EFLAGS_VM,XREGS_eflags(%esp)
jnz restore_all_vm86
@@ -111,9 +219,9 @@ FIX1: SET_XEN_SEGMENTS(a)
DBLFLT1:GET_CURRENT(%ebx)
jmp test_all_events
DBLFIX1:GET_CURRENT(%ebx)
- testb $TF_failsafe_return,DOMAIN_thread_flags(%ebx)
+ testb $TF_failsafe_return,EDOMAIN_thread_flags(%ebx)
jnz domain_crash # cannot reenter failsafe code
- orb $TF_failsafe_return,DOMAIN_thread_flags(%ebx)
+ orb $TF_failsafe_return,EDOMAIN_thread_flags(%ebx)
jmp test_all_events # will return via failsafe code
.previous
.section __pre_ex_table,"a"
@@ -130,11 +238,11 @@ DBLFIX1:GET_CURRENT(%ebx)
/* No special register assumptions */
failsafe_callback:
GET_CURRENT(%ebx)
- andb $~TF_failsafe_return,DOMAIN_thread_flags(%ebx)
- leal DOMAIN_trap_bounce(%ebx),%edx
- movl DOMAIN_failsafe_addr(%ebx),%eax
+ andb $~TF_failsafe_return,EDOMAIN_thread_flags(%ebx)
+ leal EDOMAIN_trap_bounce(%ebx),%edx
+ movl EDOMAIN_failsafe_addr(%ebx),%eax
movl %eax,TRAPBOUNCE_eip(%edx)
- movl DOMAIN_failsafe_sel(%ebx),%eax
+ movl EDOMAIN_failsafe_sel(%ebx),%eax
movw %ax,TRAPBOUNCE_cs(%edx)
movw $TBF_FAILSAFE,TRAPBOUNCE_flags(%edx)
call create_bounce_frame
@@ -150,7 +258,7 @@ FLT6: iret
.section .fixup,"ax"
FIX6: pushl %ebx
GET_CURRENT(%ebx)
- orb $TF_failsafe_return,DOMAIN_thread_flags(%ebx)
+ orb $TF_failsafe_return,EDOMAIN_thread_flags(%ebx)
pop %ebx
jmp FIX5
.section __pre_ex_table,"a"
@@ -186,26 +294,26 @@ test_all_events:
notl %ecx
cli # tests must not race interrupts
/*test_softirqs:*/
- movl DOMAIN_processor(%ebx),%eax
+ movl EDOMAIN_processor(%ebx),%eax
shl $6,%eax # sizeof(irq_cpustat) == 64
test %ecx,SYMBOL_NAME(irq_stat)(%eax,1)
jnz process_softirqs
/*test_guest_events:*/
- movl DOMAIN_shared_info(%ebx),%eax
- testb $0xFF,SHINFO_upcall_mask(%eax)
+ movl EDOMAIN_vcpu_info(%ebx),%eax
+ testb $0xFF,VCPUINFO_upcall_mask(%eax)
jnz restore_all_guest
- testb $0xFF,SHINFO_upcall_pending(%eax)
+ testb $0xFF,VCPUINFO_upcall_pending(%eax)
jz restore_all_guest
/*process_guest_events:*/
- leal DOMAIN_trap_bounce(%ebx),%edx
- movl DOMAIN_event_addr(%ebx),%eax
+ leal EDOMAIN_trap_bounce(%ebx),%edx
+ movl EDOMAIN_event_addr(%ebx),%eax
movl %eax,TRAPBOUNCE_eip(%edx)
- movl DOMAIN_event_sel(%ebx),%eax
+ movl EDOMAIN_event_sel(%ebx),%eax
movw %ax,TRAPBOUNCE_cs(%edx)
movw $TBF_INTERRUPT,TRAPBOUNCE_flags(%edx)
call create_bounce_frame
- movl DOMAIN_shared_info(%ebx),%eax
- movb $1,SHINFO_upcall_mask(%eax) # Upcalls are masked during delivery
+ movl EDOMAIN_vcpu_info(%ebx),%eax
+ movb $1,VCPUINFO_upcall_mask(%eax) # Upcalls are masked during delivery
jmp restore_all_guest
ALIGN
@@ -224,7 +332,7 @@ create_bounce_frame:
testl $(2|X86_EFLAGS_VM),%ecx
jz ring1 /* jump if returning to an existing ring-1 activation */
/* obtain ss/esp from TSS -- no current ring-1 activations */
- movl DOMAIN_processor(%ebx),%eax
+ movl EDOMAIN_processor(%ebx),%eax
/* next 4 lines multiply %eax by 8320, which is sizeof(tss_struct) */
movl %eax, %ecx
shll $7, %ecx
@@ -335,7 +443,7 @@ DBLFLT2:jmp process_guest_exception_and_events
ALIGN
process_guest_exception_and_events:
- leal DOMAIN_trap_bounce(%ebx),%edx
+ leal EDOMAIN_trap_bounce(%ebx),%edx
testb $TBF_EXCEPTION,TRAPBOUNCE_flags(%edx)
jz test_all_events
cli # create_bounce_frame needs CLI for pre-exceptions to work
@@ -674,6 +782,7 @@ ENTRY(hypercall_table)
.long SYMBOL_NAME(do_vm_assist)
.long SYMBOL_NAME(do_update_va_mapping_otherdomain)
.long SYMBOL_NAME(do_switch_vm86)
+ .long SYMBOL_NAME(do_boot_vcpu)
.rept NR_hypercalls-((.-hypercall_table)/4)
.long SYMBOL_NAME(do_ni_hypercall)
.endr
diff --git a/xen/arch/x86/x86_32/mm.c b/xen/arch/x86/x86_32/mm.c
index 4fc5623dc8..304f6d3188 100644
--- a/xen/arch/x86/x86_32/mm.c
+++ b/xen/arch/x86/x86_32/mm.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* arch/x86/x86_32/mm.c
*
@@ -27,32 +28,62 @@
#include <asm/fixmap.h>
#include <asm/domain_page.h>
-unsigned long m2p_start_mfn;
-
-static inline void set_pte_phys(unsigned long vaddr,
- l1_pgentry_t entry)
+/* Map physical byte range (@p, @p+@s) at virt address @v in pagetable @pt. */
+int map_pages(
+ pagetable_t *pt,
+ unsigned long v,
+ unsigned long p,
+ unsigned long s,
+ unsigned long flags)
{
- l2_pgentry_t *l2ent;
- l1_pgentry_t *l1ent;
+ l2_pgentry_t *pl2e;
+ l1_pgentry_t *pl1e;
+ void *newpg;
- l2ent = &idle_pg_table[l2_table_offset(vaddr)];
- l1ent = l2_pgentry_to_l1(*l2ent) + l1_table_offset(vaddr);
- *l1ent = entry;
+ while ( s != 0 )
+ {
+ pl2e = &pt[l2_table_offset(v)];
- /* It's enough to flush this one mapping. */
- __flush_tlb_one(vaddr);
-}
+ if ( ((s|v|p) & ((1<<L2_PAGETABLE_SHIFT)-1)) == 0 )
+ {
+ /* Super-page mapping. */
+ if ( (l2_pgentry_val(*pl2e) & _PAGE_PRESENT) )
+ __flush_tlb_pge();
+ *pl2e = mk_l2_pgentry(p|flags|_PAGE_PSE);
+
+ v += 1 << L2_PAGETABLE_SHIFT;
+ p += 1 << L2_PAGETABLE_SHIFT;
+ s -= 1 << L2_PAGETABLE_SHIFT;
+ }
+ else
+ {
+ /* Normal page mapping. */
+ if ( !(l2_pgentry_val(*pl2e) & _PAGE_PRESENT) )
+ {
+ newpg = (void *)alloc_xenheap_page();
+ clear_page(newpg);
+ *pl2e = mk_l2_pgentry(__pa(newpg) | __PAGE_HYPERVISOR);
+ }
+ pl1e = l2_pgentry_to_l1(*pl2e) + l1_table_offset(v);
+ if ( (l1_pgentry_val(*pl1e) & _PAGE_PRESENT) )
+ __flush_tlb_one(v);
+ *pl1e = mk_l1_pgentry(p|flags);
+
+ v += 1 << L1_PAGETABLE_SHIFT;
+ p += 1 << L1_PAGETABLE_SHIFT;
+ s -= 1 << L1_PAGETABLE_SHIFT;
+ }
+ }
+ return 0;
+}
-void __set_fixmap(enum fixed_addresses idx,
- l1_pgentry_t entry)
+void __set_fixmap(
+ enum fixed_addresses idx, unsigned long p, unsigned long flags)
{
- unsigned long address = fix_to_virt(idx);
-
- if ( likely(idx < __end_of_fixed_addresses) )
- set_pte_phys(address, entry);
- else
- printk("Invalid __set_fixmap\n");
+ if ( unlikely(idx >= __end_of_fixed_addresses) )
+ BUG();
+ map_pages(idle_pg_table, fix_to_virt(idx), p, PAGE_SIZE, flags);
}
@@ -65,16 +96,16 @@ void __init paging_init(void)
/* Allocate and map the machine-to-phys table. */
if ( (pg = alloc_domheap_pages(NULL, 10)) == NULL )
panic("Not enough memory to bootstrap Xen.\n");
- m2p_start_mfn = page_to_pfn(pg);
- idle_pg_table[RDWR_MPT_VIRT_START >> L2_PAGETABLE_SHIFT] =
+ idle_pg_table[l2_table_offset(RDWR_MPT_VIRT_START)] =
mk_l2_pgentry(page_to_phys(pg) | __PAGE_HYPERVISOR | _PAGE_PSE);
+ memset((void *)RDWR_MPT_VIRT_START, 0x55, 4UL << 20);
/* Xen 4MB mappings can all be GLOBAL. */
if ( cpu_has_pge )
{
for ( v = HYPERVISOR_VIRT_START; v; v += (1 << L2_PAGETABLE_SHIFT) )
{
- l2e = l2_pgentry_val(idle_pg_table[v >> L2_PAGETABLE_SHIFT]);
+ l2e = l2_pgentry_val(idle_pg_table[l2_table_offset(v)]);
if ( l2e & _PAGE_PSE )
l2e |= _PAGE_GLOBAL;
idle_pg_table[v >> L2_PAGETABLE_SHIFT] = mk_l2_pgentry(l2e);
@@ -84,23 +115,22 @@ void __init paging_init(void)
/* Create page table for ioremap(). */
ioremap_pt = (void *)alloc_xenheap_page();
clear_page(ioremap_pt);
- idle_pg_table[IOREMAP_VIRT_START >> L2_PAGETABLE_SHIFT] =
+ idle_pg_table[l2_table_offset(IOREMAP_VIRT_START)] =
mk_l2_pgentry(__pa(ioremap_pt) | __PAGE_HYPERVISOR);
/* Create read-only mapping of MPT for guest-OS use. */
- idle_pg_table[RO_MPT_VIRT_START >> L2_PAGETABLE_SHIFT] =
+ idle_pg_table[l2_table_offset(RO_MPT_VIRT_START)] =
mk_l2_pgentry(l2_pgentry_val(
- idle_pg_table[RDWR_MPT_VIRT_START >> L2_PAGETABLE_SHIFT]) &
- ~_PAGE_RW);
+ idle_pg_table[l2_table_offset(RDWR_MPT_VIRT_START)]) & ~_PAGE_RW);
/* Set up mapping cache for domain pages. */
mapcache = (unsigned long *)alloc_xenheap_page();
clear_page(mapcache);
- idle_pg_table[MAPCACHE_VIRT_START >> L2_PAGETABLE_SHIFT] =
+ idle_pg_table[l2_table_offset(MAPCACHE_VIRT_START)] =
mk_l2_pgentry(__pa(mapcache) | __PAGE_HYPERVISOR);
/* Set up linear page table mapping. */
- idle_pg_table[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
+ idle_pg_table[l2_table_offset(LINEAR_PT_VIRT_START)] =
mk_l2_pgentry(__pa(idle_pg_table) | __PAGE_HYPERVISOR);
}
@@ -112,6 +142,39 @@ void __init zap_low_mappings(void)
flush_tlb_all_pge();
}
+void subarch_init_memory(struct domain *dom_xen)
+{
+ unsigned long i, m2p_start_mfn;
+
+ /*
+ * We are rather picky about the layout of 'struct pfn_info'. The
+ * count_info and domain fields must be adjacent, as we perform atomic
+ * 64-bit operations on them. Also, just for sanity, we assert the size
+ * of the structure here.
+ */
+ if ( (offsetof(struct pfn_info, u.inuse._domain) !=
+ (offsetof(struct pfn_info, count_info) + sizeof(u32))) ||
+ (sizeof(struct pfn_info) != 24) )
+ {
+ printk("Weird pfn_info layout (%ld,%ld,%d)\n",
+ offsetof(struct pfn_info, count_info),
+ offsetof(struct pfn_info, u.inuse._domain),
+ sizeof(struct pfn_info));
+ for ( ; ; ) ;
+ }
+
+ /* M2P table is mappable read-only by privileged domains. */
+ m2p_start_mfn = l2_pgentry_to_pagenr(
+ idle_pg_table[l2_table_offset(RDWR_MPT_VIRT_START)]);
+ for ( i = 0; i < 1024; i++ )
+ {
+ frame_table[m2p_start_mfn+i].count_info = PGC_allocated | 1;
+ /* gdt to make sure it's only mapped read-only by non-privileged
+ domains. */
+ frame_table[m2p_start_mfn+i].u.inuse.type_info = PGT_gdt_page | 1;
+ page_set_owner(&frame_table[m2p_start_mfn+i], dom_xen);
+ }
+}
/*
* Allows shooting down of borrowed page-table use on specific CPUs.
@@ -119,9 +182,10 @@ void __init zap_low_mappings(void)
*/
static void __synchronise_pagetables(void *mask)
{
- struct domain *d = current;
- if ( ((unsigned long)mask & (1<<d->processor)) && is_idle_task(d) )
- write_ptbase(&d->mm);
+ struct exec_domain *ed = current;
+ if ( ((unsigned long)mask & (1 << ed->processor)) &&
+ is_idle_task(ed->domain) )
+ write_ptbase(ed);
}
void synchronise_pagetables(unsigned long cpu_mask)
{
@@ -138,8 +202,8 @@ long do_stack_switch(unsigned long ss, unsigned long esp)
if ( (ss & 3) == 0 )
return -EPERM;
- current->thread.guestos_ss = ss;
- current->thread.guestos_sp = esp;
+ current->arch.guestos_ss = ss;
+ current->arch.guestos_sp = esp;
t->ss1 = ss;
t->esp1 = esp;
@@ -246,24 +310,25 @@ int check_descriptor(unsigned long *d)
}
-void destroy_gdt(struct domain *d)
+void destroy_gdt(struct exec_domain *ed)
{
int i;
unsigned long pfn;
for ( i = 0; i < 16; i++ )
{
- if ( (pfn = l1_pgentry_to_pagenr(d->mm.perdomain_pt[i])) != 0 )
+ if ( (pfn = l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i])) != 0 )
put_page_and_type(&frame_table[pfn]);
- d->mm.perdomain_pt[i] = mk_l1_pgentry(0);
+ ed->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
}
}
-long set_gdt(struct domain *d,
+long set_gdt(struct exec_domain *ed,
unsigned long *frames,
unsigned int entries)
{
+ struct domain *d = ed->domain;
/* NB. There are 512 8-byte entries per GDT page. */
int i = 0, nr_pages = (entries + 511) / 512;
struct desc_struct *vgdt;
@@ -304,15 +369,15 @@ long set_gdt(struct domain *d,
unmap_domain_mem(vgdt);
/* Tear down the old GDT. */
- destroy_gdt(d);
+ destroy_gdt(ed);
/* Install the new GDT. */
for ( i = 0; i < nr_pages; i++ )
- d->mm.perdomain_pt[i] =
+ ed->arch.perdomain_ptes[i] =
mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
- SET_GDT_ADDRESS(d, GDT_VIRT_START);
- SET_GDT_ENTRIES(d, entries);
+ SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
+ SET_GDT_ENTRIES(ed, entries);
return 0;
@@ -335,12 +400,16 @@ long do_set_gdt(unsigned long *frame_list, unsigned int entries)
if ( copy_from_user(frames, frame_list, nr_pages * sizeof(unsigned long)) )
return -EFAULT;
+ LOCK_BIGLOCK(current->domain);
+
if ( (ret = set_gdt(current, frames, entries)) == 0 )
{
local_flush_tlb();
- __asm__ __volatile__ ("lgdt %0" : "=m" (*current->mm.gdt));
+ __asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
}
+ UNLOCK_BIGLOCK(current->domain);
+
return ret;
}
@@ -350,27 +419,36 @@ long do_update_descriptor(
{
unsigned long *gdt_pent, pfn = pa >> PAGE_SHIFT, d[2];
struct pfn_info *page;
+ struct exec_domain *ed;
long ret = -EINVAL;
d[0] = word1;
d[1] = word2;
- if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(d) )
+ LOCK_BIGLOCK(current->domain);
+
+ if ( (pa & 7) || (pfn >= max_page) || !check_descriptor(d) ) {
+ UNLOCK_BIGLOCK(current->domain);
return -EINVAL;
+ }
page = &frame_table[pfn];
- if ( unlikely(!get_page(page, current)) )
+ if ( unlikely(!get_page(page, current->domain)) ) {
+ UNLOCK_BIGLOCK(current->domain);
return -EINVAL;
+ }
/* Check if the given frame is in use in an unsafe context. */
switch ( page->u.inuse.type_info & PGT_type_mask )
{
case PGT_gdt_page:
/* Disallow updates of Xen-reserved descriptors in the current GDT. */
- if ( (l1_pgentry_to_pagenr(current->mm.perdomain_pt[0]) == pfn) &&
- (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
- (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
- goto out;
+ for_each_exec_domain(current->domain, ed) {
+ if ( (l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[0]) == pfn) &&
+ (((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
+ (((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
+ goto out;
+ }
if ( unlikely(!get_page_type(page, PGT_gdt_page)) )
goto out;
break;
@@ -395,6 +473,9 @@ long do_update_descriptor(
out:
put_page(page);
+
+ UNLOCK_BIGLOCK(current->domain);
+
return ret;
}
@@ -451,6 +532,11 @@ static void __memguard_change_range(void *p, unsigned long l, int guard)
}
}
+void memguard_guard_stack(void *p)
+{
+ memguard_guard_range(p, PAGE_SIZE);
+}
+
void memguard_guard_range(void *p, unsigned long l)
{
__memguard_change_range(p, l, 1);
@@ -462,14 +548,4 @@ void memguard_unguard_range(void *p, unsigned long l)
__memguard_change_range(p, l, 0);
}
-int memguard_is_guarded(void *p)
-{
- l1_pgentry_t *l1;
- l2_pgentry_t *l2;
- unsigned long _p = (unsigned long)p;
- l2 = &idle_pg_table[l2_table_offset(_p)];
- l1 = l2_pgentry_to_l1(*l2) + l1_table_offset(_p);
- return !(l1_pgentry_val(*l1) & _PAGE_PRESENT);
-}
-
#endif
diff --git a/xen/arch/x86/x86_32/seg_fixup.c b/xen/arch/x86/x86_32/seg_fixup.c
index cc4a97c195..8fcc011246 100644
--- a/xen/arch/x86/x86_32/seg_fixup.c
+++ b/xen/arch/x86/x86_32/seg_fixup.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* arch/x86/x86_32/seg_fixup.c
*
@@ -105,7 +106,7 @@ static unsigned char insn_decode[256] = {
*/
int get_baselimit(u16 seg, unsigned long *base, unsigned long *limit)
{
- struct domain *d = current;
+ struct exec_domain *d = current;
unsigned long *table, a, b;
int ldt = !!(seg & 4);
int idx = (seg >> 3) & 8191;
@@ -113,8 +114,8 @@ int get_baselimit(u16 seg, unsigned long *base, unsigned long *limit)
/* Get base and check limit. */
if ( ldt )
{
- table = (unsigned long *)LDT_VIRT_START;
- if ( idx >= d->mm.ldt_ents )
+ table = (unsigned long *)LDT_VIRT_START(d);
+ if ( idx >= d->arch.ldt_ents )
goto fail;
}
else /* gdt */
@@ -171,7 +172,7 @@ int linearise_address(u16 seg, unsigned long off, unsigned long *linear)
int fixup_seg(u16 seg, unsigned long offset)
{
- struct domain *d = current;
+ struct exec_domain *d = current;
unsigned long *table, a, b, base, limit;
int ldt = !!(seg & 4);
int idx = (seg >> 3) & 8191;
@@ -179,11 +180,11 @@ int fixup_seg(u16 seg, unsigned long offset)
/* Get base and check limit. */
if ( ldt )
{
- table = (unsigned long *)LDT_VIRT_START;
- if ( idx >= d->mm.ldt_ents )
+ table = (unsigned long *)LDT_VIRT_START(d);
+ if ( idx >= d->arch.ldt_ents )
{
DPRINTK("Segment %04x out of LDT range (%ld)\n",
- seg, d->mm.ldt_ents);
+ seg, d->arch.ldt_ents);
goto fail;
}
}
@@ -282,7 +283,7 @@ void *decode_reg(struct xen_regs *regs, u8 b)
*/
int gpf_emulate_4gb(struct xen_regs *regs)
{
- struct domain *d = current;
+ struct exec_domain *d = current;
trap_info_t *ti;
struct trap_bounce *tb;
u8 modrm, mod, reg, rm, decode;
@@ -292,7 +293,7 @@ int gpf_emulate_4gb(struct xen_regs *regs)
u32 disp32 = 0;
u8 *eip; /* ptr to instruction start */
u8 *pb, b; /* ptr into instr. / current instr. byte */
- unsigned int *pseg = NULL; /* segment for memory operand (NULL=default) */
+ unsigned long *pseg = NULL; /* segment for memory operand (NULL=default) */
/* WARNING: We only work for ring-3 segments. */
if ( unlikely(VM86_MODE(regs)) || unlikely(!RING_3(regs)) )
@@ -464,16 +465,16 @@ int gpf_emulate_4gb(struct xen_regs *regs)
perfc_incrc(seg_fixups);
/* If requested, give a callback on otherwise unused vector 15. */
- if ( VM_ASSIST(d, VMASST_TYPE_4gb_segments_notify) )
+ if ( VM_ASSIST(d->domain, VMASST_TYPE_4gb_segments_notify) )
{
- ti = &d->thread.traps[15];
- tb = &d->thread.trap_bounce;
+ ti = &d->arch.traps[15];
+ tb = &d->arch.trap_bounce;
tb->flags = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
tb->error_code = pb - eip;
tb->cs = ti->cs;
tb->eip = ti->address;
if ( TI_GET_IF(ti) )
- d->shared_info->vcpu_data[0].evtchn_upcall_mask = 1;
+ d->vcpu_info->evtchn_upcall_mask = 1;
}
return EXCRET_fault_fixed;
diff --git a/xen/arch/x86/x86_32/traps.c b/xen/arch/x86/x86_32/traps.c
new file mode 100644
index 0000000000..ec11beb5d0
--- /dev/null
+++ b/xen/arch/x86/x86_32/traps.c
@@ -0,0 +1,254 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/sched.h>
+#include <xen/lib.h>
+#include <xen/console.h>
+#include <xen/mm.h>
+#include <xen/irq.h>
+
+static int kstack_depth_to_print = 8*20;
+
+static inline int kernel_text_address(unsigned long addr)
+{
+ if (addr >= (unsigned long) &_stext &&
+ addr <= (unsigned long) &_etext)
+ return 1;
+ return 0;
+
+}
+
+void show_guest_stack(void)
+{
+ int i;
+ execution_context_t *ec = get_execution_context();
+ unsigned long *stack = (unsigned long *)ec->esp;
+ printk("Guest EIP is %lx\n ",ec->eip);
+
+ for ( i = 0; i < kstack_depth_to_print; i++ )
+ {
+ if ( ((long)stack & (STACK_SIZE-1)) == 0 )
+ break;
+ if ( i && ((i % 8) == 0) )
+ printk("\n ");
+ printk("%p ", *stack++);
+ }
+ printk("\n");
+
+}
+
+void show_trace(unsigned long *esp)
+{
+ unsigned long *stack, addr;
+ int i;
+
+ printk("Call Trace from ESP=%p:\n ", esp);
+ stack = esp;
+ i = 0;
+ while (((long) stack & (STACK_SIZE-1)) != 0) {
+ addr = *stack++;
+ if (kernel_text_address(addr)) {
+ if (i && ((i % 6) == 0))
+ printk("\n ");
+ printk("[<%p>] ", addr);
+ i++;
+ }
+ }
+ printk("\n");
+}
+
+void show_stack(unsigned long *esp)
+{
+ unsigned long *stack;
+ int i;
+
+ printk("Stack trace from ESP=%p:\n ", esp);
+
+ stack = esp;
+ for ( i = 0; i < kstack_depth_to_print; i++ )
+ {
+ if ( ((long)stack & (STACK_SIZE-1)) == 0 )
+ break;
+ if ( i && ((i % 8) == 0) )
+ printk("\n ");
+ if ( kernel_text_address(*stack) )
+ printk("[%p] ", *stack++);
+ else
+ printk("%p ", *stack++);
+ }
+ printk("\n");
+
+ show_trace( esp );
+}
+
+void show_registers(struct xen_regs *regs)
+{
+ unsigned long esp;
+ unsigned short ss, ds, es, fs, gs;
+
+ if ( GUEST_FAULT(regs) )
+ {
+ esp = regs->esp;
+ ss = regs->ss & 0xffff;
+ ds = regs->ds & 0xffff;
+ es = regs->es & 0xffff;
+ fs = regs->fs & 0xffff;
+ gs = regs->gs & 0xffff;
+ }
+ else
+ {
+ esp = (unsigned long)(&regs->esp);
+ ss = __HYPERVISOR_DS;
+ ds = __HYPERVISOR_DS;
+ es = __HYPERVISOR_DS;
+ fs = __HYPERVISOR_DS;
+ gs = __HYPERVISOR_DS;
+ }
+
+ printk("CPU: %d\nEIP: %04lx:[<%p>] \nEFLAGS: %p\n",
+ smp_processor_id(), 0xffff & regs->cs, regs->eip, regs->eflags);
+ printk("eax: %p ebx: %p ecx: %p edx: %p\n",
+ regs->eax, regs->ebx, regs->ecx, regs->edx);
+ printk("esi: %p edi: %p ebp: %p esp: %p\n",
+ regs->esi, regs->edi, regs->ebp, esp);
+ printk("ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n",
+ ds, es, fs, gs, ss);
+
+ show_stack((unsigned long *)&regs->esp);
+}
+
+void show_page_walk(unsigned long addr)
+{
+ unsigned long page;
+
+ if ( addr < PAGE_OFFSET )
+ return;
+
+ printk("Pagetable walk from %p:\n", addr);
+
+ page = l2_pgentry_val(idle_pg_table[l2_table_offset(addr)]);
+ printk(" L2 = %p %s\n", page, (page & _PAGE_PSE) ? "(4MB)" : "");
+ if ( !(page & _PAGE_PRESENT) || (page & _PAGE_PSE) )
+ return;
+
+ page &= PAGE_MASK;
+ page = ((unsigned long *) __va(page))[l1_table_offset(addr)];
+ printk(" L1 = %p\n", page);
+}
+
+#define DOUBLEFAULT_STACK_SIZE 1024
+static struct tss_struct doublefault_tss;
+static unsigned char doublefault_stack[DOUBLEFAULT_STACK_SIZE];
+
+asmlinkage void do_double_fault(void)
+{
+ struct tss_struct *tss = &doublefault_tss;
+ unsigned int cpu = ((tss->back_link>>3)-__FIRST_TSS_ENTRY)>>1;
+
+ /* Disable the NMI watchdog. It's useless now. */
+ watchdog_on = 0;
+
+ console_force_unlock();
+
+ /* Find information saved during fault and dump it to the console. */
+ tss = &init_tss[cpu];
+ printk("CPU: %d\nEIP: %04x:[<%08x>] \nEFLAGS: %08x\n",
+ cpu, tss->cs, tss->eip, tss->eflags);
+ printk("CR3: %08x\n", tss->__cr3);
+ printk("eax: %08x ebx: %08x ecx: %08x edx: %08x\n",
+ tss->eax, tss->ebx, tss->ecx, tss->edx);
+ printk("esi: %08x edi: %08x ebp: %08x esp: %08x\n",
+ tss->esi, tss->edi, tss->ebp, tss->esp);
+ printk("ds: %04x es: %04x fs: %04x gs: %04x ss: %04x\n",
+ tss->ds, tss->es, tss->fs, tss->gs, tss->ss);
+ printk("************************************\n");
+ printk("CPU%d DOUBLE FAULT -- system shutdown\n", cpu);
+ printk("System needs manual reset.\n");
+ printk("************************************\n");
+
+ /* Lock up the console to prevent spurious output from other CPUs. */
+ console_force_lock();
+
+ /* Wait for manual reset. */
+ for ( ; ; )
+ __asm__ __volatile__ ( "hlt" );
+}
+
+void __init doublefault_init(void)
+{
+ /*
+ * Make a separate task for double faults. This will get us debug output if
+ * we blow the kernel stack.
+ */
+ struct tss_struct *tss = &doublefault_tss;
+ memset(tss, 0, sizeof(*tss));
+ tss->ds = __HYPERVISOR_DS;
+ tss->es = __HYPERVISOR_DS;
+ tss->ss = __HYPERVISOR_DS;
+ tss->esp = (unsigned long)
+ &doublefault_stack[DOUBLEFAULT_STACK_SIZE];
+ tss->__cr3 = __pa(idle_pg_table);
+ tss->cs = __HYPERVISOR_CS;
+ tss->eip = (unsigned long)do_double_fault;
+ tss->eflags = 2;
+ tss->bitmap = IOBMP_INVALID_OFFSET;
+ _set_tssldt_desc(gdt_table+__DOUBLEFAULT_TSS_ENTRY,
+ (unsigned long)tss, 235, 9);
+
+ set_task_gate(TRAP_double_fault, __DOUBLEFAULT_TSS_ENTRY<<3);
+}
+
+void __init percpu_traps_init(void)
+{
+}
+
+long set_fast_trap(struct exec_domain *p, int idx)
+{
+ trap_info_t *ti;
+
+ /* Index 0 is special: it disables fast traps. */
+ if ( idx == 0 )
+ {
+ if ( p == current )
+ CLEAR_FAST_TRAP(&p->arch);
+ SET_DEFAULT_FAST_TRAP(&p->arch);
+ return 0;
+ }
+
+ /*
+ * We only fast-trap vectors 0x20-0x2f, and vector 0x80.
+ * The former range is used by Windows and MS-DOS.
+ * Vector 0x80 is used by Linux and the BSD variants.
+ */
+ if ( (idx != 0x80) && ((idx < 0x20) || (idx > 0x2f)) )
+ return -1;
+
+ ti = p->arch.traps + idx;
+
+ /*
+ * We can't virtualise interrupt gates, as there's no way to get
+ * the CPU to automatically clear the events_mask variable.
+ */
+ if ( TI_GET_IF(ti) )
+ return -1;
+
+ if ( p == current )
+ CLEAR_FAST_TRAP(&p->arch);
+
+ p->arch.fast_trap_idx = idx;
+ p->arch.fast_trap_desc.a = (ti->cs << 16) | (ti->address & 0xffff);
+ p->arch.fast_trap_desc.b =
+ (ti->address & 0xffff0000) | 0x8f00 | (TI_GET_DPL(ti)&3)<<13;
+
+ if ( p == current )
+ SET_FAST_TRAP(&p->arch);
+
+ return 0;
+}
+
+
+long do_set_fast_trap(int idx)
+{
+ return set_fast_trap(current, idx);
+}
diff --git a/xen/arch/x86/x86_32/usercopy.c b/xen/arch/x86/x86_32/usercopy.c
index df30b4849c..7e479bbee8 100644
--- a/xen/arch/x86/x86_32/usercopy.c
+++ b/xen/arch/x86/x86_32/usercopy.c
@@ -9,8 +9,6 @@
#include <xen/mm.h>
#include <asm/uaccess.h>
-#define might_sleep() ((void)0)
-
static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned long n)
{
#ifdef CONFIG_X86_INTEL_USERCOPY
@@ -22,93 +20,6 @@ static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned lon
#define movsl_is_ok(a1,a2,n) \
__movsl_is_ok((unsigned long)(a1),(unsigned long)(a2),(n))
-/*
- * Copy a null terminated string from userspace.
- */
-
-#define __do_strncpy_from_user(dst,src,count,res) \
-do { \
- int __d0, __d1, __d2; \
- __asm__ __volatile__( \
- " testl %1,%1\n" \
- " jz 2f\n" \
- "0: lodsb\n" \
- " stosb\n" \
- " testb %%al,%%al\n" \
- " jz 1f\n" \
- " decl %1\n" \
- " jnz 0b\n" \
- "1: subl %1,%0\n" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- "3: movl %5,%0\n" \
- " jmp 2b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 4\n" \
- " .long 0b,3b\n" \
- ".previous" \
- : "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
- "=&D" (__d2) \
- : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
- : "memory"); \
-} while (0)
-
-/**
- * __strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking.
- * @dst: Destination address, in kernel space. This buffer must be at
- * least @count bytes long.
- * @src: Source address, in user space.
- * @count: Maximum number of bytes to copy, including the trailing NUL.
- *
- * Copies a NUL-terminated string from userspace to kernel space.
- * Caller must check the specified block with access_ok() before calling
- * this function.
- *
- * On success, returns the length of the string (not including the trailing
- * NUL).
- *
- * If access to userspace fails, returns -EFAULT (some data may have been
- * copied).
- *
- * If @count is smaller than the length of the string, copies @count bytes
- * and returns @count.
- */
-long
-__strncpy_from_user(char *dst, const char __user *src, long count)
-{
- long res;
- __do_strncpy_from_user(dst, src, count, res);
- return res;
-}
-
-/**
- * strncpy_from_user: - Copy a NUL terminated string from userspace.
- * @dst: Destination address, in kernel space. This buffer must be at
- * least @count bytes long.
- * @src: Source address, in user space.
- * @count: Maximum number of bytes to copy, including the trailing NUL.
- *
- * Copies a NUL-terminated string from userspace to kernel space.
- *
- * On success, returns the length of the string (not including the trailing
- * NUL).
- *
- * If access to userspace fails, returns -EFAULT (some data may have been
- * copied).
- *
- * If @count is smaller than the length of the string, copies @count bytes
- * and returns @count.
- */
-long
-strncpy_from_user(char *dst, const char __user *src, long count)
-{
- long res = -EFAULT;
- if (access_ok(VERIFY_READ, src, 1))
- __do_strncpy_from_user(dst, src, count, res);
- return res;
-}
-
/*
* Zero Userspace
@@ -148,7 +59,6 @@ do { \
unsigned long
clear_user(void __user *to, unsigned long n)
{
- might_sleep();
if (access_ok(VERIFY_WRITE, to, n))
__do_clear_user(to, n);
return n;
@@ -172,49 +82,6 @@ __clear_user(void __user *to, unsigned long n)
return n;
}
-/**
- * strlen_user: - Get the size of a string in user space.
- * @s: The string to measure.
- * @n: The maximum valid length
- *
- * Get the size of a NUL-terminated string in user space.
- *
- * Returns the size of the string INCLUDING the terminating NUL.
- * On exception, returns 0.
- * If the string is too long, returns a value greater than @n.
- */
-long strnlen_user(const char __user *s, long n)
-{
- unsigned long mask = -__addr_ok(s);
- unsigned long res, tmp;
-
- might_sleep();
-
- __asm__ __volatile__(
- " testl %0, %0\n"
- " jz 3f\n"
- " andl %0,%%ecx\n"
- "0: repne; scasb\n"
- " setne %%al\n"
- " subl %%ecx,%0\n"
- " addl %0,%%eax\n"
- "1:\n"
- ".section .fixup,\"ax\"\n"
- "2: xorl %%eax,%%eax\n"
- " jmp 1b\n"
- "3: movb $1,%%al\n"
- " jmp 1b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,2b\n"
- ".previous"
- :"=r" (n), "=D" (s), "=a" (res), "=c" (tmp)
- :"0" (n), "1" (s), "2" (0), "3" (mask)
- :"cc");
- return res & mask;
-}
-
#ifdef CONFIG_X86_INTEL_USERCOPY
static unsigned long
__copy_user_intel(void __user *to, const void *from, unsigned long size)
@@ -543,12 +410,10 @@ __copy_from_user_ll(void *to, const void __user *from, unsigned long n)
unsigned long
copy_to_user(void __user *to, const void *from, unsigned long n)
{
- might_sleep();
if (access_ok(VERIFY_WRITE, to, n))
n = __copy_to_user(to, from, n);
return n;
}
-EXPORT_SYMBOL(copy_to_user);
/**
* copy_from_user: - Copy a block of data from user space.
@@ -569,11 +434,9 @@ EXPORT_SYMBOL(copy_to_user);
unsigned long
copy_from_user(void *to, const void __user *from, unsigned long n)
{
- might_sleep();
if (access_ok(VERIFY_READ, from, n))
n = __copy_from_user(to, from, n);
else
memset(to, 0, n);
return n;
}
-EXPORT_SYMBOL(copy_from_user);
diff --git a/xen/arch/x86/x86_32/xen.lds b/xen/arch/x86/x86_32/xen.lds
index 298c9fee4d..604b0e6211 100644
--- a/xen/arch/x86/x86_32/xen.lds
+++ b/xen/arch/x86/x86_32/xen.lds
@@ -25,12 +25,12 @@ SECTIONS
.rodata : { *(.rodata) *(.rodata.*) } :text
.kstrtab : { *(.kstrtab) } :text
- . = ALIGN(16); /* Exception table */
+ . = ALIGN(32); /* Exception table */
__start___ex_table = .;
__ex_table : { *(__ex_table) } :text
__stop___ex_table = .;
- . = ALIGN(16); /* Pre-exception table */
+ . = ALIGN(32); /* Pre-exception table */
__start___pre_ex_table = .;
__pre_ex_table : { *(__pre_ex_table) } :text
__stop___pre_ex_table = .;
@@ -57,7 +57,7 @@ SECTIONS
__init_begin = .;
.text.init : { *(.text.init) } :text
.data.init : { *(.data.init) } :text
- . = ALIGN(16);
+ . = ALIGN(32);
__setup_start = .;
.setup.init : { *(.setup.init) } :text
__setup_end = .;
diff --git a/xen/arch/x86/x86_64/asm-offsets.c b/xen/arch/x86/x86_64/asm-offsets.c
index 2e6c3b396e..2dd6055f0a 100644
--- a/xen/arch/x86/x86_64/asm-offsets.c
+++ b/xen/arch/x86/x86_64/asm-offsets.c
@@ -30,7 +30,8 @@ void __dummy__(void)
OFFSET(XREGS_rdx, struct xen_regs, rdx);
OFFSET(XREGS_rsi, struct xen_regs, rsi);
OFFSET(XREGS_rdi, struct xen_regs, rdi);
- OFFSET(XREGS_orig_rax, struct xen_regs, orig_rax);
+ OFFSET(XREGS_error_code, struct xen_regs, error_code);
+ OFFSET(XREGS_entry_vector, struct xen_regs, entry_vector);
OFFSET(XREGS_rip, struct xen_regs, rip);
OFFSET(XREGS_cs, struct xen_regs, cs);
OFFSET(XREGS_eflags, struct xen_regs, eflags);
@@ -38,14 +39,14 @@ void __dummy__(void)
OFFSET(XREGS_ss, struct xen_regs, ss);
BLANK();
- OFFSET(DOMAIN_processor, struct domain, processor);
- OFFSET(DOMAIN_shared_info, struct domain, shared_info);
- OFFSET(DOMAIN_event_sel, struct domain, thread.event_selector);
- OFFSET(DOMAIN_event_addr, struct domain, thread.event_address);
- OFFSET(DOMAIN_failsafe_sel, struct domain, thread.failsafe_selector);
- OFFSET(DOMAIN_failsafe_addr, struct domain, thread.failsafe_address);
- OFFSET(DOMAIN_trap_bounce, struct domain, thread.trap_bounce);
- OFFSET(DOMAIN_thread_flags, struct domain, thread.flags);
+ OFFSET(EDOMAIN_processor, struct exec_domain, processor);
+ OFFSET(EDOMAIN_vcpu_info, struct exec_domain, vcpu_info);
+ OFFSET(EDOMAIN_event_sel, struct exec_domain, arch.event_selector);
+ OFFSET(EDOMAIN_event_addr, struct exec_domain, arch.event_address);
+ OFFSET(EDOMAIN_failsafe_sel, struct exec_domain, arch.failsafe_selector);
+ OFFSET(EDOMAIN_failsafe_addr, struct exec_domain, arch.failsafe_address);
+ OFFSET(EDOMAIN_trap_bounce, struct exec_domain, arch.trap_bounce);
+ OFFSET(EDOMAIN_thread_flags, struct exec_domain, arch.flags);
BLANK();
OFFSET(SHINFO_upcall_pending, shared_info_t,
diff --git a/xen/arch/x86/x86_64/domain_build.c b/xen/arch/x86/x86_64/domain_build.c
new file mode 100644
index 0000000000..bd15fe9eeb
--- /dev/null
+++ b/xen/arch/x86/x86_64/domain_build.c
@@ -0,0 +1,412 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+/******************************************************************************
+ * domain_build.c
+ *
+ * Copyright (c) 2002-2005, K A Fraser
+ */
+
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/sched.h>
+#include <xen/smp.h>
+#include <xen/delay.h>
+#include <asm/regs.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/desc.h>
+#include <asm/i387.h>
+#include <xen/event.h>
+#include <xen/elf.h>
+#include <xen/kernel.h>
+
+/* Allow ring-3 access in long mode as guest cannot use ring 1. */
+#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_USER)
+#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+#define L3_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+#define L4_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+
+#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
+#define round_pgdown(_p) ((_p)&PAGE_MASK)
+
+int construct_dom0(struct domain *d,
+ unsigned long alloc_start,
+ unsigned long alloc_end,
+ unsigned long _image_start, unsigned long image_len,
+ unsigned long _initrd_start, unsigned long initrd_len,
+ char *cmdline)
+{
+ char *dst;
+ int i, rc;
+ unsigned long pfn, mfn;
+ unsigned long nr_pages = (alloc_end - alloc_start) >> PAGE_SHIFT;
+ unsigned long nr_pt_pages;
+ unsigned long count;
+ l4_pgentry_t *l4tab = NULL, *l4start = NULL;
+ l3_pgentry_t *l3tab = NULL, *l3start = NULL;
+ l2_pgentry_t *l2tab = NULL, *l2start = NULL;
+ l1_pgentry_t *l1tab = NULL, *l1start = NULL;
+ struct pfn_info *page = NULL;
+ start_info_t *si;
+ struct exec_domain *ed = d->exec_domain[0];
+ char *image_start = __va(_image_start);
+ char *initrd_start = __va(_initrd_start);
+
+ /*
+ * This fully describes the memory layout of the initial domain. All
+ * *_start address are page-aligned, except v_start (and v_end) which are
+ * superpage-aligned.
+ */
+ struct domain_setup_info dsi;
+ unsigned long vinitrd_start;
+ unsigned long vinitrd_end;
+ unsigned long vphysmap_start;
+ unsigned long vphysmap_end;
+ unsigned long vstartinfo_start;
+ unsigned long vstartinfo_end;
+ unsigned long vstack_start;
+ unsigned long vstack_end;
+ unsigned long vpt_start;
+ unsigned long vpt_end;
+ unsigned long v_end;
+
+ /* Machine address of next candidate page-table page. */
+ unsigned long mpt_alloc;
+
+ extern void physdev_init_dom0(struct domain *);
+
+ /* Sanity! */
+ if ( d->id != 0 )
+ BUG();
+ if ( test_bit(DF_CONSTRUCTED, &d->d_flags) )
+ BUG();
+
+ memset(&dsi, 0, sizeof(struct domain_setup_info));
+
+ printk("*** LOADING DOMAIN 0 ***\n");
+
+ /*
+ * This is all a bit grim. We've moved the modules to the "safe" physical
+ * memory region above MAP_DIRECTMAP_ADDRESS (48MB). Later in this
+ * routine we're going to copy it down into the region that's actually
+ * been allocated to domain 0. This is highly likely to be overlapping, so
+ * we use a forward copy.
+ *
+ * MAP_DIRECTMAP_ADDRESS should be safe. The worst case is a machine with
+ * 4GB and lots of network/disk cards that allocate loads of buffers.
+ * We'll have to revisit this if we ever support PAE (64GB).
+ */
+
+ rc = parseelfimage(image_start, image_len, &dsi);
+ if ( rc != 0 )
+ return rc;
+
+ /* Set up domain options */
+ if ( dsi.use_writable_pagetables )
+ vm_assist(d, VMASST_CMD_enable, VMASST_TYPE_writable_pagetables);
+
+ /* Align load address to 4MB boundary. */
+ dsi.v_start &= ~((1UL<<22)-1);
+
+ /*
+ * Why do we need this? The number of page-table frames depends on the
+ * size of the bootstrap address space. But the size of the address space
+ * depends on the number of page-table frames (since each one is mapped
+ * read-only). We have a pair of simultaneous equations in two unknowns,
+ * which we solve by exhaustive search.
+ */
+ vinitrd_start = round_pgup(dsi.v_kernend);
+ vinitrd_end = vinitrd_start + initrd_len;
+ vphysmap_start = round_pgup(vinitrd_end);
+ vphysmap_end = vphysmap_start + (nr_pages * sizeof(unsigned long));
+ vpt_start = round_pgup(vphysmap_end);
+ for ( nr_pt_pages = 2; ; nr_pt_pages++ )
+ {
+ vpt_end = vpt_start + (nr_pt_pages * PAGE_SIZE);
+ vstartinfo_start = vpt_end;
+ vstartinfo_end = vstartinfo_start + PAGE_SIZE;
+ vstack_start = vstartinfo_end;
+ vstack_end = vstack_start + PAGE_SIZE;
+ v_end = (vstack_end + (1UL<<22)-1) & ~((1UL<<22)-1);
+ if ( (v_end - vstack_end) < (512UL << 10) )
+ v_end += 1UL << 22; /* Add extra 4MB to get >= 512kB padding. */
+#define NR(_l,_h,_s) \
+ (((((_h) + ((1UL<<(_s))-1)) & ~((1UL<<(_s))-1)) - \
+ ((_l) & ~((1UL<<(_s))-1))) >> (_s))
+ if ( (1 + /* # L4 */
+ NR(dsi.v_start, v_end, L4_PAGETABLE_SHIFT) + /* # L3 */
+ NR(dsi.v_start, v_end, L3_PAGETABLE_SHIFT) + /* # L2 */
+ NR(dsi.v_start, v_end, L2_PAGETABLE_SHIFT)) /* # L1 */
+ <= nr_pt_pages )
+ break;
+ }
+
+ printk("PHYSICAL MEMORY ARRANGEMENT:\n"
+ " Kernel image: %p->%p\n"
+ " Initrd image: %p->%p\n"
+ " Dom0 alloc.: %p->%p\n",
+ _image_start, _image_start + image_len,
+ _initrd_start, _initrd_start + initrd_len,
+ alloc_start, alloc_end);
+ printk("VIRTUAL MEMORY ARRANGEMENT:\n"
+ " Loaded kernel: %p->%p\n"
+ " Init. ramdisk: %p->%p\n"
+ " Phys-Mach map: %p->%p\n"
+ " Page tables: %p->%p\n"
+ " Start info: %p->%p\n"
+ " Boot stack: %p->%p\n"
+ " TOTAL: %p->%p\n",
+ dsi.v_kernstart, dsi.v_kernend,
+ vinitrd_start, vinitrd_end,
+ vphysmap_start, vphysmap_end,
+ vpt_start, vpt_end,
+ vstartinfo_start, vstartinfo_end,
+ vstack_start, vstack_end,
+ dsi.v_start, v_end);
+ printk(" ENTRY ADDRESS: %p\n", dsi.v_kernentry);
+
+ if ( (v_end - dsi.v_start) > (nr_pages * PAGE_SIZE) )
+ {
+ printk("Initial guest OS requires too much space\n"
+ "(%luMB is greater than %luMB limit)\n",
+ (v_end-dsi.v_start)>>20, (nr_pages<<PAGE_SHIFT)>>20);
+ return -ENOMEM;
+ }
+
+ /* Overlap with Xen protected area? */
+ if ( (dsi.v_start < HYPERVISOR_VIRT_END) &&
+ (v_end > HYPERVISOR_VIRT_START) )
+ {
+ printk("DOM0 image overlaps with Xen private area.\n");
+ return -EINVAL;
+ }
+
+ /* Paranoia: scrub DOM0's memory allocation. */
+ printk("Scrubbing DOM0 RAM: ");
+ dst = __va(alloc_start);
+ while ( __pa(dst) < alloc_end )
+ {
+#define SCRUB_BYTES (100 * 1024 * 1024) /* 100MB */
+ printk(".");
+ touch_nmi_watchdog();
+ if ( (alloc_end - __pa(dst)) > SCRUB_BYTES )
+ {
+ memset(dst, 0, SCRUB_BYTES);
+ dst += SCRUB_BYTES;
+ }
+ else
+ {
+ memset(dst, 0, alloc_end - __pa(dst));
+ break;
+ }
+ }
+ printk("done.\n");
+
+ /* Construct a frame-allocation list for the initial domain. */
+ for ( mfn = (alloc_start>>PAGE_SHIFT);
+ mfn < (alloc_end>>PAGE_SHIFT);
+ mfn++ )
+ {
+ page = &frame_table[mfn];
+ page_set_owner(page, d);
+ page->u.inuse.type_info = 0;
+ page->count_info = PGC_allocated | 1;
+ list_add_tail(&page->list, &d->page_list);
+ d->tot_pages++; d->max_pages++;
+ }
+
+ mpt_alloc = (vpt_start - dsi.v_start) + alloc_start;
+
+ SET_GDT_ENTRIES(ed, DEFAULT_GDT_ENTRIES);
+ SET_GDT_ADDRESS(ed, DEFAULT_GDT_ADDRESS);
+
+ /*
+ * We're basically forcing default RPLs to 1, so that our "what privilege
+ * level are we returning to?" logic works.
+ */
+ ed->arch.failsafe_selector = FLAT_GUESTOS_CS;
+ ed->arch.event_selector = FLAT_GUESTOS_CS;
+ ed->arch.guestos_ss = FLAT_GUESTOS_SS;
+ for ( i = 0; i < 256; i++ )
+ ed->arch.traps[i].cs = FLAT_GUESTOS_CS;
+
+ /* WARNING: The new domain must have its 'processor' field filled in! */
+ phys_to_page(mpt_alloc)->u.inuse.type_info = PGT_l4_page_table;
+ l4start = l4tab = __va(mpt_alloc); mpt_alloc += PAGE_SIZE;
+ memcpy(l4tab, &idle_pg_table[0], PAGE_SIZE);
+ l4tab[l4_table_offset(LINEAR_PT_VIRT_START)] =
+ mk_l4_pgentry(__pa(l4start) | __PAGE_HYPERVISOR);
+ l4tab[l4_table_offset(PERDOMAIN_VIRT_START)] =
+ mk_l4_pgentry(__pa(d->arch.mm_perdomain_pt) | __PAGE_HYPERVISOR);
+ ed->arch.pagetable = mk_pagetable(__pa(l4start));
+
+ l4tab += l4_table_offset(dsi.v_start);
+ mfn = alloc_start >> PAGE_SHIFT;
+ for ( count = 0; count < ((v_end-dsi.v_start)>>PAGE_SHIFT); count++ )
+ {
+ if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) )
+ {
+ phys_to_page(mpt_alloc)->u.inuse.type_info = PGT_l1_page_table;
+ l1start = l1tab = __va(mpt_alloc); mpt_alloc += PAGE_SIZE;
+ clear_page(l1tab);
+ if ( count == 0 )
+ l1tab += l1_table_offset(dsi.v_start);
+ if ( !((unsigned long)l2tab & (PAGE_SIZE-1)) )
+ {
+ phys_to_page(mpt_alloc)->u.inuse.type_info = PGT_l2_page_table;
+ l2start = l2tab = __va(mpt_alloc); mpt_alloc += PAGE_SIZE;
+ clear_page(l2tab);
+ if ( count == 0 )
+ l2tab += l2_table_offset(dsi.v_start);
+ if ( !((unsigned long)l3tab & (PAGE_SIZE-1)) )
+ {
+ phys_to_page(mpt_alloc)->u.inuse.type_info =
+ PGT_l3_page_table;
+ l3start = l3tab = __va(mpt_alloc); mpt_alloc += PAGE_SIZE;
+ clear_page(l3tab);
+ if ( count == 0 )
+ l3tab += l3_table_offset(dsi.v_start);
+ *l4tab++ = mk_l4_pgentry(__pa(l3start) | L4_PROT);
+ }
+ *l3tab++ = mk_l3_pgentry(__pa(l2start) | L3_PROT);
+ }
+ *l2tab++ = mk_l2_pgentry(__pa(l1start) | L2_PROT);
+ }
+ *l1tab++ = mk_l1_pgentry((mfn << PAGE_SHIFT) | L1_PROT);
+
+ page = &frame_table[mfn];
+ if ( (page->u.inuse.type_info == 0) &&
+ !get_page_and_type(page, d, PGT_writable_page) )
+ BUG();
+
+ mfn++;
+ }
+
+ /* Pages that are part of page tables must be read only. */
+ l4tab = l4start + l4_table_offset(vpt_start);
+ l3start = l3tab = l4_pgentry_to_l3(*l4tab);
+ l3tab += l3_table_offset(vpt_start);
+ l2start = l2tab = l3_pgentry_to_l2(*l3tab);
+ l2tab += l2_table_offset(vpt_start);
+ l1start = l1tab = l2_pgentry_to_l1(*l2tab);
+ l1tab += l1_table_offset(vpt_start);
+ for ( count = 0; count < nr_pt_pages; count++ )
+ {
+ *l1tab = mk_l1_pgentry(l1_pgentry_val(*l1tab) & ~_PAGE_RW);
+ page = &frame_table[l1_pgentry_to_pagenr(*l1tab)];
+
+ /* Read-only mapping + PGC_allocated + page-table page. */
+ page->count_info = PGC_allocated | 3;
+ page->u.inuse.type_info |= PGT_validated | 1;
+
+ /* Top-level p.t. is pinned. */
+ if ( (page->u.inuse.type_info & PGT_type_mask) == PGT_l4_page_table )
+ {
+ page->count_info += 1;
+ page->u.inuse.type_info += 1 | PGT_pinned;
+ }
+
+ /* Iterate. */
+ if ( !((unsigned long)++l1tab & (PAGE_SIZE - 1)) )
+ {
+ if ( !((unsigned long)++l2tab & (PAGE_SIZE - 1)) )
+ {
+ if ( !((unsigned long)++l3tab & (PAGE_SIZE - 1)) )
+ l3start = l3tab = l4_pgentry_to_l3(*++l4tab);
+ l2start = l2tab = l3_pgentry_to_l2(*l3tab);
+ }
+ l1start = l1tab = l2_pgentry_to_l1(*l2tab);
+ }
+ }
+
+ /* Set up shared-info area. */
+ update_dom_time(d);
+ d->shared_info->domain_time = 0;
+ /* Mask all upcalls... */
+ for ( i = 0; i < MAX_VIRT_CPUS; i++ )
+ d->shared_info->vcpu_data[i].evtchn_upcall_mask = 1;
+ d->shared_info->n_vcpu = smp_num_cpus;
+
+ /* Install the new page tables. */
+ __cli();
+ write_ptbase(ed);
+
+ /* Copy the OS image. */
+ (void)loadelfimage(image_start);
+
+ /* Copy the initial ramdisk. */
+ if ( initrd_len != 0 )
+ memcpy((void *)vinitrd_start, initrd_start, initrd_len);
+
+ /* Set up start info area. */
+ si = (start_info_t *)vstartinfo_start;
+ memset(si, 0, PAGE_SIZE);
+ si->nr_pages = d->tot_pages;
+ si->shared_info = virt_to_phys(d->shared_info);
+ si->flags = SIF_PRIVILEGED | SIF_INITDOMAIN;
+ si->pt_base = vpt_start;
+ si->nr_pt_frames = nr_pt_pages;
+ si->mfn_list = vphysmap_start;
+
+ /* Write the phys->machine and machine->phys table entries. */
+ for ( pfn = 0; pfn < d->tot_pages; pfn++ )
+ {
+ mfn = pfn + (alloc_start>>PAGE_SHIFT);
+#ifndef NDEBUG
+#define REVERSE_START ((v_end - dsi.v_start) >> PAGE_SHIFT)
+ if ( pfn > REVERSE_START )
+ mfn = (alloc_end>>PAGE_SHIFT) - (pfn - REVERSE_START);
+#endif
+ ((unsigned long *)vphysmap_start)[pfn] = mfn;
+ machine_to_phys_mapping[mfn] = pfn;
+ }
+
+ if ( initrd_len != 0 )
+ {
+ si->mod_start = vinitrd_start;
+ si->mod_len = initrd_len;
+ printk("Initrd len 0x%lx, start at 0x%p\n",
+ si->mod_len, si->mod_start);
+ }
+
+ dst = si->cmd_line;
+ if ( cmdline != NULL )
+ {
+ for ( i = 0; i < 255; i++ )
+ {
+ if ( cmdline[i] == '\0' )
+ break;
+ *dst++ = cmdline[i];
+ }
+ }
+ *dst = '\0';
+
+ /* Reinstate the caller's page tables. */
+ write_ptbase(current);
+ __sti();
+
+ /* DOM0 gets access to everything. */
+ physdev_init_dom0(d);
+
+ set_bit(DF_CONSTRUCTED, &d->d_flags);
+
+ new_thread(ed, dsi.v_kernentry, vstack_end, vstartinfo_start);
+
+ return 0;
+}
+
+int elf_sanity_check(Elf_Ehdr *ehdr)
+{
+ if ( !IS_ELF(*ehdr) ||
+ (ehdr->e_ident[EI_CLASS] != ELFCLASS64) ||
+ (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) ||
+ (ehdr->e_type != ET_EXEC) ||
+ (ehdr->e_machine != EM_X86_64) )
+ {
+ printk("DOM0 image is not x86/64-compatible executable Elf image.\n");
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/xen/arch/x86/x86_64/entry.S b/xen/arch/x86/x86_64/entry.S
index e69de29bb2..ad1544092b 100644
--- a/xen/arch/x86/x86_64/entry.S
+++ b/xen/arch/x86/x86_64/entry.S
@@ -0,0 +1,190 @@
+/*
+ * Hypercall and fault low-level handling routines.
+ *
+ * Copyright (c) 2005, K A Fraser
+ */
+
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/softirq.h>
+#include <asm/asm_defns.h>
+#include <asm/apicdef.h>
+#include <public/xen.h>
+
+ENTRY(hypercall)
+ movl $0x0833,8(%rsp)
+ pushq %r11
+ pushq $0x082b
+ pushq %rcx
+ pushq $0
+ SAVE_ALL
+ andq $(NR_hypercalls-1),%rax
+ leaq SYMBOL_NAME(exception_table)(%rip),%rcx
+ callq *(%rcx,%rax,8)
+ RESTORE_ALL
+ addq $8,%rsp
+ popq %rcx
+ addq $8,%rsp
+ popq %r11
+ cli
+ popq %rsp
+ sysretq
+
+ENTRY(ret_from_intr)
+restore_all_xen:
+ RESTORE_ALL
+ addq $8,%rsp
+ iretq
+
+error_code:
+ SAVE_ALL
+ movq %rsp,%rdi
+ movl XREGS_entry_vector(%rsp),%eax
+ leaq SYMBOL_NAME(exception_table)(%rip),%rdx
+ callq *(%rdx,%rax,8)
+ jmp restore_all_xen
+
+ENTRY(divide_error)
+ pushq $0
+ movl $TRAP_divide_error,4(%rsp)
+ jmp error_code
+
+ENTRY(coprocessor_error)
+ pushq $0
+ movl $TRAP_copro_error,4(%rsp)
+ jmp error_code
+
+ENTRY(simd_coprocessor_error)
+ pushq $0
+ movl $TRAP_simd_error,4(%rsp)
+ jmp error_code
+
+ENTRY(device_not_available)
+ pushq $0
+ movl $TRAP_no_device,4(%rsp)
+ jmp error_code
+
+ENTRY(debug)
+ pushq $0
+ movl $TRAP_debug,4(%rsp)
+ jmp error_code
+
+ENTRY(int3)
+ pushq $0
+ movl $TRAP_int3,4(%rsp)
+ jmp error_code
+
+ENTRY(overflow)
+ pushq $0
+ movl $TRAP_overflow,4(%rsp)
+ jmp error_code
+
+ENTRY(bounds)
+ pushq $0
+ movl $TRAP_bounds,4(%rsp)
+ jmp error_code
+
+ENTRY(invalid_op)
+ pushq $0
+ movl $TRAP_invalid_op,4(%rsp)
+ jmp error_code
+
+ENTRY(coprocessor_segment_overrun)
+ pushq $0
+ movl $TRAP_copro_seg,4(%rsp)
+ jmp error_code
+
+ENTRY(invalid_TSS)
+ movl $TRAP_invalid_tss,4(%rsp)
+ jmp error_code
+
+ENTRY(segment_not_present)
+ movl $TRAP_no_segment,4(%rsp)
+ jmp error_code
+
+ENTRY(stack_segment)
+ movl $TRAP_stack_error,4(%rsp)
+ jmp error_code
+
+ENTRY(general_protection)
+ movl $TRAP_gp_fault,4(%rsp)
+ jmp error_code
+
+ENTRY(alignment_check)
+ movl $TRAP_alignment_check,4(%rsp)
+ jmp error_code
+
+ENTRY(page_fault)
+ movl $TRAP_page_fault,4(%rsp)
+ jmp error_code
+
+ENTRY(machine_check)
+ pushq $0
+ movl $TRAP_machine_check,4(%rsp)
+ jmp error_code
+
+ENTRY(spurious_interrupt_bug)
+ pushq $0
+ movl $TRAP_spurious_int,4(%rsp)
+ jmp error_code
+
+ENTRY(double_fault)
+ movl $TRAP_double_fault,4(%rsp)
+ jmp error_code
+
+ENTRY(nmi)
+ iretq
+
+.data
+
+ENTRY(exception_table)
+ .quad SYMBOL_NAME(do_divide_error)
+ .quad SYMBOL_NAME(do_debug)
+ .quad 0 # nmi
+ .quad SYMBOL_NAME(do_int3)
+ .quad SYMBOL_NAME(do_overflow)
+ .quad SYMBOL_NAME(do_bounds)
+ .quad SYMBOL_NAME(do_invalid_op)
+ .quad SYMBOL_NAME(math_state_restore)
+ .quad SYMBOL_NAME(do_double_fault)
+ .quad SYMBOL_NAME(do_coprocessor_segment_overrun)
+ .quad SYMBOL_NAME(do_invalid_TSS)
+ .quad SYMBOL_NAME(do_segment_not_present)
+ .quad SYMBOL_NAME(do_stack_segment)
+ .quad SYMBOL_NAME(do_general_protection)
+ .quad SYMBOL_NAME(do_page_fault)
+ .quad SYMBOL_NAME(do_spurious_interrupt_bug)
+ .quad SYMBOL_NAME(do_coprocessor_error)
+ .quad SYMBOL_NAME(do_alignment_check)
+ .quad SYMBOL_NAME(do_machine_check)
+ .quad SYMBOL_NAME(do_simd_coprocessor_error)
+
+ENTRY(hypercall_table)
+ .quad SYMBOL_NAME(do_set_trap_table) /* 0 */
+ .quad SYMBOL_NAME(do_mmu_update)
+ .quad SYMBOL_NAME(do_set_gdt)
+ .quad SYMBOL_NAME(do_stack_switch)
+ .quad SYMBOL_NAME(do_set_callbacks)
+ .quad SYMBOL_NAME(do_fpu_taskswitch) /* 5 */
+ .quad SYMBOL_NAME(do_sched_op)
+ .quad SYMBOL_NAME(do_dom0_op)
+ .quad SYMBOL_NAME(do_set_debugreg)
+ .quad SYMBOL_NAME(do_get_debugreg)
+ .quad SYMBOL_NAME(do_update_descriptor) /* 10 */
+ .quad SYMBOL_NAME(do_ni_hypercall) # do_set_fast_trap
+ .quad SYMBOL_NAME(do_dom_mem_op)
+ .quad SYMBOL_NAME(do_multicall)
+ .quad SYMBOL_NAME(do_update_va_mapping)
+ .quad SYMBOL_NAME(do_set_timer_op) /* 15 */
+ .quad SYMBOL_NAME(do_event_channel_op)
+ .quad SYMBOL_NAME(do_xen_version)
+ .quad SYMBOL_NAME(do_console_io)
+ .quad SYMBOL_NAME(do_physdev_op)
+ .quad SYMBOL_NAME(do_grant_table_op) /* 20 */
+ .quad SYMBOL_NAME(do_vm_assist)
+ .quad SYMBOL_NAME(do_update_va_mapping_otherdomain)
+ .quad SYMBOL_NAME(do_ni_hypercall) # do_switch_vm86
+ .quad SYMBOL_NAME(do_boot_vcpu)
+ .rept NR_hypercalls-((.-hypercall_table)/4)
+ .quad SYMBOL_NAME(do_ni_hypercall)
+ .endr
diff --git a/xen/arch/x86/x86_64/mm.c b/xen/arch/x86/x86_64/mm.c
index c7bcb17805..bf6927f019 100644
--- a/xen/arch/x86/x86_64/mm.c
+++ b/xen/arch/x86/x86_64/mm.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* arch/x86/x86_64/mm.c
*
@@ -27,71 +28,189 @@
#include <asm/fixmap.h>
#include <asm/domain_page.h>
-static inline void set_pte_phys(unsigned long vaddr,
- l1_pgentry_t entry)
+void *safe_page_alloc(void)
{
- l4_pgentry_t *l4ent;
- l3_pgentry_t *l3ent;
- l2_pgentry_t *l2ent;
- l1_pgentry_t *l1ent;
-
- l4ent = &idle_pg_table[l4_table_offset(vaddr)];
- l3ent = l4_pgentry_to_l3(*l4ent) + l3_table_offset(vaddr);
- l2ent = l3_pgentry_to_l2(*l3ent) + l2_table_offset(vaddr);
- l1ent = l2_pgentry_to_l1(*l2ent) + l1_table_offset(vaddr);
- *l1ent = entry;
-
- /* It's enough to flush this one mapping. */
- __flush_tlb_one(vaddr);
+ extern int early_boot;
+ if ( early_boot )
+ return __va(alloc_boot_pages(PAGE_SIZE, PAGE_SIZE));
+ return (void *)alloc_xenheap_page();
}
-
-void __set_fixmap(enum fixed_addresses idx,
- l1_pgentry_t entry)
+/* Map physical byte range (@p, @p+@s) at virt address @v in pagetable @pt. */
+int map_pages(
+ pagetable_t *pt,
+ unsigned long v,
+ unsigned long p,
+ unsigned long s,
+ unsigned long flags)
{
- unsigned long address = fix_to_virt(idx);
+ l4_pgentry_t *pl4e;
+ l3_pgentry_t *pl3e;
+ l2_pgentry_t *pl2e;
+ l1_pgentry_t *pl1e;
+ void *newpg;
- if ( likely(idx < __end_of_fixed_addresses) )
- set_pte_phys(address, entry);
- else
- printk("Invalid __set_fixmap\n");
+ while ( s != 0 )
+ {
+ pl4e = &pt[l4_table_offset(v)];
+ if ( !(l4_pgentry_val(*pl4e) & _PAGE_PRESENT) )
+ {
+ newpg = safe_page_alloc();
+ clear_page(newpg);
+ *pl4e = mk_l4_pgentry(__pa(newpg) | __PAGE_HYPERVISOR);
+ }
+
+ pl3e = l4_pgentry_to_l3(*pl4e) + l3_table_offset(v);
+ if ( !(l3_pgentry_val(*pl3e) & _PAGE_PRESENT) )
+ {
+ newpg = safe_page_alloc();
+ clear_page(newpg);
+ *pl3e = mk_l3_pgentry(__pa(newpg) | __PAGE_HYPERVISOR);
+ }
+
+ pl2e = l3_pgentry_to_l2(*pl3e) + l2_table_offset(v);
+
+ if ( ((s|v|p) & ((1<<L2_PAGETABLE_SHIFT)-1)) == 0 )
+ {
+ /* Super-page mapping. */
+ if ( (l2_pgentry_val(*pl2e) & _PAGE_PRESENT) )
+ __flush_tlb_pge();
+ *pl2e = mk_l2_pgentry(p|flags|_PAGE_PSE);
+
+ v += 1 << L2_PAGETABLE_SHIFT;
+ p += 1 << L2_PAGETABLE_SHIFT;
+ s -= 1 << L2_PAGETABLE_SHIFT;
+ }
+ else
+ {
+ /* Normal page mapping. */
+ if ( !(l2_pgentry_val(*pl2e) & _PAGE_PRESENT) )
+ {
+ newpg = safe_page_alloc();
+ clear_page(newpg);
+ *pl2e = mk_l2_pgentry(__pa(newpg) | __PAGE_HYPERVISOR);
+ }
+ pl1e = l2_pgentry_to_l1(*pl2e) + l1_table_offset(v);
+ if ( (l1_pgentry_val(*pl1e) & _PAGE_PRESENT) )
+ __flush_tlb_one(v);
+ *pl1e = mk_l1_pgentry(p|flags);
+
+ v += 1 << L1_PAGETABLE_SHIFT;
+ p += 1 << L1_PAGETABLE_SHIFT;
+ s -= 1 << L1_PAGETABLE_SHIFT;
+ }
+ }
+
+ return 0;
+}
+
+void __set_fixmap(
+ enum fixed_addresses idx, unsigned long p, unsigned long flags)
+{
+ if ( unlikely(idx >= __end_of_fixed_addresses) )
+ BUG();
+ map_pages(idle_pg_table, fix_to_virt(idx), p, PAGE_SIZE, flags);
}
void __init paging_init(void)
{
- void *ioremap_pt;
- int i;
+ void *newpt;
+ unsigned long i, p, max;
- /* Create page table for ioremap(). */
- ioremap_pt = (void *)alloc_xenheap_page();
- clear_page(ioremap_pt);
- idle_pg_table[IOREMAP_VIRT_START >> L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry(__pa(ioremap_pt) | __PAGE_HYPERVISOR);
+ /* Map all of physical memory. */
+ max = ((max_page + ENTRIES_PER_L1_PAGETABLE - 1) &
+ ~(ENTRIES_PER_L1_PAGETABLE - 1)) << PAGE_SHIFT;
+ map_pages(idle_pg_table, PAGE_OFFSET, 0, max, PAGE_HYPERVISOR);
+
+ /*
+ * Allocate and map the machine-to-phys table.
+ * This also ensures L3 is present for ioremap().
+ */
+ for ( i = 0; i < max_page; i += ((1UL << L2_PAGETABLE_SHIFT) / 8) )
+ {
+ p = alloc_boot_pages(1UL << L2_PAGETABLE_SHIFT,
+ 1UL << L2_PAGETABLE_SHIFT);
+ if ( p == 0 )
+ panic("Not enough memory for m2p table\n");
+ map_pages(idle_pg_table, RDWR_MPT_VIRT_START + i*8, p,
+ 1UL << L2_PAGETABLE_SHIFT, PAGE_HYPERVISOR);
+ memset((void *)(RDWR_MPT_VIRT_START + i*8), 0x55,
+ 1UL << L2_PAGETABLE_SHIFT);
+ }
/* Create read-only mapping of MPT for guest-OS use. */
- idle_pg_table[RO_MPT_VIRT_START >> L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry(l2_pgentry_val(
- idle_pg_table[RDWR_MPT_VIRT_START >> L2_PAGETABLE_SHIFT]) &
+ newpt = (void *)alloc_xenheap_page();
+ clear_page(newpt);
+ idle_pg_table[l4_table_offset(RO_MPT_VIRT_START)] =
+ mk_l4_pgentry((__pa(newpt) | __PAGE_HYPERVISOR | _PAGE_USER) &
~_PAGE_RW);
-
- /* Set up mapping cache for domain pages. */
- mapcache = (unsigned long *)alloc_xenheap_page();
- clear_page(mapcache);
- idle_pg_table[MAPCACHE_VIRT_START >> L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry(__pa(mapcache) | __PAGE_HYPERVISOR);
+ /* Copy the L3 mappings from the RDWR_MPT area. */
+ p = l4_pgentry_val(idle_pg_table[l4_table_offset(RDWR_MPT_VIRT_START)]);
+ p &= PAGE_MASK;
+ p += l3_table_offset(RDWR_MPT_VIRT_START) * sizeof(l3_pgentry_t);
+ newpt = (void *)((unsigned long)newpt +
+ (l3_table_offset(RO_MPT_VIRT_START) *
+ sizeof(l3_pgentry_t)));
+ memcpy(newpt, __va(p),
+ (RDWR_MPT_VIRT_END - RDWR_MPT_VIRT_START) >> L3_PAGETABLE_SHIFT);
/* Set up linear page table mapping. */
- idle_pg_table[LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT] =
- mk_l2_pgentry(__pa(idle_pg_table) | __PAGE_HYPERVISOR);
-
+ idle_pg_table[l4_table_offset(LINEAR_PT_VIRT_START)] =
+ mk_l4_pgentry(__pa(idle_pg_table) | __PAGE_HYPERVISOR);
}
void __init zap_low_mappings(void)
{
- idle_pg_table[0] = 0;
+ idle_pg_table[0] = mk_l4_pgentry(0);
+ flush_tlb_all_pge();
}
+void subarch_init_memory(struct domain *dom_xen)
+{
+ unsigned long i, v, m2p_start_mfn;
+ l3_pgentry_t l3e;
+ l2_pgentry_t l2e;
+
+ /*
+ * We are rather picky about the layout of 'struct pfn_info'. The
+ * count_info and domain fields must be adjacent, as we perform atomic
+ * 64-bit operations on them.
+ */
+ if ( (offsetof(struct pfn_info, u.inuse._domain) !=
+ (offsetof(struct pfn_info, count_info) + sizeof(u32))) )
+ {
+ printk("Weird pfn_info layout (%ld,%ld,%d)\n",
+ offsetof(struct pfn_info, count_info),
+ offsetof(struct pfn_info, u.inuse._domain),
+ sizeof(struct pfn_info));
+ for ( ; ; ) ;
+ }
+
+ /* M2P table is mappable read-only by privileged domains. */
+ for ( v = RDWR_MPT_VIRT_START;
+ v != RDWR_MPT_VIRT_END;
+ v += 1 << L2_PAGETABLE_SHIFT )
+ {
+ l3e = l4_pgentry_to_l3(idle_pg_table[l4_table_offset(v)])[
+ l3_table_offset(v)];
+ if ( !(l3_pgentry_val(l3e) & _PAGE_PRESENT) )
+ continue;
+ l2e = l3_pgentry_to_l2(l3e)[l2_table_offset(v)];
+ if ( !(l2_pgentry_val(l2e) & _PAGE_PRESENT) )
+ continue;
+ m2p_start_mfn = l2_pgentry_to_pagenr(l2e);
+
+ for ( i = 0; i < ENTRIES_PER_L1_PAGETABLE; i++ )
+ {
+ frame_table[m2p_start_mfn+i].count_info = PGC_allocated | 1;
+ /* gdt to make sure it's only mapped read-only by non-privileged
+ domains. */
+ frame_table[m2p_start_mfn+i].u.inuse.type_info = PGT_gdt_page | 1;
+ page_set_owner(&frame_table[m2p_start_mfn+i], dom_xen);
+ }
+ }
+}
/*
* Allows shooting down of borrowed page-table use on specific CPUs.
@@ -99,9 +218,10 @@ void __init zap_low_mappings(void)
*/
static void __synchronise_pagetables(void *mask)
{
- struct domain *d = current;
- if ( ((unsigned long)mask & (1<<d->processor)) && is_idle_task(d) )
- write_ptbase(&d->mm);
+ struct exec_domain *ed = current;
+ if ( ((unsigned long)mask & (1 << ed->processor)) &&
+ is_idle_task(ed->domain) )
+ write_ptbase(ed);
}
void synchronise_pagetables(unsigned long cpu_mask)
{
@@ -111,18 +231,10 @@ void synchronise_pagetables(unsigned long cpu_mask)
long do_stack_switch(unsigned long ss, unsigned long esp)
{
- int nr = smp_processor_id();
- struct tss_struct *t = &init_tss[nr];
-
- /* We need to do this check as we load and use SS on guest's behalf. */
- if ( (ss & 3) == 0 )
+ if ( (ss & 3) != 3 )
return -EPERM;
-
- current->thread.guestos_ss = ss;
- current->thread.guestos_sp = esp;
- t->ss1 = ss;
- t->esp1 = esp;
-
+ current->arch.guestos_ss = ss;
+ current->arch.guestos_sp = esp;
return 0;
}
@@ -163,9 +275,11 @@ int check_descriptor(unsigned long *d)
if ( (b & _SEGMENT_TYPE) != 0xc00 )
goto bad;
+#if 0
/* Can't allow far jump to a Xen-private segment. */
if ( !VALID_CODESEL(a>>16) )
goto bad;
+#endif
/* Reserved bits must be zero. */
if ( (b & 0xe0) != 0 )
@@ -226,24 +340,25 @@ int check_descriptor(unsigned long *d)
}
-void destroy_gdt(struct domain *d)
+void destroy_gdt(struct exec_domain *ed)
{
int i;
unsigned long pfn;
for ( i = 0; i < 16; i++ )
{
- if ( (pfn = l1_pgentry_to_pagenr(d->mm.perdomain_pt[i])) != 0 )
+ if ( (pfn = l1_pgentry_to_pagenr(ed->arch.perdomain_ptes[i])) != 0 )
put_page_and_type(&frame_table[pfn]);
- d->mm.perdomain_pt[i] = mk_l1_pgentry(0);
+ ed->arch.perdomain_ptes[i] = mk_l1_pgentry(0);
}
}
-long set_gdt(struct domain *d,
+long set_gdt(struct exec_domain *ed,
unsigned long *frames,
unsigned int entries)
{
+ struct domain *d = ed->domain;
/* NB. There are 512 8-byte entries per GDT page. */
int i = 0, nr_pages = (entries + 511) / 512;
struct desc_struct *vgdt;
@@ -284,15 +399,15 @@ long set_gdt(struct domain *d,
unmap_domain_mem(vgdt);
/* Tear down the old GDT. */
- destroy_gdt(d);
+ destroy_gdt(ed);
/* Install the new GDT. */
for ( i = 0; i < nr_pages; i++ )
- d->mm.perdomain_pt[i] =
+ ed->arch.perdomain_ptes[i] =
mk_l1_pgentry((frames[i] << PAGE_SHIFT) | __PAGE_HYPERVISOR);
- SET_GDT_ADDRESS(d, GDT_VIRT_START);
- SET_GDT_ENTRIES(d, entries);
+ SET_GDT_ADDRESS(ed, GDT_VIRT_START(ed));
+ SET_GDT_ENTRIES(ed, entries);
return 0;
@@ -318,7 +433,7 @@ long do_set_gdt(unsigned long *frame_list, unsigned int entries)
if ( (ret = set_gdt(current, frames, entries)) == 0 )
{
local_flush_tlb();
- __asm__ __volatile__ ("lgdt %0" : "=m" (*current->mm.gdt));
+ __asm__ __volatile__ ("lgdt %0" : "=m" (*current->arch.gdt));
}
return ret;
@@ -339,7 +454,7 @@ long do_update_descriptor(
return -EINVAL;
page = &frame_table[pfn];
- if ( unlikely(!get_page(page, current)) )
+ if ( unlikely(!get_page(page, current->domain)) )
return -EINVAL;
/* Check if the given frame is in use in an unsafe context. */
@@ -347,7 +462,7 @@ long do_update_descriptor(
{
case PGT_gdt_page:
/* Disallow updates of Xen-reserved descriptors in the current GDT. */
- if ( (l1_pgentry_to_pagenr(current->mm.perdomain_pt[0]) == pfn) &&
+ if ( (l1_pgentry_to_pagenr(current->arch.perdomain_ptes[0]) == pfn) &&
(((pa&(PAGE_SIZE-1))>>3) >= FIRST_RESERVED_GDT_ENTRY) &&
(((pa&(PAGE_SIZE-1))>>3) <= LAST_RESERVED_GDT_ENTRY) )
goto out;
@@ -380,10 +495,19 @@ long do_update_descriptor(
#ifdef MEMORY_GUARD
+#define ALLOC_PT(_level) \
+do { \
+ (_level) = (_level ## _pgentry_t *)heap_start; \
+ heap_start = (void *)((unsigned long)heap_start + PAGE_SIZE); \
+ clear_page(_level); \
+} while ( 0 )
void *memguard_init(void *heap_start)
{
- l1_pgentry_t *l1;
- int i, j;
+ l1_pgentry_t *l1 = NULL;
+ l2_pgentry_t *l2 = NULL;
+ l3_pgentry_t *l3 = NULL;
+ l4_pgentry_t *l4 = &idle_pg_table[l4_table_offset(PAGE_OFFSET)];
+ unsigned long i, j;
/* Round the allocation pointer up to a page boundary. */
heap_start = (void *)(((unsigned long)heap_start + (PAGE_SIZE-1)) &
@@ -392,14 +516,22 @@ void *memguard_init(void *heap_start)
/* Memory guarding is incompatible with super pages. */
for ( i = 0; i < (xenheap_phys_end >> L2_PAGETABLE_SHIFT); i++ )
{
- l1 = (l1_pgentry_t *)heap_start;
- heap_start = (void *)((unsigned long)heap_start + PAGE_SIZE);
+ ALLOC_PT(l1);
for ( j = 0; j < ENTRIES_PER_L1_PAGETABLE; j++ )
l1[j] = mk_l1_pgentry((i << L2_PAGETABLE_SHIFT) |
(j << L1_PAGETABLE_SHIFT) |
__PAGE_HYPERVISOR);
- idle_pg_table[i] = idle_pg_table[i + l2_table_offset(PAGE_OFFSET)] =
- mk_l2_pgentry(virt_to_phys(l1) | __PAGE_HYPERVISOR);
+ if ( !((unsigned long)l2 & (PAGE_SIZE-1)) )
+ {
+ ALLOC_PT(l2);
+ if ( !((unsigned long)l3 & (PAGE_SIZE-1)) )
+ {
+ ALLOC_PT(l3);
+ *l4++ = mk_l4_pgentry(virt_to_phys(l3) | __PAGE_HYPERVISOR);
+ }
+ *l3++ = mk_l3_pgentry(virt_to_phys(l2) | __PAGE_HYPERVISOR);
+ }
+ *l2++ = mk_l2_pgentry(virt_to_phys(l1) | __PAGE_HYPERVISOR);
}
return heap_start;
@@ -409,6 +541,8 @@ static void __memguard_change_range(void *p, unsigned long l, int guard)
{
l1_pgentry_t *l1;
l2_pgentry_t *l2;
+ l3_pgentry_t *l3;
+ l4_pgentry_t *l4;
unsigned long _p = (unsigned long)p;
unsigned long _l = (unsigned long)l;
@@ -420,8 +554,10 @@ static void __memguard_change_range(void *p, unsigned long l, int guard)
while ( _l != 0 )
{
- l2 = &idle_pg_table[l2_table_offset(_p)];
- l1 = l2_pgentry_to_l1(*l2) + l1_table_offset(_p);
+ l4 = &idle_pg_table[l4_table_offset(_p)];
+ l3 = l4_pgentry_to_l3(*l4) + l3_table_offset(_p);
+ l2 = l3_pgentry_to_l2(*l3) + l2_table_offset(_p);
+ l1 = l2_pgentry_to_l1(*l2) + l1_table_offset(_p);
if ( guard )
*l1 = mk_l1_pgentry(l1_pgentry_val(*l1) & ~_PAGE_PRESENT);
else
@@ -431,6 +567,12 @@ static void __memguard_change_range(void *p, unsigned long l, int guard)
}
}
+void memguard_guard_stack(void *p)
+{
+ p = (void *)((unsigned long)p + PAGE_SIZE);
+ memguard_guard_range(p, 2 * PAGE_SIZE);
+}
+
void memguard_guard_range(void *p, unsigned long l)
{
__memguard_change_range(p, l, 1);
@@ -442,14 +584,4 @@ void memguard_unguard_range(void *p, unsigned long l)
__memguard_change_range(p, l, 0);
}
-int memguard_is_guarded(void *p)
-{
- l1_pgentry_t *l1;
- l2_pgentry_t *l2;
- unsigned long _p = (unsigned long)p;
- l2 = &idle_pg_table[l2_table_offset(_p)];
- l1 = l2_pgentry_to_l1(*l2) + l1_table_offset(_p);
- return !(l1_pgentry_val(*l1) & _PAGE_PRESENT);
-}
-
#endif
diff --git a/xen/arch/x86/x86_64/traps.c b/xen/arch/x86/x86_64/traps.c
new file mode 100644
index 0000000000..1460058f5e
--- /dev/null
+++ b/xen/arch/x86/x86_64/traps.c
@@ -0,0 +1,233 @@
+
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/sched.h>
+#include <xen/lib.h>
+#include <xen/errno.h>
+#include <xen/mm.h>
+#include <xen/irq.h>
+#include <xen/console.h>
+#include <xen/sched.h>
+#include <asm/msr.h>
+
+static int kstack_depth_to_print = 8*20;
+
+static inline int kernel_text_address(unsigned long addr)
+{
+ if (addr >= (unsigned long) &_stext &&
+ addr <= (unsigned long) &_etext)
+ return 1;
+ return 0;
+
+}
+
+void show_guest_stack(void)
+{
+ int i;
+ execution_context_t *ec = get_execution_context();
+ unsigned long *stack = (unsigned long *)ec->rsp;
+ printk("Guest RIP is %lx\n ", ec->rip);
+
+ for ( i = 0; i < kstack_depth_to_print; i++ )
+ {
+ if ( ((long)stack & (STACK_SIZE-1)) == 0 )
+ break;
+ if ( i && ((i % 8) == 0) )
+ printk("\n ");
+ printk("%p ", *stack++);
+ }
+ printk("\n");
+
+}
+
+void show_trace(unsigned long *rsp)
+{
+ unsigned long *stack, addr;
+ int i;
+
+ printk("Call Trace from RSP=%p:\n ", rsp);
+ stack = rsp;
+ i = 0;
+ while (((long) stack & (STACK_SIZE-1)) != 0) {
+ addr = *stack++;
+ if (kernel_text_address(addr)) {
+ if (i && ((i % 6) == 0))
+ printk("\n ");
+ printk("[<%p>] ", addr);
+ i++;
+ }
+ }
+ printk("\n");
+}
+
+void show_stack(unsigned long *rsp)
+{
+ unsigned long *stack;
+ int i;
+
+ printk("Stack trace from RSP=%p:\n ", rsp);
+
+ stack = rsp;
+ for ( i = 0; i < kstack_depth_to_print; i++ )
+ {
+ if ( ((long)stack & (STACK_SIZE-1)) == 0 )
+ break;
+ if ( i && ((i % 8) == 0) )
+ printk("\n ");
+ if ( kernel_text_address(*stack) )
+ printk("[%p] ", *stack++);
+ else
+ printk("%p ", *stack++);
+ }
+ printk("\n");
+
+ show_trace(rsp);
+}
+
+void show_registers(struct xen_regs *regs)
+{
+ printk("CPU: %d\nEIP: %04lx:[<%p>] \nEFLAGS: %p\n",
+ smp_processor_id(), 0xffff & regs->cs, regs->rip, regs->eflags);
+ printk("rax: %p rbx: %p rcx: %p rdx: %p\n",
+ regs->rax, regs->rbx, regs->rcx, regs->rdx);
+ printk("rsi: %p rdi: %p rbp: %p rsp: %p\n",
+ regs->rsi, regs->rdi, regs->rbp, regs->rsp);
+ printk("r8: %p r9: %p r10: %p r11: %p\n",
+ regs->r8, regs->r9, regs->r10, regs->r11);
+ printk("r12: %p r13: %p r14: %p r15: %p\n",
+ regs->r12, regs->r13, regs->r14, regs->r15);
+
+ show_stack((unsigned long *)regs->rsp);
+}
+
+void show_page_walk(unsigned long addr)
+{
+ unsigned long page = read_cr3();
+
+ printk("Pagetable walk from %p:\n", addr);
+
+ page &= PAGE_MASK;
+ page = ((unsigned long *) __va(page))[l4_table_offset(addr)];
+ printk(" L4 = %p\n", page);
+ if ( !(page & _PAGE_PRESENT) )
+ return;
+
+ page &= PAGE_MASK;
+ page = ((unsigned long *) __va(page))[l3_table_offset(addr)];
+ printk(" L3 = %p\n", page);
+ if ( !(page & _PAGE_PRESENT) )
+ return;
+
+ page &= PAGE_MASK;
+ page = ((unsigned long *) __va(page))[l2_table_offset(addr)];
+ printk(" L2 = %p %s\n", page, (page & _PAGE_PSE) ? "(2MB)" : "");
+ if ( !(page & _PAGE_PRESENT) || (page & _PAGE_PSE) )
+ return;
+
+ page &= PAGE_MASK;
+ page = ((unsigned long *) __va(page))[l1_table_offset(addr)];
+ printk(" L1 = %p\n", page);
+}
+
+#define DOUBLEFAULT_STACK_SIZE 1024
+static unsigned char doublefault_stack[DOUBLEFAULT_STACK_SIZE];
+asmlinkage void double_fault(void);
+
+asmlinkage void do_double_fault(struct xen_regs *regs)
+{
+ /* Disable the NMI watchdog. It's useless now. */
+ watchdog_on = 0;
+
+ console_force_unlock();
+
+ /* Find information saved during fault and dump it to the console. */
+ printk("************************************\n");
+ printk("EIP: %04lx:[<%p>] \nEFLAGS: %p\n",
+ 0xffff & regs->cs, regs->rip, regs->eflags);
+ printk("rax: %p rbx: %p rcx: %p rdx: %p\n",
+ regs->rax, regs->rbx, regs->rcx, regs->rdx);
+ printk("rsi: %p rdi: %p rbp: %p rsp: %p\n",
+ regs->rsi, regs->rdi, regs->rbp, regs->rsp);
+ printk("r8: %p r9: %p r10: %p r11: %p\n",
+ regs->r8, regs->r9, regs->r10, regs->r11);
+ printk("r12: %p r13: %p r14: %p r15: %p\n",
+ regs->r12, regs->r13, regs->r14, regs->r15);
+ printk("************************************\n");
+ printk("CPU%d DOUBLE FAULT -- system shutdown\n",
+ logical_smp_processor_id());
+ printk("System needs manual reset.\n");
+ printk("************************************\n");
+
+ /* Lock up the console to prevent spurious output from other CPUs. */
+ console_force_lock();
+
+ /* Wait for manual reset. */
+ for ( ; ; )
+ __asm__ __volatile__ ( "hlt" );
+}
+
+void __init doublefault_init(void)
+{
+ int i;
+
+ /* Initialise IST1 for each CPU. Note the handler is non-reentrant. */
+ for ( i = 0; i < NR_CPUS; i++ )
+ init_tss[i].ist[0] = (unsigned long)
+ &doublefault_stack[DOUBLEFAULT_STACK_SIZE];
+
+ /* Set interrupt gate for double faults, specifying IST1. */
+ set_intr_gate(TRAP_double_fault, &double_fault);
+ idt_table[TRAP_double_fault].a |= 1UL << 32; /* IST1 */
+}
+
+asmlinkage void hypercall(void);
+void __init percpu_traps_init(void)
+{
+ char *stack_top = (char *)get_stack_top();
+ char *stack = (char *)((unsigned long)stack_top & ~(STACK_SIZE - 1));
+
+ /* movq %rsp, saversp(%rip) */
+ stack[0] = 0x48;
+ stack[1] = 0x89;
+ stack[2] = 0x25;
+ *(u32 *)&stack[3] = (stack_top - &stack[7]) - 16;
+
+ /* leaq saversp(%rip), %rsp */
+ stack[7] = 0x48;
+ stack[8] = 0x8d;
+ stack[9] = 0x25;
+ *(u32 *)&stack[10] = (stack_top - &stack[14]) - 16;
+
+ /* jmp hypercall */
+ stack[14] = 0xe9;
+ *(u32 *)&stack[15] = (char *)hypercall - &stack[19];
+
+ wrmsr(MSR_STAR, 0, (FLAT_RING3_CS64<<16) | __HYPERVISOR_CS);
+ wrmsr(MSR_LSTAR, (unsigned long)stack, ((unsigned long)stack>>32));
+ wrmsr(MSR_SYSCALL_MASK, 0xFFFFFFFFU, 0U);
+}
+
+void *decode_reg(struct xen_regs *regs, u8 b)
+{
+ switch ( b )
+ {
+ case 0: return &regs->rax;
+ case 1: return &regs->rcx;
+ case 2: return &regs->rdx;
+ case 3: return &regs->rbx;
+ case 4: return &regs->rsp;
+ case 5: return &regs->rbp;
+ case 6: return &regs->rsi;
+ case 7: return &regs->rdi;
+ case 8: return &regs->r8;
+ case 9: return &regs->r9;
+ case 10: return &regs->r10;
+ case 11: return &regs->r11;
+ case 12: return &regs->r12;
+ case 13: return &regs->r13;
+ case 14: return &regs->r14;
+ case 15: return &regs->r15;
+ }
+
+ return NULL;
+}
diff --git a/xen/arch/x86/x86_64/usercopy.c b/xen/arch/x86/x86_64/usercopy.c
index e7c11fa501..839d2582a5 100644
--- a/xen/arch/x86/x86_64/usercopy.c
+++ b/xen/arch/x86/x86_64/usercopy.c
@@ -8,55 +8,6 @@
#include <asm/uaccess.h>
/*
- * Copy a null terminated string from userspace.
- */
-
-#define __do_strncpy_from_user(dst,src,count,res) \
-do { \
- long __d0, __d1, __d2; \
- __asm__ __volatile__( \
- " testq %1,%1\n" \
- " jz 2f\n" \
- "0: lodsb\n" \
- " stosb\n" \
- " testb %%al,%%al\n" \
- " jz 1f\n" \
- " decq %1\n" \
- " jnz 0b\n" \
- "1: subq %1,%0\n" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- "3: movq %5,%0\n" \
- " jmp 2b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 8\n" \
- " .quad 0b,3b\n" \
- ".previous" \
- : "=r"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \
- "=&D" (__d2) \
- : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
- : "memory"); \
-} while (0)
-
-long
-__strncpy_from_user(char *dst, const char *src, long count)
-{
- long res;
- __do_strncpy_from_user(dst, src, count, res);
- return res;
-}
-
-long
-strncpy_from_user(char *dst, const char *src, long count)
-{
- long res = -EFAULT;
- if (access_ok(VERIFY_READ, src, 1))
- __do_strncpy_from_user(dst, src, count, res);
- return res;
-}
-
-/*
* Zero Userspace
*/
@@ -88,11 +39,91 @@ unsigned long __clear_user(void *addr, unsigned long size)
" .quad 1b,2b\n"
".previous"
: [size8] "=c"(size), [dst] "=&D" (__d0)
- : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst] "(addr),
+ : [size1] "r"(size & 7), "[size8]" (size / 8), "[dst]"(addr),
[zero] "r" (0UL), [eight] "r" (8UL));
return size;
}
+unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned n)
+{
+ unsigned long __d0, __d1, __d2, __n = n;
+ __asm__ __volatile__(
+ " cmpq $15,%0\n"
+ " jbe 1f\n"
+ " mov %1,%0\n"
+ " neg %0\n"
+ " and $7,%0\n"
+ " sub %0,%3\n"
+ "4: rep; movsb\n" /* make 'to' address aligned */
+ " mov %3,%0\n"
+ " shr $3,%0\n"
+ " and $7,%3\n"
+ " .align 2,0x90\n"
+ "0: rep; movsq\n" /* as many quadwords as possible... */
+ " mov %3,%0\n"
+ "1: rep; movsb\n" /* ...remainder copied as bytes */
+ "2:\n"
+ ".section .fixup,\"ax\"\n"
+ "5: add %3,%0\n"
+ " jmp 2b\n"
+ "3: lea 0(%3,%0,8),%0\n"
+ " jmp 2b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 8\n"
+ " .quad 4b,5b\n"
+ " .quad 0b,3b\n"
+ " .quad 1b,2b\n"
+ ".previous"
+ : "=&c"(__n), "=&D" (__d0), "=&S" (__d1), "=r"(__d2)
+ : "3"(__n), "0"(__n), "1"(to), "2"(from)
+ : "memory");
+ return (unsigned)__n;
+}
+
+unsigned long
+__copy_from_user_ll(void *to, const void __user *from, unsigned n)
+{
+ unsigned long __d0, __d1, __d2, __n = n;
+ __asm__ __volatile__(
+ " cmp $15,%0\n"
+ " jbe 1f\n"
+ " mov %1,%0\n"
+ " neg %0\n"
+ " and $7,%0\n"
+ " sub %0,%3\n"
+ "4: rep; movsb\n" /* make 'to' address aligned */
+ " mov %3,%0\n"
+ " shr $3,%0\n"
+ " and $7,%3\n"
+ " .align 2,0x90\n"
+ "0: rep; movsq\n" /* as many quadwords as possible... */
+ " mov %3,%0\n"
+ "1: rep; movsb\n" /* ...remainder copied as bytes */
+ "2:\n"
+ ".section .fixup,\"ax\"\n"
+ "5: add %3,%0\n"
+ " jmp 6f\n"
+ "3: lea 0(%3,%0,8),%0\n"
+ "6: push %0\n"
+ " push %%rax\n"
+ " xor %%rax,%%rax\n"
+ " rep; stosb\n"
+ " pop %%rax\n"
+ " pop %0\n"
+ " jmp 2b\n"
+ ".previous\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 8\n"
+ " .quad 4b,5b\n"
+ " .quad 0b,3b\n"
+ " .quad 1b,6b\n"
+ ".previous"
+ : "=&c"(__n), "=&D" (__d0), "=&S" (__d1), "=r"(__d2)
+ : "3"(__n), "0"(__n), "1"(to), "2"(from)
+ : "memory");
+ return (unsigned)__n;
+}
unsigned long clear_user(void *to, unsigned long n)
{
@@ -101,36 +132,49 @@ unsigned long clear_user(void *to, unsigned long n)
return n;
}
-/*
- * Return the size of a string (including the ending 0)
+/**
+ * copy_to_user: - Copy a block of data into user space.
+ * @to: Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from kernel space to user space.
*
- * Return 0 on exception, a value greater than N if too long
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
*/
-
-long strnlen_user(const char *s, long n)
+unsigned long
+copy_to_user(void __user *to, const void *from, unsigned n)
{
- unsigned long res = 0;
- char c;
-
- if (!access_ok(VERIFY_READ, s, n))
- return 0;
-
- while (1) {
- if (get_user(c, s))
- return 0;
- if (!c)
- return res+1;
- if (res>n)
- return n+1;
- res++;
- s++;
- }
+ if (access_ok(VERIFY_WRITE, to, n))
+ n = __copy_to_user(to, from, n);
+ return n;
}
-unsigned long copy_in_user(void *to, const void *from, unsigned len)
+/**
+ * copy_from_user: - Copy a block of data from user space.
+ * @to: Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from user space to kernel space.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ */
+unsigned long
+copy_from_user(void *to, const void __user *from, unsigned n)
{
- if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) {
- return copy_user_generic(to, from, len);
- }
- return len;
+ if (access_ok(VERIFY_READ, from, n))
+ n = __copy_from_user(to, from, n);
+ else
+ memset(to, 0, n);
+ return n;
}
diff --git a/xen/arch/x86/x86_64/xen.lds b/xen/arch/x86/x86_64/xen.lds
index 2bb2d9ed49..30a2b0ca67 100644
--- a/xen/arch/x86/x86_64/xen.lds
+++ b/xen/arch/x86/x86_64/xen.lds
@@ -23,12 +23,12 @@ SECTIONS
.rodata : { *(.rodata) *(.rodata.*) } :text
.kstrtab : { *(.kstrtab) } :text
- . = ALIGN(16); /* Exception table */
+ . = ALIGN(32); /* Exception table */
__start___ex_table = .;
__ex_table : { *(__ex_table) } :text
__stop___ex_table = .;
- . = ALIGN(16); /* Pre-exception table */
+ . = ALIGN(32); /* Pre-exception table */
__start___pre_ex_table = .;
__pre_ex_table : { *(__pre_ex_table) } :text
__stop___pre_ex_table = .;
@@ -55,7 +55,7 @@ SECTIONS
__init_begin = .;
.text.init : { *(.text.init) } :text
.data.init : { *(.data.init) } :text
- . = ALIGN(16);
+ . = ALIGN(32);
__setup_start = .;
.setup.init : { *(.setup.init) } :text
__setup_end = .;
diff --git a/xen/common/Makefile b/xen/common/Makefile
index 1ae6148be2..34dbb44175 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -5,12 +5,8 @@ ifeq ($(TARGET_ARCH),ia64)
OBJS := $(subst dom_mem_ops.o,,$(OBJS))
OBJS := $(subst grant_table.o,,$(OBJS))
OBJS := $(subst page_alloc.o,,$(OBJS))
-OBJS := $(subst slab.o,,$(OBJS))
-endif
-
-ifneq ($(debugger),y)
-OBJS := $(subst debug.o,,$(OBJS))
-OBJS := $(subst debug-linux.o,,$(OBJS))
+OBJS := $(subst physdev.o,,$(OBJS))
+OBJS := $(subst xmalloc.o,,$(OBJS))
endif
ifneq ($(perfc),y)
@@ -21,6 +17,9 @@ ifneq ($(trace),y)
OBJS := $(subst trace.o,,$(OBJS))
endif
+OBJS := $(subst sched_atropos.o,,$(OBJS))
+OBJS := $(subst sched_rrobin.o,,$(OBJS))
+
default: common.o
common.o: $(OBJS)
$(LD) $(LDFLAGS) -r -o common.o $(OBJS)
diff --git a/xen/common/ac_timer.c b/xen/common/ac_timer.c
index a33498090b..22c67aac22 100644
--- a/xen/common/ac_timer.c
+++ b/xen/common/ac_timer.c
@@ -1,4 +1,4 @@
-/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*-
****************************************************************************
* (C) 2002-2003 - Rolf Neugebauer - Intel Research Cambridge
* (C) 2002-2003 University of Cambridge
@@ -130,7 +130,7 @@ static int add_entry(struct ac_timer **heap, struct ac_timer *t)
if ( unlikely(sz == GET_HEAP_LIMIT(heap)) )
{
int i, limit = (GET_HEAP_LIMIT(heap)+1) << 1;
- struct ac_timer **new_heap = xmalloc(limit*sizeof(struct ac_timer *));
+ struct ac_timer **new_heap = xmalloc_array(struct ac_timer *, limit);
if ( new_heap == NULL ) BUG();
memcpy(new_heap, heap, (limit>>1)*sizeof(struct ac_timer *));
for ( i = 0; i < smp_num_cpus; i++ )
@@ -278,8 +278,7 @@ void __init ac_timer_init(void)
for ( i = 0; i < smp_num_cpus; i++ )
{
- ac_timers[i].heap = xmalloc(
- (DEFAULT_HEAP_LIMIT+1) * sizeof(struct ac_timer *));
+ ac_timers[i].heap = xmalloc_array(struct ac_timer *, DEFAULT_HEAP_LIMIT+1);
if ( ac_timers[i].heap == NULL ) BUG();
SET_HEAP_SIZE(ac_timers[i].heap, 0);
SET_HEAP_LIMIT(ac_timers[i].heap, DEFAULT_HEAP_LIMIT);
diff --git a/xen/common/debug-linux.c b/xen/common/debug-linux.c
deleted file mode 100644
index 03c4995eb1..0000000000
--- a/xen/common/debug-linux.c
+++ /dev/null
@@ -1,267 +0,0 @@
-
-/*
- * pervasive debugger
- * www.cl.cam.ac.uk/netos/pdb
- *
- * alex ho
- * 2004
- * university of cambridge computer laboratory
- *
- * linux specific pdb stuff
- */
-
-#include <xen/config.h>
-#include <xen/types.h>
-#include <xen/lib.h>
-#include <public/dom0_ops.h>
-#include <asm/pdb.h>
-
-/* from linux/sched.h */
-#define PIDHASH_SZ (4096 >> 2)
-#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
-
-/* from asm-xen/pgtable-2level.h */
-#define PGDIR_SHIFT 22
-#define PTRS_PER_PGD 1024
-
-/* from asm-xen/page.h */
-#define PAGE_SHIFT 12
-#define PAGE_SIZE (1UL << PAGE_SHIFT)
-#define PAGE_MASK (~(PAGE_SIZE-1))
-
-#define __PAGE_OFFSET (0xC0000000)
-#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
-#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
-#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
-
-/* from debug.h */
-#define ENTRIES_PER_L1_PAGETABLE 1024
-#define L1_PAGE_BITS ( (ENTRIES_PER_L1_PAGETABLE - 1) << PAGE_SHIFT )
-
-void pdb_linux_process_details (unsigned long cr3, int pid, char *buffer);
-
-/* adapted from asm-xen/page.h */
-static inline unsigned long machine_to_phys(unsigned long cr3,
- unsigned long machine)
-{
- unsigned long phys;
- pdb_get_values((u_char *) &phys, sizeof(phys), cr3,
- (unsigned long) machine_to_phys_mapping +
- (machine >> PAGE_SHIFT) * 4);
- phys = (phys << PAGE_SHIFT) | (machine & ~PAGE_MASK);
- return phys;
-}
-
-unsigned long pdb_pidhash_addr = 0xc01971e0UL;
-unsigned long pdb_init_task_union_addr = 0xc0182000UL;
-
-
-unsigned int task_struct_mm_offset = 0x2c;
-unsigned int task_struct_next_task_offset = 0x48;
-unsigned int task_struct_pid_offset = 0x7c;
-unsigned int task_struct_pidhash_next_offset = 0xb0;
-unsigned int task_struct_comm_offset = 0x23e;
-unsigned int task_struct_comm_length = 0x10;
-
-unsigned int mm_struct_pgd_offset = 0x0c;
-
-/*
- * find the task structure of a process (pid)
- * given the cr3 of the guest os.
- */
-unsigned long pdb_linux_pid_task_struct (unsigned long cr3, int pid)
-{
- unsigned long task_struct_p = (unsigned long) NULL;
- unsigned long task_struct_pid;
-
- /* find the task_struct of the given process */
- pdb_get_values((u_char *) &task_struct_p, sizeof(task_struct_p),
- cr3, pdb_pidhash_addr + pid_hashfn(pid) * 4);
-
- /* find the correct task struct */
- while (task_struct_p != (unsigned long)NULL)
- {
- pdb_get_values((u_char *) &task_struct_pid, sizeof(task_struct_pid),
- cr3, task_struct_p + task_struct_pid_offset);
- if (task_struct_pid == pid)
- {
- break;
- }
-
- pdb_get_values((u_char *) &task_struct_p, sizeof(task_struct_p),
- cr3, task_struct_p + task_struct_pidhash_next_offset);
- }
- if (task_struct_p == (unsigned long) NULL)
- {
- /* oops */
- printk ("pdb error: couldn't find process 0x%x (0x%lx)\n", pid, cr3);
- }
-
- return task_struct_p;
-}
-
-/*
- * find the ptbr of a process (pid)
- * given the cr3 of the guest os.
- */
-unsigned long pdb_linux_pid_ptbr (unsigned long cr3, int pid)
-{
- unsigned long task_struct_p;
- unsigned long mm_p, pgd;
-
- task_struct_p = pdb_linux_pid_task_struct(cr3, pid);
- if (task_struct_p == (unsigned long) NULL)
- {
- return (unsigned long) NULL;
- }
-
- /* get the mm_struct within the task_struct */
- pdb_get_values((u_char *) &mm_p, sizeof(mm_p),
- cr3, task_struct_p + task_struct_mm_offset);
- /* get the page global directory (cr3) within the mm_struct */
- pdb_get_values((u_char *) &pgd, sizeof(pgd),
- cr3, mm_p + mm_struct_pgd_offset);
-
- return pgd;
-}
-
-
-
-/* read a byte from a process
- *
- * in: pid: process id
- * cr3: ptbr for the process' domain
- * addr: address to read
- */
-
-u_char pdb_linux_get_value(int pid, unsigned long cr3, unsigned long addr)
-{
- u_char result = 0;
- unsigned long pgd;
- unsigned long l2tab, page;
-
- /* get the process' pgd */
- pgd = pdb_linux_pid_ptbr(cr3, pid);
-
- /* get the l2 table entry */
- pdb_get_values((u_char *) &l2tab, sizeof(l2tab),
- cr3, pgd + (addr >> PGDIR_SHIFT) * 4);
- l2tab = (unsigned long)__va(machine_to_phys(cr3, l2tab) & PAGE_MASK);
-
- /* get the page table entry */
- pdb_get_values((u_char *) &page, sizeof(page),
- cr3, l2tab + ((addr & L1_PAGE_BITS) >> PAGE_SHIFT) * 4);
- page = (unsigned long)__va(machine_to_phys(cr3, page) & PAGE_MASK);
-
- /* get the byte */
- pdb_get_values((u_char *) &result, sizeof(result),
- cr3, page + (addr & ~PAGE_MASK));
-
- return result;
-}
-
-void pdb_linux_get_values(char *buffer, int length, unsigned long address,
- int pid, unsigned long cr3)
-{
- int loop;
-
- /* yes, this can be optimized... a lot */
- for (loop = 0; loop < length; loop++)
- {
- buffer[loop] = pdb_linux_get_value(pid, cr3, address + loop);
- }
-}
-
-
-void pdb_linux_set_value(int pid, unsigned long cr3, unsigned long addr,
- u_char *value)
-{
- unsigned long pgd;
- unsigned long l2tab, page;
-
- /* get the process' pgd */
- pgd = pdb_linux_pid_ptbr(cr3, pid);
-
- /* get the l2 table entry */
- pdb_get_values((u_char *) &l2tab, sizeof(l2tab),
- cr3, pgd + (addr >> PGDIR_SHIFT) * 4);
- l2tab = (unsigned long)__va(machine_to_phys(cr3, l2tab) & PAGE_MASK);
-
- /* get the page table entry */
- pdb_get_values((u_char *) &page, sizeof(page),
- cr3, l2tab + ((addr & L1_PAGE_BITS) >> PAGE_SHIFT) * 4);
- page = (unsigned long)__va(machine_to_phys(cr3, page) & PAGE_MASK);
-
- /* set the byte */
- pdb_set_values(value, sizeof(u_char), cr3, page + (addr & ~PAGE_MASK));
-}
-
-void pdb_linux_set_values(char *buffer, int length, unsigned long address,
- int pid, unsigned long cr3)
-{
- int loop;
-
- /* it's difficult to imagine a more inefficient algorithm */
- for (loop = 0; loop < length; loop++)
- {
- pdb_linux_set_value(pid, cr3, address + loop, &buffer[loop * 2]);
- }
-}
-
-/**********************************************************************/
-
-/*
- * return 1 if is the virtual address is in the operating system's
- * address space, else 0
- */
-int pdb_linux_address_space (unsigned long addr)
-{
- return (addr > PAGE_OFFSET);
-}
-
-/* get a list of at most "max" processes
- * return: number of threads found
- *
- * init_task -> init_task_union.task
- * while (next_task != init_task) {}
- */
-int pdb_linux_process_list (unsigned long cr3, int array[], int max)
-{
- unsigned long task_p, next_p;
- int pid;
- int count = 0;
-
- /* task_p = init_task->next_task */
- pdb_get_values((u_char *) &task_p, sizeof(task_p),
- cr3, pdb_init_task_union_addr + task_struct_next_task_offset);
-
- while (task_p != pdb_init_task_union_addr)
- {
- pdb_get_values((u_char *) &pid, sizeof(pid),
- cr3, task_p + task_struct_pid_offset);
-
- array[count % max] = pid;
- count++;
-
- pdb_get_values((u_char *) &next_p, sizeof(next_p),
- cr3, task_p + task_struct_next_task_offset);
- task_p = next_p;
- }
-
- return count;
-}
-
-/*
- * get additional details about a particular process
- */
-void pdb_linux_process_details (unsigned long cr3, int pid, char *buffer)
-{
- unsigned long task_struct_p;
-
- task_struct_p = pdb_linux_pid_task_struct(cr3, pid);
-
- pdb_get_values((u_char *) buffer, task_struct_comm_length,
- cr3, task_struct_p + task_struct_comm_offset);
- return;
-}
-
diff --git a/xen/common/debug.c b/xen/common/debug.c
deleted file mode 100644
index fa99d6bd8f..0000000000
--- a/xen/common/debug.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * debug.c
- *
- * xen pervasive debugger
- */
-
-#include <xen/config.h>
-#include <xen/types.h>
-#include <xen/lib.h>
-#include <public/dom0_ops.h>
-#include <xen/sched.h>
-#include <xen/event.h>
-#include <asm/page.h>
-#include <asm/pdb.h>
-#include <asm/shadow.h>
-
-#undef DEBUG_TRACE
-#ifdef DEBUG_TRACE
-#define TRC(_x) _x
-#else
-#define TRC(_x)
-#endif
-
-/****************************************************************************/
-
-extern u_char pdb_linux_get_value(int pid, unsigned long cr3,
- unsigned long addr);
-
-/*
- * interactively call pervasive debugger from a privileged domain
- */
-void pdb_do_debug (dom0_op_t *op)
-{
- op->u.debug.status = 0;
-
- TRC(printk("PDB: op:%c, dom:%llu, in1:%x, in2:%x, in3:%x, in4:%x\n",
- op->u.debug.opcode, op->u.debug.domain,
- op->u.debug.in1, op->u.debug.in2,
- op->u.debug.in3, op->u.debug.in4));
-
- /* NOT NOW
- if (op->u.debug.domain == 0)
- {
- op->u.debug.status = 1;
- return;
- }
- */
-
- switch (op->u.debug.opcode)
- {
- case 'c' :
- {
- struct domain *d = find_domain_by_id(op->u.debug.domain);
- if ( d != NULL )
- {
- domain_unpause_by_systemcontroller(d);
- put_domain(d);
- }
- else
- {
- op->u.debug.status = 2; /* invalid domain */
- }
- break;
- }
- case 'r' :
- {
- int loop;
- u_char x;
- unsigned long cr3;
- struct domain *d;
-
- d = find_domain_by_id(op->u.debug.domain);
- if ( shadow_mode(d) )
- cr3 = pagetable_val(d->mm.shadow_table);
- else
- cr3 = pagetable_val(d->mm.pagetable);
-
- for (loop = 0; loop < op->u.debug.in2; loop++) /* length */
- {
- if (loop % 8 == 0)
- {
- printk ("\n%08x ", op->u.debug.in1 + loop);
- }
- x = pdb_linux_get_value(op->u.debug.in3,
- cr3, op->u.debug.in1 + loop);
- printk (" %02x", x);
- }
- printk ("\n");
- put_domain(d);
- break;
- }
- case 's' :
- {
- struct domain *d = find_domain_by_id(op->u.debug.domain);
-
- if ( d != NULL )
- {
- domain_pause_by_systemcontroller(d);
- put_domain(d);
- }
- else
- {
- op->u.debug.status = 2; /* invalid domain */
- }
- break;
- }
- default :
- {
- printk("PDB error: unknown debug opcode %c (0x%x)\n",
- op->u.debug.opcode, op->u.debug.opcode);
- }
- }
-}
diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c
index e5b9f1d1e7..e59bed3a3a 100644
--- a/xen/common/dom0_ops.c
+++ b/xen/common/dom0_ops.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* dom0_ops.c
*
@@ -14,7 +15,6 @@
#include <xen/sched.h>
#include <xen/event.h>
#include <asm/domain_page.h>
-#include <asm/pdb.h>
#include <xen/trace.h>
#include <xen/console.h>
#include <asm/shadow.h>
@@ -26,7 +26,7 @@
extern unsigned int alloc_new_dom_mem(struct domain *, unsigned int);
extern long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op);
extern void arch_getdomaininfo_ctxt(
- struct domain *, full_execution_context_t *);
+ struct exec_domain *, full_execution_context_t *);
static inline int is_free_domid(domid_t dom)
{
@@ -96,7 +96,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
long ret = 0;
dom0_op_t curop, *op = &curop;
- if ( !IS_PRIV(current) )
+ if ( !IS_PRIV(current->domain) )
return -EPERM;
if ( copy_from_user(op, u_dom0_op, sizeof(*op)) )
@@ -131,7 +131,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
if ( d != NULL )
{
ret = -EINVAL;
- if ( d != current )
+ if ( d != current->domain )
{
domain_pause_by_systemcontroller(d);
ret = 0;
@@ -148,7 +148,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
if ( d != NULL )
{
ret = -EINVAL;
- if ( test_bit(DF_CONSTRUCTED, &d->flags) )
+ if ( test_bit(DF_CONSTRUCTED, &d->d_flags) )
{
domain_unpause_by_systemcontroller(d);
ret = 0;
@@ -178,11 +178,14 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
{
/* Do an initial placement. Pick the least-populated CPU. */
struct domain *d;
+ struct exec_domain *ed;
unsigned int i, cnt[NR_CPUS] = { 0 };
read_lock(&domlist_lock);
- for_each_domain ( d )
- cnt[d->processor]++;
+ for_each_domain ( d ) {
+ for_each_exec_domain ( d, ed )
+ cnt[ed->processor]++;
+ }
read_unlock(&domlist_lock);
for ( i = 0; i < smp_num_cpus; i++ )
@@ -217,7 +220,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
if ( d != NULL )
{
ret = -EINVAL;
- if ( d != current )
+ if ( d != current->domain )
{
domain_kill(d);
ret = 0;
@@ -231,6 +234,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
{
domid_t dom = op->u.pincpudomain.domain;
struct domain *d = find_domain_by_id(dom);
+ struct exec_domain *ed;
int cpu = op->u.pincpudomain.cpu;
if ( d == NULL )
@@ -239,7 +243,15 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
break;
}
- if ( d == current )
+ ed = d->exec_domain[op->u.pincpudomain.exec_domain];
+ if ( ed == NULL )
+ {
+ ret = -ESRCH;
+ put_domain(d);
+ break;
+ }
+
+ if ( ed == current )
{
ret = -EINVAL;
put_domain(d);
@@ -248,17 +260,17 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
if ( cpu == -1 )
{
- clear_bit(DF_CPUPINNED, &d->flags);
+ clear_bit(EDF_CPUPINNED, &ed->ed_flags);
}
else
{
- domain_pause(d);
+ exec_domain_pause(ed);
synchronise_pagetables(~0UL);
- if ( d->processor != (cpu % smp_num_cpus) )
- set_bit(DF_MIGRATED, &d->flags);
- set_bit(DF_CPUPINNED, &d->flags);
- d->processor = cpu % smp_num_cpus;
- domain_unpause(d);
+ if ( ed->processor != (cpu % smp_num_cpus) )
+ set_bit(EDF_MIGRATED, &ed->ed_flags);
+ set_bit(EDF_CPUPINNED, &ed->ed_flags);
+ ed->processor = cpu % smp_num_cpus;
+ exec_domain_unpause(ed);
}
put_domain(d);
@@ -279,48 +291,11 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
}
break;
- case DOM0_GETMEMLIST:
- {
- int i;
- struct domain *d = find_domain_by_id(op->u.getmemlist.domain);
- unsigned long max_pfns = op->u.getmemlist.max_pfns;
- unsigned long pfn;
- unsigned long *buffer = op->u.getmemlist.buffer;
- struct list_head *list_ent;
-
- ret = -EINVAL;
- if ( d != NULL )
- {
- ret = 0;
-
- spin_lock(&d->page_alloc_lock);
- list_ent = d->page_list.next;
- for ( i = 0; (i < max_pfns) && (list_ent != &d->page_list); i++ )
- {
- pfn = list_entry(list_ent, struct pfn_info, list) -
- frame_table;
- if ( put_user(pfn, buffer) )
- {
- ret = -EFAULT;
- break;
- }
- buffer++;
- list_ent = frame_table[pfn].list.next;
- }
- spin_unlock(&d->page_alloc_lock);
-
- op->u.getmemlist.num_pfns = i;
- copy_to_user(u_dom0_op, op, sizeof(*op));
-
- put_domain(d);
- }
- }
- break;
-
case DOM0_GETDOMAININFO:
{
full_execution_context_t *c;
struct domain *d;
+ struct exec_domain *ed;
read_lock(&domlist_lock);
@@ -340,41 +315,50 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
read_unlock(&domlist_lock);
op->u.getdomaininfo.domain = d->id;
+
+ if ( (op->u.getdomaininfo.exec_domain >= MAX_VIRT_CPUS) ||
+ !d->exec_domain[op->u.getdomaininfo.exec_domain] )
+ {
+ ret = -EINVAL;
+ break;
+ }
+ ed = d->exec_domain[op->u.getdomaininfo.exec_domain];
+
op->u.getdomaininfo.flags =
- (test_bit(DF_DYING, &d->flags) ? DOMFLAGS_DYING : 0) |
- (test_bit(DF_CRASHED, &d->flags) ? DOMFLAGS_CRASHED : 0) |
- (test_bit(DF_SHUTDOWN, &d->flags) ? DOMFLAGS_SHUTDOWN : 0) |
- (test_bit(DF_CTRLPAUSE, &d->flags) ? DOMFLAGS_PAUSED : 0) |
- (test_bit(DF_BLOCKED, &d->flags) ? DOMFLAGS_BLOCKED : 0) |
- (test_bit(DF_RUNNING, &d->flags) ? DOMFLAGS_RUNNING : 0);
-
- op->u.getdomaininfo.flags |= d->processor << DOMFLAGS_CPUSHIFT;
+ (test_bit( DF_DYING, &d->d_flags) ? DOMFLAGS_DYING : 0) |
+ (test_bit( DF_CRASHED, &d->d_flags) ? DOMFLAGS_CRASHED : 0) |
+ (test_bit( DF_SHUTDOWN, &d->d_flags) ? DOMFLAGS_SHUTDOWN : 0) |
+ (test_bit(EDF_CTRLPAUSE, &ed->ed_flags) ? DOMFLAGS_PAUSED : 0) |
+ (test_bit(EDF_BLOCKED, &ed->ed_flags) ? DOMFLAGS_BLOCKED : 0) |
+ (test_bit(EDF_RUNNING, &ed->ed_flags) ? DOMFLAGS_RUNNING : 0);
+
+ op->u.getdomaininfo.flags |= ed->processor << DOMFLAGS_CPUSHIFT;
op->u.getdomaininfo.flags |=
d->shutdown_code << DOMFLAGS_SHUTDOWNSHIFT;
op->u.getdomaininfo.tot_pages = d->tot_pages;
op->u.getdomaininfo.max_pages = d->max_pages;
- op->u.getdomaininfo.cpu_time = d->cpu_time;
+ op->u.getdomaininfo.cpu_time = ed->cpu_time;
op->u.getdomaininfo.shared_info_frame =
__pa(d->shared_info) >> PAGE_SHIFT;
if ( op->u.getdomaininfo.ctxt != NULL )
{
- if ( (c = xmalloc(sizeof(*c))) == NULL )
+ if ( (c = xmalloc(full_execution_context_t)) == NULL )
{
ret = -ENOMEM;
put_domain(d);
break;
}
- if ( d != current )
- domain_pause(d);
+ if ( ed != current )
+ exec_domain_pause(ed);
- arch_getdomaininfo_ctxt(d,c);
+ arch_getdomaininfo_ctxt(ed,c);
- if ( d != current )
- domain_unpause(d);
+ if ( ed != current )
+ exec_domain_unpause(ed);
if ( copy_to_user(op->u.getdomaininfo.ctxt, c, sizeof(*c)) )
ret = -EINVAL;
@@ -390,16 +374,6 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
}
break;
-#ifdef XEN_DEBUGGER
- case DOM0_DEBUG:
- {
- pdb_do_debug(op);
- copy_to_user(u_dom0_op, op, sizeof(*op));
- ret = 0;
- }
- break;
-#endif
-
case DOM0_SETTIME:
{
do_settime(op->u.settime.secs,
@@ -453,7 +427,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
if ( d != NULL )
{
/* should only be used *before* domain is built. */
- if ( !test_bit(DF_CONSTRUCTED, &d->flags) )
+ if ( !test_bit(DF_CONSTRUCTED, &d->d_flags) )
ret = alloc_new_dom_mem(
d, op->u.setdomaininitialmem.initial_memkb );
else
diff --git a/xen/common/dom_mem_ops.c b/xen/common/dom_mem_ops.c
index d675603cdf..9de62004ba 100644
--- a/xen/common/dom_mem_ops.c
+++ b/xen/common/dom_mem_ops.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* dom_mem_ops.c
*
@@ -28,13 +29,13 @@
__HYPERVISOR_dom_mem_op, 5, \
(_op) | (i << START_EXTENT_SHIFT), \
extent_list, nr_extents, extent_order, \
- (d == current) ? DOMID_SELF : d->id)
+ (d == current->domain) ? DOMID_SELF : d->id);
static long
alloc_dom_mem(struct domain *d,
unsigned long *extent_list,
unsigned long start_extent,
- unsigned long nr_extents,
+ unsigned int nr_extents,
unsigned int extent_order)
{
struct pfn_info *page;
@@ -44,7 +45,7 @@ alloc_dom_mem(struct domain *d,
nr_extents, sizeof(*extent_list))) )
return start_extent;
- if ( (extent_order != 0) && !IS_CAPABLE_PHYSDEV(current) )
+ if ( (extent_order != 0) && !IS_CAPABLE_PHYSDEV(current->domain) )
{
DPRINTK("Only I/O-capable domains may allocate > order-0 memory.\n");
return start_extent;
@@ -72,7 +73,7 @@ static long
free_dom_mem(struct domain *d,
unsigned long *extent_list,
unsigned long start_extent,
- unsigned long nr_extents,
+ unsigned int nr_extents,
unsigned int extent_order)
{
struct pfn_info *page;
@@ -133,33 +134,39 @@ do_dom_mem_op(unsigned long op,
op &= (1 << START_EXTENT_SHIFT) - 1;
if ( unlikely(start_extent > nr_extents) ||
- unlikely(nr_extents > (~0UL >> START_EXTENT_SHIFT)) )
+ unlikely(nr_extents > ~0U) ) /* can pack into a uint? */
return -EINVAL;
if ( likely(domid == DOMID_SELF) )
- d = current;
- else if ( unlikely(!IS_PRIV(current)) )
+ d = current->domain;
+ else if ( unlikely(!IS_PRIV(current->domain)) )
return -EPERM;
else if ( unlikely((d = find_domain_by_id(domid)) == NULL) )
- return -ESRCH;
+ return -ESRCH;
+
+ LOCK_BIGLOCK(d);
switch ( op )
{
case MEMOP_increase_reservation:
rc = alloc_dom_mem(
- d, extent_list, start_extent, nr_extents, extent_order);
- break;
+ d, extent_list, start_extent,
+ (unsigned int)nr_extents, extent_order);
+ break;
case MEMOP_decrease_reservation:
rc = free_dom_mem(
- d, extent_list, start_extent, nr_extents, extent_order);
- break;
+ d, extent_list, start_extent,
+ (unsigned int)nr_extents, extent_order);
+ break;
default:
rc = -ENOSYS;
break;
}
if ( unlikely(domid != DOMID_SELF) )
- put_domain(d);
+ put_domain(d);
+
+ UNLOCK_BIGLOCK(d);
return rc;
}
diff --git a/xen/common/domain.c b/xen/common/domain.c
index c2fe184267..d06ed7c491 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* domain.c
*
@@ -7,6 +8,7 @@
#include <xen/config.h>
#include <xen/init.h>
#include <xen/lib.h>
+#include <xen/sched.h>
#include <xen/errno.h>
#include <xen/sched.h>
#include <xen/mm.h>
@@ -27,20 +29,27 @@ struct domain *dom0;
struct domain *do_createdomain(domid_t dom_id, unsigned int cpu)
{
struct domain *d, **pd;
+ struct exec_domain *ed;
if ( (d = alloc_domain_struct()) == NULL )
return NULL;
+ ed = d->exec_domain[0];
+
atomic_set(&d->refcnt, 1);
- atomic_set(&d->pausecnt, 0);
+ atomic_set(&ed->pausecnt, 0);
shadow_lock_init(d);
d->id = dom_id;
- d->processor = cpu;
+ ed->processor = cpu;
d->create_time = NOW();
- memcpy(&d->thread, &idle0_task.thread, sizeof(d->thread));
+ memcpy(&ed->arch, &idle0_exec_domain.arch, sizeof(ed->arch));
+
+ spin_lock_init(&d->time_lock);
+
+ spin_lock_init(&d->big_lock);
spin_lock_init(&d->page_alloc_lock);
INIT_LIST_HEAD(&d->page_list);
@@ -58,9 +67,9 @@ struct domain *do_createdomain(domid_t dom_id, unsigned int cpu)
return NULL;
}
- arch_do_createdomain(d);
+ arch_do_createdomain(ed);
- sched_add_domain(d);
+ sched_add_domain(ed);
if ( d->id != IDLE_DOMAIN_ID )
{
@@ -126,10 +135,13 @@ struct domain *find_last_domain(void)
void domain_kill(struct domain *d)
{
+ struct exec_domain *ed;
+
domain_pause(d);
- if ( !test_and_set_bit(DF_DYING, &d->flags) )
+ if ( !test_and_set_bit(DF_DYING, &d->d_flags) )
{
- sched_rem_domain(d);
+ for_each_exec_domain(d, ed)
+ sched_rem_domain(ed);
domain_relinquish_memory(d);
put_domain(d);
}
@@ -138,12 +150,14 @@ void domain_kill(struct domain *d)
void domain_crash(void)
{
- if ( current->id == 0 )
+ struct domain *d = current->domain;
+
+ if ( d->id == 0 )
BUG();
- set_bit(DF_CRASHED, &current->flags);
+ set_bit(DF_CRASHED, &d->d_flags);
- send_guest_virq(dom0, VIRQ_DOM_EXC);
+ send_guest_virq(dom0->exec_domain[0], VIRQ_DOM_EXC);
__enter_scheduler();
BUG();
@@ -151,7 +165,9 @@ void domain_crash(void)
void domain_shutdown(u8 reason)
{
- if ( current->id == 0 )
+ struct domain *d = current->domain;
+
+ if ( d->id == 0 )
{
extern void machine_restart(char *);
extern void machine_halt(void);
@@ -168,10 +184,10 @@ void domain_shutdown(u8 reason)
}
}
- current->shutdown_code = reason;
- set_bit(DF_SHUTDOWN, &current->flags);
+ d->shutdown_code = reason;
+ set_bit(DF_SHUTDOWN, &d->d_flags);
- send_guest_virq(dom0, VIRQ_DOM_EXC);
+ send_guest_virq(dom0->exec_domain[0], VIRQ_DOM_EXC);
__enter_scheduler();
}
@@ -207,7 +223,7 @@ void domain_destruct(struct domain *d)
struct domain **pd;
atomic_t old, new;
- if ( !test_bit(DF_DYING, &d->flags) )
+ if ( !test_bit(DF_DYING, &d->d_flags) )
BUG();
/* May be already destructed, or get_domain() can race us. */
@@ -249,10 +265,10 @@ int final_setup_guestos(struct domain *p, dom0_builddomain_t *builddomain)
int rc = 0;
full_execution_context_t *c;
- if ( (c = xmalloc(sizeof(*c))) == NULL )
+ if ( (c = xmalloc(full_execution_context_t)) == NULL )
return -ENOMEM;
- if ( test_bit(DF_CONSTRUCTED, &p->flags) )
+ if ( test_bit(DF_CONSTRUCTED, &p->d_flags) )
{
rc = -EINVAL;
goto out;
@@ -264,13 +280,13 @@ int final_setup_guestos(struct domain *p, dom0_builddomain_t *builddomain)
goto out;
}
- if ( (rc = arch_final_setup_guestos(p,c)) != 0 )
+ if ( (rc = arch_final_setup_guestos(p->exec_domain[0],c)) != 0 )
goto out;
/* Set up the shared info structure. */
- update_dom_time(p->shared_info);
+ update_dom_time(p);
- set_bit(DF_CONSTRUCTED, &p->flags);
+ set_bit(DF_CONSTRUCTED, &p->d_flags);
out:
if ( c != NULL )
@@ -278,6 +294,70 @@ int final_setup_guestos(struct domain *p, dom0_builddomain_t *builddomain)
return rc;
}
+/*
+ * final_setup_guestos is used for final setup and launching of domains other
+ * than domain 0. ie. the domains that are being built by the userspace dom0
+ * domain builder.
+ */
+long do_boot_vcpu(unsigned long vcpu, full_execution_context_t *ctxt)
+{
+ struct domain *d = current->domain;
+ struct exec_domain *ed;
+ int rc = 0;
+ full_execution_context_t *c;
+
+ if ( (vcpu >= MAX_VIRT_CPUS) || (d->exec_domain[vcpu] != NULL) )
+ return -EINVAL;
+
+ if ( alloc_exec_domain_struct(d, vcpu) == NULL )
+ return -ENOMEM;
+
+ if ( (c = xmalloc(full_execution_context_t)) == NULL )
+ {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ if ( copy_from_user(c, ctxt, sizeof(*c)) )
+ {
+ rc = -EFAULT;
+ goto out;
+ }
+
+ ed = d->exec_domain[vcpu];
+
+ atomic_set(&ed->pausecnt, 0);
+ shadow_lock_init(d);
+
+ memcpy(&ed->arch, &idle0_exec_domain.arch, sizeof(ed->arch));
+
+ arch_do_boot_vcpu(ed);
+
+ sched_add_domain(ed);
+
+ if ( (rc = arch_final_setup_guestos(ed, c)) != 0 ) {
+ sched_rem_domain(ed);
+ goto out;
+ }
+
+ /* Set up the shared info structure. */
+ update_dom_time(d);
+
+ /* domain_unpause_by_systemcontroller */
+ if ( test_and_clear_bit(EDF_CTRLPAUSE, &ed->ed_flags) )
+ domain_wake(ed);
+
+ xfree(c);
+ return 0;
+
+ out:
+ if ( c != NULL )
+ xfree(c);
+ arch_free_exec_domain_struct(d->exec_domain[vcpu]);
+ d->exec_domain[vcpu] = NULL;
+ return rc;
+}
+
long vm_assist(struct domain *p, unsigned int cmd, unsigned int type)
{
if ( type > MAX_VMASST_TYPE )
diff --git a/xen/common/elf.c b/xen/common/elf.c
index 8241d96520..7c94dab5e2 100644
--- a/xen/common/elf.c
+++ b/xen/common/elf.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* elf.c
*
@@ -35,11 +36,8 @@ int parseelfimage(char *elfbase,
char *shstrtab, *guestinfo=NULL, *p;
int h;
- if ( !IS_ELF(*ehdr) )
- {
- printk("Kernel image does not have an ELF header.\n");
+ if ( !elf_sanity_check(ehdr) )
return -EINVAL;
- }
if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize )
{
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index 40e218c731..a55ea94e85 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* event_channel.c
*
@@ -28,28 +29,33 @@
#define INIT_EVENT_CHANNELS 16
#define MAX_EVENT_CHANNELS 1024
+#define EVENT_CHANNELS_SPREAD 32
-static int get_free_port(struct domain *d)
+static int get_free_port(struct exec_domain *ed)
{
+ struct domain *d = ed->domain;
int max, port;
event_channel_t *chn;
max = d->max_event_channel;
chn = d->event_channel;
- for ( port = 0; port < max; port++ )
+ for ( port = ed->eid * EVENT_CHANNELS_SPREAD; port < max; port++ )
if ( chn[port].state == ECS_FREE )
break;
- if ( port == max )
+ if ( port >= max )
{
if ( max == MAX_EVENT_CHANNELS )
return -ENOSPC;
+
+ if ( port == 0 )
+ max = INIT_EVENT_CHANNELS;
+ else
+ max = port + EVENT_CHANNELS_SPREAD;
- max *= 2;
-
- chn = xmalloc(max * sizeof(event_channel_t));
+ chn = xmalloc_array(event_channel_t, max);
if ( unlikely(chn == NULL) )
return -ENOMEM;
@@ -57,7 +63,8 @@ static int get_free_port(struct domain *d)
if ( d->event_channel != NULL )
{
- memcpy(chn, d->event_channel, (max/2) * sizeof(event_channel_t));
+ memcpy(chn, d->event_channel, d->max_event_channel *
+ sizeof(event_channel_t));
xfree(d->event_channel);
}
@@ -71,12 +78,12 @@ static int get_free_port(struct domain *d)
static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
{
- struct domain *d = current;
+ struct domain *d = current->domain;
int port;
spin_lock(&d->event_channel_lock);
- if ( (port = get_free_port(d)) >= 0 )
+ if ( (port = get_free_port(current)) >= 0 )
{
d->event_channel[port].state = ECS_UNBOUND;
d->event_channel[port].u.unbound.remote_domid = alloc->dom;
@@ -96,20 +103,21 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
{
#define ERROR_EXIT(_errno) do { rc = (_errno); goto out; } while ( 0 )
struct domain *d1, *d2;
+ struct exec_domain *ed1, *ed2;
int port1 = bind->port1, port2 = bind->port2;
domid_t dom1 = bind->dom1, dom2 = bind->dom2;
long rc = 0;
- if ( !IS_PRIV(current) && (dom1 != DOMID_SELF) )
+ if ( !IS_PRIV(current->domain) && (dom1 != DOMID_SELF) )
return -EPERM;
if ( (port1 < 0) || (port2 < 0) )
return -EINVAL;
if ( dom1 == DOMID_SELF )
- dom1 = current->id;
+ dom1 = current->domain->id;
if ( dom2 == DOMID_SELF )
- dom2 = current->id;
+ dom2 = current->domain->id;
if ( ((d1 = find_domain_by_id(dom1)) == NULL) ||
((d2 = find_domain_by_id(dom2)) == NULL) )
@@ -119,6 +127,9 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
return -ESRCH;
}
+ ed1 = d1->exec_domain[0]; /* XXX */
+ ed2 = d2->exec_domain[0]; /* XXX */
+
/* Avoid deadlock by first acquiring lock of domain with smaller id. */
if ( d1 < d2 )
{
@@ -135,7 +146,7 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
/* Obtain, or ensure that we already have, a valid <port1>. */
if ( port1 == 0 )
{
- if ( (port1 = get_free_port(d1)) < 0 )
+ if ( (port1 = get_free_port(ed1)) < 0 )
ERROR_EXIT(port1);
}
else if ( port1 >= d1->max_event_channel )
@@ -147,7 +158,7 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
/* Make port1 non-free while we allocate port2 (in case dom1==dom2). */
u16 tmp = d1->event_channel[port1].state;
d1->event_channel[port1].state = ECS_INTERDOMAIN;
- port2 = get_free_port(d2);
+ port2 = get_free_port(ed2);
d1->event_channel[port1].state = tmp;
if ( port2 < 0 )
ERROR_EXIT(port2);
@@ -167,7 +178,7 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
break;
case ECS_INTERDOMAIN:
- if ( d1->event_channel[port1].u.interdomain.remote_dom != d2 )
+ if ( d1->event_channel[port1].u.interdomain.remote_dom != ed2 )
ERROR_EXIT(-EINVAL);
if ( (d1->event_channel[port1].u.interdomain.remote_port != port2) &&
(bind->port2 != 0) )
@@ -183,7 +194,7 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
switch ( d2->event_channel[port2].state )
{
case ECS_FREE:
- if ( !IS_PRIV(current) && (dom2 != DOMID_SELF) )
+ if ( !IS_PRIV(current->domain) && (dom2 != DOMID_SELF) )
ERROR_EXIT(-EPERM);
break;
@@ -193,7 +204,7 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
break;
case ECS_INTERDOMAIN:
- if ( d2->event_channel[port2].u.interdomain.remote_dom != d1 )
+ if ( d2->event_channel[port2].u.interdomain.remote_dom != ed1 )
ERROR_EXIT(-EINVAL);
if ( (d2->event_channel[port2].u.interdomain.remote_port != port1) &&
(bind->port1 != 0) )
@@ -209,11 +220,11 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
* Everything checked out okay -- bind <dom1,port1> to <dom2,port2>.
*/
- d1->event_channel[port1].u.interdomain.remote_dom = d2;
+ d1->event_channel[port1].u.interdomain.remote_dom = ed2;
d1->event_channel[port1].u.interdomain.remote_port = (u16)port2;
d1->event_channel[port1].state = ECS_INTERDOMAIN;
- d2->event_channel[port2].u.interdomain.remote_dom = d1;
+ d2->event_channel[port2].u.interdomain.remote_dom = ed1;
d2->event_channel[port2].u.interdomain.remote_port = (u16)port1;
d2->event_channel[port2].state = ECS_INTERDOMAIN;
@@ -235,28 +246,27 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
{
- struct domain *d = current;
+ struct exec_domain *ed = current;
+ struct domain *d = ed->domain;
int port, virq = bind->virq;
- if ( virq >= ARRAY_SIZE(d->virq_to_evtchn) )
+ if ( virq >= ARRAY_SIZE(ed->virq_to_evtchn) )
return -EINVAL;
spin_lock(&d->event_channel_lock);
/*
* Port 0 is the fallback port for VIRQs that haven't been explicitly
- * bound yet. The exception is the 'misdirect VIRQ', which is permanently
- * bound to port 0.
+ * bound yet.
*/
- if ( ((port = d->virq_to_evtchn[virq]) != 0) ||
- (virq == VIRQ_MISDIRECT) ||
- ((port = get_free_port(d)) < 0) )
+ if ( ((port = ed->virq_to_evtchn[virq]) != 0) ||
+ ((port = get_free_port(ed)) < 0) )
goto out;
d->event_channel[port].state = ECS_VIRQ;
d->event_channel[port].u.virq = virq;
- d->virq_to_evtchn[virq] = port;
+ ed->virq_to_evtchn[virq] = port;
out:
spin_unlock(&d->event_channel_lock);
@@ -268,10 +278,33 @@ static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
return 0;
}
+static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
+{
+ struct exec_domain *ed = current;
+ struct domain *d = ed->domain;
+ int port, ipi_edom = bind->ipi_edom;
+
+ spin_lock(&d->event_channel_lock);
+
+ if ( (port = get_free_port(ed)) >= 0 )
+ {
+ d->event_channel[port].state = ECS_IPI;
+ d->event_channel[port].u.ipi_edom = ipi_edom;
+ }
+
+ spin_unlock(&d->event_channel_lock);
+
+ if ( port < 0 )
+ return port;
+
+ bind->port = port;
+ return 0;
+}
+
static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
{
- struct domain *d = current;
+ struct domain *d = current->domain;
int port, rc, pirq = bind->pirq;
if ( pirq >= ARRAY_SIZE(d->pirq_to_evtchn) )
@@ -280,11 +313,11 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
spin_lock(&d->event_channel_lock);
if ( ((rc = port = d->pirq_to_evtchn[pirq]) != 0) ||
- ((rc = port = get_free_port(d)) < 0) )
+ ((rc = port = get_free_port(current)) < 0) )
goto out;
d->pirq_to_evtchn[pirq] = port;
- rc = pirq_guest_bind(d, pirq,
+ rc = pirq_guest_bind(current, pirq,
!!(bind->flags & BIND_PIRQ__WILL_SHARE));
if ( rc != 0 )
{
@@ -309,6 +342,7 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
static long __evtchn_close(struct domain *d1, int port1)
{
struct domain *d2 = NULL;
+ struct exec_domain *ed;
event_channel_t *chn1, *chn2;
int port2;
long rc = 0;
@@ -318,8 +352,7 @@ static long __evtchn_close(struct domain *d1, int port1)
chn1 = d1->event_channel;
- /* NB. Port 0 is special (VIRQ_MISDIRECT). Never let it be closed. */
- if ( (port1 <= 0) || (port1 >= d1->max_event_channel) )
+ if ( (port1 < 0) || (port1 >= d1->max_event_channel) )
{
rc = -EINVAL;
goto out;
@@ -328,6 +361,7 @@ static long __evtchn_close(struct domain *d1, int port1)
switch ( chn1[port1].state )
{
case ECS_FREE:
+ case ECS_RESERVED:
rc = -EINVAL;
goto out;
@@ -340,13 +374,19 @@ static long __evtchn_close(struct domain *d1, int port1)
break;
case ECS_VIRQ:
- d1->virq_to_evtchn[chn1[port1].u.virq] = 0;
+ /* XXX could store exec_domain in chn1[port1].u */
+ for_each_exec_domain(d1, ed)
+ if (ed->virq_to_evtchn[chn1[port1].u.virq] == port1)
+ ed->virq_to_evtchn[chn1[port1].u.virq] = 0;
+ break;
+
+ case ECS_IPI:
break;
case ECS_INTERDOMAIN:
if ( d2 == NULL )
{
- d2 = chn1[port1].u.interdomain.remote_dom;
+ d2 = chn1[port1].u.interdomain.remote_dom->domain;
/* If we unlock d1 then we could lose d2. Must get a reference. */
if ( unlikely(!get_domain(d2)) )
@@ -370,7 +410,7 @@ static long __evtchn_close(struct domain *d1, int port1)
goto again;
}
}
- else if ( d2 != chn1[port1].u.interdomain.remote_dom )
+ else if ( d2 != chn1[port1].u.interdomain.remote_dom->domain )
{
rc = -EINVAL;
goto out;
@@ -383,7 +423,7 @@ static long __evtchn_close(struct domain *d1, int port1)
BUG();
if ( chn2[port2].state != ECS_INTERDOMAIN )
BUG();
- if ( chn2[port2].u.interdomain.remote_dom != d1 )
+ if ( chn2[port2].u.interdomain.remote_dom->domain != d1 )
BUG();
chn2[port2].state = ECS_UNBOUND;
@@ -417,8 +457,8 @@ static long evtchn_close(evtchn_close_t *close)
domid_t dom = close->dom;
if ( dom == DOMID_SELF )
- dom = current->id;
- else if ( !IS_PRIV(current) )
+ dom = current->domain->id;
+ else if ( !IS_PRIV(current->domain) )
return -EPERM;
if ( (d = find_domain_by_id(dom)) == NULL )
@@ -431,29 +471,43 @@ static long evtchn_close(evtchn_close_t *close)
}
-static long evtchn_send(int lport)
+long evtchn_send(int lport)
{
- struct domain *ld = current, *rd;
- int rport;
+ struct domain *ld = current->domain;
+ struct exec_domain *rd;
+ int rport, ret = 0;
spin_lock(&ld->event_channel_lock);
if ( unlikely(lport < 0) ||
- unlikely(lport >= ld->max_event_channel) ||
- unlikely(ld->event_channel[lport].state != ECS_INTERDOMAIN) )
+ unlikely(lport >= ld->max_event_channel))
{
spin_unlock(&ld->event_channel_lock);
return -EINVAL;
}
- rd = ld->event_channel[lport].u.interdomain.remote_dom;
- rport = ld->event_channel[lport].u.interdomain.remote_port;
+ switch ( ld->event_channel[lport].state )
+ {
+ case ECS_INTERDOMAIN:
+ rd = ld->event_channel[lport].u.interdomain.remote_dom;
+ rport = ld->event_channel[lport].u.interdomain.remote_port;
- evtchn_set_pending(rd, rport);
+ evtchn_set_pending(rd, rport);
+ break;
+ case ECS_IPI:
+ rd = ld->exec_domain[ld->event_channel[lport].u.ipi_edom];
+ if ( rd )
+ evtchn_set_pending(rd, lport);
+ else
+ ret = -EINVAL;
+ break;
+ default:
+ ret = -EINVAL;
+ }
spin_unlock(&ld->event_channel_lock);
- return 0;
+ return ret;
}
@@ -466,8 +520,8 @@ static long evtchn_status(evtchn_status_t *status)
long rc = 0;
if ( dom == DOMID_SELF )
- dom = current->id;
- else if ( !IS_PRIV(current) )
+ dom = current->domain->id;
+ else if ( !IS_PRIV(current->domain) )
return -EPERM;
if ( (d = find_domain_by_id(dom)) == NULL )
@@ -486,6 +540,7 @@ static long evtchn_status(evtchn_status_t *status)
switch ( chn[port].state )
{
case ECS_FREE:
+ case ECS_RESERVED:
status->status = EVTCHNSTAT_closed;
break;
case ECS_UNBOUND:
@@ -494,7 +549,8 @@ static long evtchn_status(evtchn_status_t *status)
break;
case ECS_INTERDOMAIN:
status->status = EVTCHNSTAT_interdomain;
- status->u.interdomain.dom = chn[port].u.interdomain.remote_dom->id;
+ status->u.interdomain.dom =
+ chn[port].u.interdomain.remote_dom->domain->id;
status->u.interdomain.port = chn[port].u.interdomain.remote_port;
break;
case ECS_PIRQ:
@@ -505,6 +561,10 @@ static long evtchn_status(evtchn_status_t *status)
status->status = EVTCHNSTAT_virq;
status->u.virq = chn[port].u.virq;
break;
+ case ECS_IPI:
+ status->status = EVTCHNSTAT_ipi;
+ status->u.ipi_edom = chn[port].u.ipi_edom;
+ break;
default:
BUG();
}
@@ -544,6 +604,12 @@ long do_event_channel_op(evtchn_op_t *uop)
rc = -EFAULT; /* Cleaning up here would be a mess! */
break;
+ case EVTCHNOP_bind_ipi:
+ rc = evtchn_bind_ipi(&op.u.bind_ipi);
+ if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
+ rc = -EFAULT; /* Cleaning up here would be a mess! */
+ break;
+
case EVTCHNOP_bind_pirq:
rc = evtchn_bind_pirq(&op.u.bind_pirq);
if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
@@ -576,13 +642,10 @@ long do_event_channel_op(evtchn_op_t *uop)
int init_event_channels(struct domain *d)
{
spin_lock_init(&d->event_channel_lock);
- d->event_channel = xmalloc(INIT_EVENT_CHANNELS * sizeof(event_channel_t));
- if ( unlikely(d->event_channel == NULL) )
- return -ENOMEM;
- d->max_event_channel = INIT_EVENT_CHANNELS;
- memset(d->event_channel, 0, INIT_EVENT_CHANNELS * sizeof(event_channel_t));
- d->event_channel[0].state = ECS_VIRQ;
- d->event_channel[0].u.virq = VIRQ_MISDIRECT;
+ /* Call get_free_port to initialize d->event_channel */
+ if ( get_free_port(d->exec_domain[0]) != 0 )
+ return -EINVAL;
+ d->event_channel[0].state = ECS_RESERVED;
return 0;
}
diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 1a207711e2..2a7b62f9f7 100644
--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* common/grant_table.c
*
@@ -74,7 +75,7 @@ __gnttab_map_grant_ref(
*/
int retries = 0;
- ld = current;
+ ld = current->domain;
/* Bitwise-OR avoids short-circuiting which screws control flow. */
if ( unlikely(__get_user(dom, &uop->dom) |
@@ -291,7 +292,7 @@ __gnttab_unmap_grant_ref(
s16 rc = 0;
unsigned long frame, virt;
- ld = current;
+ ld = current->domain;
/* Bitwise-OR avoids short-circuiting which screws control flow. */
if ( unlikely(__get_user(virt, &uop->host_virt_addr) |
@@ -404,9 +405,9 @@ gnttab_setup_table(
if ( op.dom == DOMID_SELF )
{
- op.dom = current->id;
+ op.dom = current->domain->id;
}
- else if ( unlikely(!IS_PRIV(current)) )
+ else if ( unlikely(!IS_PRIV(current->domain)) )
{
(void)put_user(GNTST_permission_denied, &uop->status);
return 0;
@@ -443,6 +444,8 @@ do_grant_table_op(
if ( count > 512 )
return -EINVAL;
+ LOCK_BIGLOCK(current->domain);
+
switch ( cmd )
{
case GNTTABOP_map_grant_ref:
@@ -465,6 +468,8 @@ do_grant_table_op(
break;
}
+ UNLOCK_BIGLOCK(current->domain);
+
return rc;
}
@@ -561,7 +566,7 @@ grant_table_create(
grant_table_t *t;
int i;
- if ( (t = xmalloc(sizeof(*t))) == NULL )
+ if ( (t = xmalloc(grant_table_t)) == NULL )
goto no_mem;
/* Simple stuff. */
@@ -569,8 +574,8 @@ grant_table_create(
spin_lock_init(&t->lock);
/* Active grant table. */
- if ( (t->active = xmalloc(sizeof(active_grant_entry_t) *
- NR_GRANT_ENTRIES)) == NULL )
+ if ( (t->active = xmalloc_array(active_grant_entry_t, NR_GRANT_ENTRIES))
+ == NULL )
goto no_mem;
memset(t->active, 0, sizeof(active_grant_entry_t) * NR_GRANT_ENTRIES);
diff --git a/xen/common/kernel.c b/xen/common/kernel.c
index cf47e3214c..e02654b053 100644
--- a/xen/common/kernel.c
+++ b/xen/common/kernel.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* kernel.c
*
@@ -78,7 +79,7 @@ long do_xen_version(int cmd)
vm_assist_info_t vm_assist_info[MAX_VMASST_TYPE + 1];
long do_vm_assist(unsigned int cmd, unsigned int type)
{
- return vm_assist(current, cmd, type);
+ return vm_assist(current->domain, cmd, type);
}
long do_ni_hypercall(void)
diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c
index ef62fc4a5a..1b9527aa89 100644
--- a/xen/common/keyhandler.c
+++ b/xen/common/keyhandler.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* keyhandler.c
*/
@@ -96,6 +97,7 @@ static void halt_machine(unsigned char key, struct xen_regs *regs)
void do_task_queues(unsigned char key)
{
struct domain *d;
+ struct exec_domain *ed;
s_time_t now = NOW();
printk("'%c' pressed -> dumping task queues (now=0x%X:%08X)\n", key,
@@ -105,19 +107,28 @@ void do_task_queues(unsigned char key)
for_each_domain ( d )
{
- printk("Xen: DOM %u, CPU %d [has=%c] flags=%lx refcnt=%d nr_pages=%d "
- "xenheap_pages=%d\n",
- d->id, d->processor,
- test_bit(DF_RUNNING, &d->flags) ? 'T':'F', d->flags,
+ printk("Xen: DOM %u, flags=%lx refcnt=%d nr_pages=%d "
+ "xenheap_pages=%d\n", d->id, d->d_flags,
atomic_read(&d->refcnt), d->tot_pages, d->xenheap_pages);
dump_pageframe_info(d);
- printk("Guest: upcall_pend = %02x, upcall_mask = %02x\n",
- d->shared_info->vcpu_data[0].evtchn_upcall_pending,
- d->shared_info->vcpu_data[0].evtchn_upcall_mask);
- printk("Notifying guest...\n");
- send_guest_virq(d, VIRQ_DEBUG);
+ for_each_exec_domain ( d, ed ) {
+ printk("Guest: %p CPU %d [has=%c] flags=%lx "
+ "upcall_pend = %02x, upcall_mask = %02x\n", ed,
+ ed->processor,
+ test_bit(EDF_RUNNING, &ed->ed_flags) ? 'T':'F',
+ ed->ed_flags,
+ ed->vcpu_info->evtchn_upcall_pending,
+ ed->vcpu_info->evtchn_upcall_mask);
+ printk("Notifying guest... %d/%d\n", d->id, ed->eid);
+ printk("port %d/%d stat %d %d %d\n",
+ VIRQ_DEBUG, ed->virq_to_evtchn[VIRQ_DEBUG],
+ test_bit(ed->virq_to_evtchn[VIRQ_DEBUG], &d->shared_info->evtchn_pending[0]),
+ test_bit(ed->virq_to_evtchn[VIRQ_DEBUG], &d->shared_info->evtchn_mask[0]),
+ test_bit(ed->virq_to_evtchn[VIRQ_DEBUG]>>5, &ed->vcpu_info->evtchn_pending_sel));
+ send_guest_virq(ed, VIRQ_DEBUG);
+ }
}
read_unlock(&domlist_lock);
diff --git a/xen/common/lib.c b/xen/common/lib.c
index b01d5a1727..d3f11e0fdd 100644
--- a/xen/common/lib.c
+++ b/xen/common/lib.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
#include <xen/ctype.h>
#include <xen/lib.h>
@@ -394,9 +395,9 @@ __udivdi3(a, b)
*/
u64 __umoddi3(u64 a, u64 b)
{
- u64 rem;
- __qdivrem(a, b, &rem);
- return rem;
+ u64 rem;
+ __qdivrem(a, b, &rem);
+ return rem;
}
/*
@@ -425,19 +426,18 @@ s64 __moddi3(s64 a, s64 b)
ub = b, neg2 = 0;
__qdivrem(ua, ub, &urem);
- /* There 4 different cases: */
- if(neg1)
- {
- if(neg2)
- return -urem;
- else
- return ub - urem;
- }
- else
- if(neg2)
- return -ub + urem;
- else
- return urem;
+ /* There 4 different cases: */
+ if (neg1) {
+ if (neg2)
+ return -urem;
+ else
+ return ub - urem;
+ } else {
+ if (neg2)
+ return -ub + urem;
+ else
+ return urem;
+ }
}
#endif /* BITS_PER_LONG == 32 */
diff --git a/xen/common/multicall.c b/xen/common/multicall.c
index 04605ebb2a..112a9f3176 100644
--- a/xen/common/multicall.c
+++ b/xen/common/multicall.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* multicall.c
*/
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 1790e3520d..5fc2a14668 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* page_alloc.c
*
@@ -49,8 +50,9 @@ static unsigned long bitmap_size; /* in bytes */
static unsigned long *alloc_bitmap;
#define PAGES_PER_MAPWORD (sizeof(unsigned long) * 8)
-#define allocated_in_map(_pn) \
-(alloc_bitmap[(_pn)/PAGES_PER_MAPWORD] & (1<<((_pn)&(PAGES_PER_MAPWORD-1))))
+#define allocated_in_map(_pn) \
+( !! (alloc_bitmap[(_pn)/PAGES_PER_MAPWORD] & \
+ (1UL<<((_pn)&(PAGES_PER_MAPWORD-1)))) )
/*
* Hint regarding bitwise arithmetic in map_{alloc,free}:
@@ -79,13 +81,13 @@ static void map_alloc(unsigned long first_page, unsigned long nr_pages)
if ( curr_idx == end_idx )
{
- alloc_bitmap[curr_idx] |= ((1<<end_off)-1) & -(1<<start_off);
+ alloc_bitmap[curr_idx] |= ((1UL<<end_off)-1) & -(1UL<<start_off);
}
else
{
- alloc_bitmap[curr_idx] |= -(1<<start_off);
- while ( ++curr_idx < end_idx ) alloc_bitmap[curr_idx] = ~0L;
- alloc_bitmap[curr_idx] |= (1<<end_off)-1;
+ alloc_bitmap[curr_idx] |= -(1UL<<start_off);
+ while ( ++curr_idx < end_idx ) alloc_bitmap[curr_idx] = ~0UL;
+ alloc_bitmap[curr_idx] |= (1UL<<end_off)-1;
}
}
@@ -108,13 +110,13 @@ static void map_free(unsigned long first_page, unsigned long nr_pages)
if ( curr_idx == end_idx )
{
- alloc_bitmap[curr_idx] &= -(1<<end_off) | ((1<<start_off)-1);
+ alloc_bitmap[curr_idx] &= -(1UL<<end_off) | ((1UL<<start_off)-1);
}
else
{
- alloc_bitmap[curr_idx] &= (1<<start_off)-1;
+ alloc_bitmap[curr_idx] &= (1UL<<start_off)-1;
while ( ++curr_idx != end_idx ) alloc_bitmap[curr_idx] = 0;
- alloc_bitmap[curr_idx] &= -(1<<end_off);
+ alloc_bitmap[curr_idx] &= -(1UL<<end_off);
}
}
@@ -261,8 +263,8 @@ struct pfn_info *alloc_heap_pages(unsigned int zone, unsigned int order)
/* Find smallest order which can satisfy the request. */
for ( i = order; i <= MAX_ORDER; i++ )
- if ( !list_empty(&heap[zone][i]) )
- goto found;
+ if ( !list_empty(&heap[zone][i]) )
+ goto found;
/* No suitable memory blocks. Fail the request. */
spin_unlock(&heap_lock);
@@ -402,9 +404,8 @@ unsigned long alloc_xenheap_pages(unsigned int order)
{
unsigned long flags;
struct pfn_info *pg;
- int i, attempts = 0;
+ int i;
- retry:
local_irq_save(flags);
pg = alloc_heap_pages(MEMZONE_XEN, order);
local_irq_restore(flags);
@@ -417,21 +418,14 @@ unsigned long alloc_xenheap_pages(unsigned int order)
for ( i = 0; i < (1 << order); i++ )
{
pg[i].count_info = 0;
- pg[i].u.inuse.domain = NULL;
+ pg[i].u.inuse._domain = 0;
pg[i].u.inuse.type_info = 0;
}
return (unsigned long)page_to_virt(pg);
no_memory:
- if ( attempts++ < 8 )
- {
- xmem_cache_reap();
- goto retry;
- }
-
printk("Cannot handle page request order %d!\n", order);
- dump_slabinfo();
return 0;
}
@@ -483,11 +477,11 @@ struct pfn_info *alloc_domheap_pages(struct domain *d, unsigned int order)
pfn_stamp = pg[i].tlbflush_timestamp;
for ( j = 0; (mask != 0) && (j < smp_num_cpus); j++ )
{
- if ( mask & (1<<j) )
+ if ( mask & (1UL<<j) )
{
cpu_stamp = tlbflush_time[j];
if ( !NEED_FLUSH(cpu_stamp, pfn_stamp) )
- mask &= ~(1<<j);
+ mask &= ~(1UL<<j);
}
}
@@ -500,7 +494,7 @@ struct pfn_info *alloc_domheap_pages(struct domain *d, unsigned int order)
}
pg[i].count_info = 0;
- pg[i].u.inuse.domain = NULL;
+ pg[i].u.inuse._domain = 0;
pg[i].u.inuse.type_info = 0;
}
@@ -509,13 +503,13 @@ struct pfn_info *alloc_domheap_pages(struct domain *d, unsigned int order)
spin_lock(&d->page_alloc_lock);
- if ( unlikely(test_bit(DF_DYING, &d->flags)) ||
+ if ( unlikely(test_bit(DF_DYING, &d->d_flags)) ||
unlikely((d->tot_pages + (1 << order)) > d->max_pages) )
{
DPRINTK("Over-allocation for domain %u: %u > %u\n",
d->id, d->tot_pages + (1 << order), d->max_pages);
DPRINTK("...or the domain is dying (%d)\n",
- !!test_bit(DF_DYING, &d->flags));
+ !!test_bit(DF_DYING, &d->d_flags));
spin_unlock(&d->page_alloc_lock);
free_heap_pages(MEMZONE_DOM, pg, order);
return NULL;
@@ -528,7 +522,7 @@ struct pfn_info *alloc_domheap_pages(struct domain *d, unsigned int order)
for ( i = 0; i < (1 << order); i++ )
{
- pg[i].u.inuse.domain = d;
+ page_set_owner(&pg[i], d);
wmb(); /* Domain pointer must be visible before updating refcnt. */
pg[i].count_info |= PGC_allocated | 1;
list_add_tail(&pg[i].list, &d->page_list);
@@ -543,8 +537,10 @@ struct pfn_info *alloc_domheap_pages(struct domain *d, unsigned int order)
void free_domheap_pages(struct pfn_info *pg, unsigned int order)
{
int i, drop_dom_ref;
- struct domain *d = pg->u.inuse.domain;
+ struct domain *d = page_get_owner(pg);
+ struct exec_domain *ed;
void *p;
+ int cpu_mask = 0;
ASSERT(!in_irq());
@@ -566,11 +562,14 @@ void free_domheap_pages(struct pfn_info *pg, unsigned int order)
/* NB. May recursively lock from domain_relinquish_memory(). */
spin_lock_recursive(&d->page_alloc_lock);
+ for_each_exec_domain(d, ed)
+ cpu_mask |= 1 << ed->processor;
+
for ( i = 0; i < (1 << order); i++ )
{
ASSERT((pg[i].u.inuse.type_info & PGT_count_mask) == 0);
pg[i].tlbflush_timestamp = tlbflush_current_time();
- pg[i].u.free.cpu_mask = 1 << d->processor;
+ pg[i].u.free.cpu_mask = cpu_mask;
list_del(&pg[i].list);
/*
@@ -578,7 +577,7 @@ void free_domheap_pages(struct pfn_info *pg, unsigned int order)
* if it cares about the secrecy of their contents. However, after
* a domain has died we assume responsibility for erasure.
*/
- if ( unlikely(test_bit(DF_DYING, &d->flags)) )
+ if ( unlikely(test_bit(DF_DYING, &d->d_flags)) )
{
p = map_domain_mem(page_to_phys(&pg[i]));
clear_page(p);
diff --git a/xen/common/perfc.c b/xen/common/perfc.c
index d5384c4af5..511df11a9e 100644
--- a/xen/common/perfc.c
+++ b/xen/common/perfc.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
#include <xen/lib.h>
#include <xen/smp.h>
@@ -22,7 +23,7 @@
static struct {
char *name;
enum { TYPE_SINGLE, TYPE_CPU, TYPE_ARRAY,
- TYPE_S_SINGLE, TYPE_S_CPU, TYPE_S_ARRAY
+ TYPE_S_SINGLE, TYPE_S_CPU, TYPE_S_ARRAY
} type;
int nr_elements;
} perfc_info[] = {
@@ -92,19 +93,19 @@ void perfc_reset(unsigned char key)
switch ( perfc_info[i].type )
{
case TYPE_SINGLE:
- atomic_set(&counters[0],0);
+ atomic_set(&counters[0],0);
case TYPE_S_SINGLE:
counters += 1;
break;
case TYPE_CPU:
for ( j = sum = 0; j < smp_num_cpus; j++ )
- atomic_set(&counters[j],0);
+ atomic_set(&counters[j],0);
case TYPE_S_CPU:
counters += NR_CPUS;
break;
case TYPE_ARRAY:
for ( j = sum = 0; j < perfc_info[i].nr_elements; j++ )
- atomic_set(&counters[j],0);
+ atomic_set(&counters[j],0);
case TYPE_S_ARRAY:
counters += perfc_info[i].nr_elements;
break;
diff --git a/xen/common/physdev.c b/xen/common/physdev.c
index cd4d2811e3..d6356f4678 100644
--- a/xen/common/physdev.c
+++ b/xen/common/physdev.c
@@ -1,4 +1,4 @@
-/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*-
****************************************************************************
* (c) 2004 - Rolf Neugebauer - Intel Research Cambridge
* (c) 2004 - Keir Fraser - University of Cambridge
@@ -98,7 +98,7 @@ static void add_dev_to_task(struct domain *p,
return;
}
- if ( (pdev = xmalloc(sizeof(phys_dev_t))) == NULL )
+ if ( (pdev = xmalloc(phys_dev_t)) == NULL )
{
INFO("Error allocating pdev structure.\n");
return;
@@ -125,10 +125,11 @@ int physdev_pci_access_modify(
domid_t dom, int bus, int dev, int func, int enable)
{
struct domain *p;
+ struct exec_domain *ed, *edc;
struct pci_dev *pdev;
int i, j, rc = 0;
-
- if ( !IS_PRIV(current) )
+
+ if ( !IS_PRIV(current->domain) )
BUG();
if ( (bus > PCI_BUSMAX) || (dev > PCI_DEVMAX) || (func > PCI_FUNCMAX) )
@@ -145,11 +146,13 @@ int physdev_pci_access_modify(
if ( (p = find_domain_by_id(dom)) == NULL )
return -ESRCH;
+ ed = p->exec_domain[0]; /* XXX */
+
/* Make the domain privileged. */
- set_bit(DF_PHYSDEV, &p->flags);
+ set_bit(DF_PHYSDEV, &p->d_flags);
/* FIXME: MAW for now make the domain REALLY privileged so that it
* can run a backend driver (hw access should work OK otherwise) */
- set_bit(DF_PRIVILEGED, &p->flags);
+ set_bit(DF_PRIVILEGED, &p->d_flags);
/* Grant write access to the specified device. */
if ( (pdev = pci_find_slot(bus, PCI_DEVFN(dev, func))) == NULL )
@@ -169,16 +172,22 @@ int physdev_pci_access_modify(
/* Now, setup access to the IO ports and memory regions for the device. */
- if ( p->thread.io_bitmap == NULL )
+ if ( ed->arch.io_bitmap == NULL )
{
- if ( (p->thread.io_bitmap = xmalloc(IOBMP_BYTES)) == NULL )
+ if ( (ed->arch.io_bitmap = xmalloc_array(u8, IOBMP_BYTES)) == NULL )
{
rc = -ENOMEM;
goto out;
}
- memset(p->thread.io_bitmap, 0xFF, IOBMP_BYTES);
+ memset(ed->arch.io_bitmap, 0xFF, IOBMP_BYTES);
- p->thread.io_bitmap_sel = ~0ULL;
+ ed->arch.io_bitmap_sel = ~0ULL;
+
+ for_each_exec_domain(p, edc) {
+ if (edc == ed)
+ continue;
+ edc->arch.io_bitmap = ed->arch.io_bitmap;
+ }
}
for ( i = 0; i < DEVICE_COUNT_RESOURCE; i++ )
@@ -195,13 +204,20 @@ int physdev_pci_access_modify(
"for device %s\n", dom, r->start, r->end, pdev->slot_name);
for ( j = r->start; j < r->end + 1; j++ )
{
- clear_bit(j, p->thread.io_bitmap);
- clear_bit(j / IOBMP_BITS_PER_SELBIT, &p->thread.io_bitmap_sel);
+ clear_bit(j, ed->arch.io_bitmap);
+ clear_bit(j / IOBMP_BITS_PER_SELBIT, &ed->arch.io_bitmap_sel);
}
}
/* rights to IO memory regions are checked when the domain maps them */
}
+
+ for_each_exec_domain(p, edc) {
+ if (edc == ed)
+ continue;
+ edc->arch.io_bitmap_sel = ed->arch.io_bitmap_sel;
+ }
+
out:
put_domain(p);
return rc;
@@ -489,7 +505,7 @@ static long pci_cfgreg_read(int bus, int dev, int func, int reg,
int ret;
phys_dev_t *pdev;
- if ( (ret = check_dev_acc(current, bus, dev, func, &pdev)) != 0 )
+ if ( (ret = check_dev_acc(current->domain, bus, dev, func, &pdev)) != 0 )
{
/* PCI spec states that reads from non-existent devices should return
* all 1s. In this case the domain has no read access, which should
@@ -556,7 +572,7 @@ static long pci_cfgreg_write(int bus, int dev, int func, int reg,
int ret;
phys_dev_t *pdev;
- if ( (ret = check_dev_acc(current, bus, dev, func, &pdev)) != 0 )
+ if ( (ret = check_dev_acc(current->domain, bus, dev, func, &pdev)) != 0 )
return ret;
/* special treatment for some registers */
@@ -619,7 +635,7 @@ static long pci_probe_root_buses(u32 *busmask)
memset(busmask, 0, 256/8);
- list_for_each_entry ( pdev, &current->pcidev_list, node )
+ list_for_each_entry ( pdev, &current->domain->pcidev_list, node )
set_bit(pdev->dev->bus->number, busmask);
return 0;
@@ -660,7 +676,7 @@ long do_physdev_op(physdev_op_t *uop)
break;
case PHYSDEVOP_PCI_INITIALISE_DEVICE:
- if ( (ret = check_dev_acc(current,
+ if ( (ret = check_dev_acc(current->domain,
op.u.pci_initialise_device.bus,
op.u.pci_initialise_device.dev,
op.u.pci_initialise_device.func,
@@ -673,7 +689,7 @@ long do_physdev_op(physdev_op_t *uop)
break;
case PHYSDEVOP_IRQ_UNMASK_NOTIFY:
- ret = pirq_guest_unmask(current);
+ ret = pirq_guest_unmask(current->domain);
break;
case PHYSDEVOP_IRQ_STATUS_QUERY:
@@ -749,7 +765,7 @@ void physdev_init_dom0(struct domain *p)
if ( (dev->hdr_type != PCI_HEADER_TYPE_NORMAL) &&
(dev->hdr_type != PCI_HEADER_TYPE_CARDBUS) )
continue;
- pdev = xmalloc(sizeof(phys_dev_t));
+ pdev = xmalloc(phys_dev_t);
pdev->dev = dev;
pdev->flags = ACC_WRITE;
pdev->state = 0;
@@ -757,6 +773,6 @@ void physdev_init_dom0(struct domain *p)
list_add(&pdev->node, &p->pcidev_list);
}
- set_bit(DF_PHYSDEV, &p->flags);
+ set_bit(DF_PHYSDEV, &p->d_flags);
}
diff --git a/xen/common/resource.c b/xen/common/resource.c
index 8df57772a6..7fff4059d9 100644
--- a/xen/common/resource.c
+++ b/xen/common/resource.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* linux/kernel/resource.c
*
@@ -220,7 +221,7 @@ int allocate_resource(struct resource *root, struct resource *new,
*/
struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
{
- struct resource *res = xmalloc(sizeof(*res));
+ struct resource *res = xmalloc(struct resource);
if (res) {
memset(res, 0, sizeof(*res));
diff --git a/xen/common/sched_atropos.c b/xen/common/sched_atropos.c
index b5901f2397..73e0080281 100644
--- a/xen/common/sched_atropos.c
+++ b/xen/common/sched_atropos.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/*
* atropos.c
* ---------
@@ -69,8 +70,6 @@ struct at_cpu_info
static void at_dump_cpu_state(int cpu);
-static xmem_cache_t *dom_info_cache;
-
static inline void __add_to_runqueue_head(struct domain *d)
{
list_add(RUNLIST(d), RUNQ(d->processor));
@@ -173,7 +172,7 @@ static int at_alloc_task(struct domain *p)
{
ASSERT(p != NULL);
- p->sched_priv = xmem_cache_alloc(dom_info_cache);
+ p->sched_priv = xmalloc(struct at_dom_info);
if ( p->sched_priv == NULL )
return -1;
@@ -558,10 +557,6 @@ static int at_init_scheduler()
INIT_LIST_HEAD(RUNQ(i));
}
- dom_info_cache = xmem_cache_create("Atropos dom info",
- sizeof(struct at_dom_info),
- 0, 0, NULL, NULL);
-
return 0;
}
@@ -649,7 +644,7 @@ static int at_adjdom(struct domain *p, struct sched_adjdom_cmd *cmd)
/* free memory associated with a task */
static void at_free_task(struct domain *p)
{
- xmem_cache_free( dom_info_cache, DOM_INFO(p) );
+ xfree( DOM_INFO(p) );
}
diff --git a/xen/common/sched_bvt.c b/xen/common/sched_bvt.c
index 6f0a79fad1..fb555781f1 100644
--- a/xen/common/sched_bvt.c
+++ b/xen/common/sched_bvt.c
@@ -1,4 +1,4 @@
-/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*-
****************************************************************************
* (C) 2002-2003 - Rolf Neugebauer - Intel Research Cambridge
* (C) 2002-2003 University of Cambridge
@@ -28,13 +28,19 @@
#include <xen/softirq.h>
/* all per-domain BVT-specific scheduling info is stored here */
-struct bvt_dom_info
+struct bvt_edom_info
{
- struct domain *domain; /* domain this info belongs to */
struct list_head run_list; /* runqueue list pointers */
- u32 mcu_advance; /* inverse of weight */
u32 avt; /* actual virtual time */
u32 evt; /* effective virtual time */
+ struct exec_domain *exec_domain;
+ struct bvt_dom_info *inf;
+};
+
+struct bvt_dom_info
+{
+ struct domain *domain; /* domain this info belongs to */
+ u32 mcu_advance; /* inverse of weight */
int warpback; /* warp? */
int warp; /* warp set and within the warp
limits*/
@@ -43,6 +49,8 @@ struct bvt_dom_info
struct ac_timer warp_timer; /* deals with warpl */
s_time_t warpu; /* unwarp time requirement */
struct ac_timer unwarp_timer; /* deals with warpu */
+
+ struct bvt_edom_info ed_inf[MAX_VIRT_CPUS];
};
struct bvt_cpu_info
@@ -52,8 +60,9 @@ struct bvt_cpu_info
};
#define BVT_INFO(p) ((struct bvt_dom_info *)(p)->sched_priv)
+#define EBVT_INFO(p) ((struct bvt_edom_info *)(p)->ed_sched_priv)
#define CPU_INFO(cpu) ((struct bvt_cpu_info *)(schedule_data[cpu]).sched_priv)
-#define RUNLIST(p) ((struct list_head *)&(BVT_INFO(p)->run_list))
+#define RUNLIST(p) ((struct list_head *)&(EBVT_INFO(p)->run_list))
#define RUNQUEUE(cpu) ((struct list_head *)&(CPU_INFO(cpu)->runqueue))
#define CPU_SVT(cpu) (CPU_INFO(cpu)->svt)
@@ -62,26 +71,24 @@ struct bvt_cpu_info
#define TIME_SLOP (s32)MICROSECS(50) /* allow time to slip a bit */
static s32 ctx_allow = (s32)MILLISECS(5); /* context switch allowance */
-static xmem_cache_t *dom_info_cache;
-
-static inline void __add_to_runqueue_head(struct domain *d)
+static inline void __add_to_runqueue_head(struct exec_domain *d)
{
list_add(RUNLIST(d), RUNQUEUE(d->processor));
}
-static inline void __add_to_runqueue_tail(struct domain *d)
+static inline void __add_to_runqueue_tail(struct exec_domain *d)
{
list_add_tail(RUNLIST(d), RUNQUEUE(d->processor));
}
-static inline void __del_from_runqueue(struct domain *d)
+static inline void __del_from_runqueue(struct exec_domain *d)
{
struct list_head *runlist = RUNLIST(d);
list_del(runlist);
runlist->next = NULL;
}
-static inline int __task_on_runqueue(struct domain *d)
+static inline int __task_on_runqueue(struct exec_domain *d)
{
return (RUNLIST(d))->next != NULL;
}
@@ -91,7 +98,7 @@ static inline int __task_on_runqueue(struct domain *d)
static void warp_timer_fn(unsigned long pointer)
{
struct bvt_dom_info *inf = (struct bvt_dom_info *)pointer;
- unsigned int cpu = inf->domain->processor;
+ unsigned int cpu = inf->domain->exec_domain[0]->processor;
spin_lock_irq(&schedule_data[cpu].schedule_lock);
@@ -114,7 +121,7 @@ static void warp_timer_fn(unsigned long pointer)
static void unwarp_timer_fn(unsigned long pointer)
{
struct bvt_dom_info *inf = (struct bvt_dom_info *)pointer;
- unsigned int cpu = inf->domain->processor;
+ unsigned int cpu = inf->domain->exec_domain[0]->processor;
spin_lock_irq(&schedule_data[cpu].schedule_lock);
@@ -127,24 +134,25 @@ static void unwarp_timer_fn(unsigned long pointer)
spin_unlock_irq(&schedule_data[cpu].schedule_lock);
}
-static inline u32 calc_avt(struct domain *d, s_time_t now)
+static inline u32 calc_avt(struct exec_domain *d, s_time_t now)
{
u32 ranfor, mcus;
- struct bvt_dom_info *inf = BVT_INFO(d);
+ struct bvt_dom_info *inf = BVT_INFO(d->domain);
+ struct bvt_edom_info *einf = EBVT_INFO(d);
ranfor = (u32)(now - d->lastschd);
mcus = (ranfor + MCU - 1)/MCU;
- return inf->avt + mcus * inf->mcu_advance;
+ return einf->avt + mcus * inf->mcu_advance;
}
/*
* Calculate the effective virtual time for a domain. Take into account
* warping limits
*/
-static inline u32 calc_evt(struct domain *d, u32 avt)
+static inline u32 calc_evt(struct exec_domain *d, u32 avt)
{
- struct bvt_dom_info *inf = BVT_INFO(d);
+ struct bvt_dom_info *inf = BVT_INFO(d->domain);
/* TODO The warp routines need to be rewritten GM */
if ( inf->warp )
@@ -159,71 +167,82 @@ static inline u32 calc_evt(struct domain *d, u32 avt)
*
* Returns non-zero on failure.
*/
-int bvt_alloc_task(struct domain *d)
+int bvt_alloc_task(struct exec_domain *ed)
{
- if ( (d->sched_priv = xmem_cache_alloc(dom_info_cache)) == NULL )
- return -1;
- memset(d->sched_priv, 0, sizeof(struct bvt_dom_info));
+ struct domain *d = ed->domain;
+ if ( (d->sched_priv == NULL) ) {
+ if ( (d->sched_priv = xmalloc(struct bvt_dom_info)) == NULL )
+ return -1;
+ memset(d->sched_priv, 0, sizeof(struct bvt_dom_info));
+ }
+ ed->ed_sched_priv = &BVT_INFO(d)->ed_inf[ed->eid];
+ BVT_INFO(d)->ed_inf[ed->eid].inf = BVT_INFO(d);
+ BVT_INFO(d)->ed_inf[ed->eid].exec_domain = ed;
return 0;
}
/*
* Add and remove a domain
*/
-void bvt_add_task(struct domain *d)
+void bvt_add_task(struct exec_domain *d)
{
- struct bvt_dom_info *inf = BVT_INFO(d);
+ struct bvt_dom_info *inf = BVT_INFO(d->domain);
+ struct bvt_edom_info *einf = EBVT_INFO(d);
ASSERT(inf != NULL);
ASSERT(d != NULL);
- inf->mcu_advance = MCU_ADVANCE;
- inf->domain = d;
- inf->warpback = 0;
- /* Set some default values here. */
- inf->warp = 0;
- inf->warp_value = 0;
- inf->warpl = MILLISECS(2000);
- inf->warpu = MILLISECS(1000);
- /* initialise the timers */
- init_ac_timer(&inf->warp_timer);
- inf->warp_timer.cpu = d->processor;
- inf->warp_timer.data = (unsigned long)inf;
- inf->warp_timer.function = &warp_timer_fn;
- init_ac_timer(&inf->unwarp_timer);
- inf->unwarp_timer.cpu = d->processor;
- inf->unwarp_timer.data = (unsigned long)inf;
- inf->unwarp_timer.function = &unwarp_timer_fn;
-
- if ( d->id == IDLE_DOMAIN_ID )
+ if (d->eid == 0) {
+ inf->mcu_advance = MCU_ADVANCE;
+ inf->domain = d->domain;
+ inf->warpback = 0;
+ /* Set some default values here. */
+ inf->warp = 0;
+ inf->warp_value = 0;
+ inf->warpl = MILLISECS(2000);
+ inf->warpu = MILLISECS(1000);
+ /* initialise the timers */
+ init_ac_timer(&inf->warp_timer);
+ inf->warp_timer.cpu = d->processor;
+ inf->warp_timer.data = (unsigned long)inf;
+ inf->warp_timer.function = &warp_timer_fn;
+ init_ac_timer(&inf->unwarp_timer);
+ inf->unwarp_timer.cpu = d->processor;
+ inf->unwarp_timer.data = (unsigned long)inf;
+ inf->unwarp_timer.function = &unwarp_timer_fn;
+ }
+
+ einf->exec_domain = d;
+
+ if ( d->domain->id == IDLE_DOMAIN_ID )
{
- inf->avt = inf->evt = ~0U;
+ einf->avt = einf->evt = ~0U;
}
else
{
/* Set avt and evt to system virtual time. */
- inf->avt = CPU_SVT(d->processor);
- inf->evt = CPU_SVT(d->processor);
+ einf->avt = CPU_SVT(d->processor);
+ einf->evt = CPU_SVT(d->processor);
}
}
-int bvt_init_idle_task(struct domain *p)
+int bvt_init_idle_task(struct exec_domain *p)
{
if ( bvt_alloc_task(p) < 0 )
return -1;
bvt_add_task(p);
- set_bit(DF_RUNNING, &p->flags);
+ set_bit(EDF_RUNNING, &p->ed_flags);
if ( !__task_on_runqueue(p) )
__add_to_runqueue_head(p);
return 0;
}
-void bvt_wake(struct domain *d)
+void bvt_wake(struct exec_domain *d)
{
- struct bvt_dom_info *inf = BVT_INFO(d);
- struct domain *curr;
+ struct bvt_edom_info *einf = EBVT_INFO(d);
+ struct exec_domain *curr;
s_time_t now, r_time;
int cpu = d->processor;
u32 curr_evt;
@@ -237,31 +256,31 @@ void bvt_wake(struct domain *d)
/* Set the BVT parameters. AVT should always be updated
if CPU migration ocurred.*/
- if ( inf->avt < CPU_SVT(cpu) ||
- unlikely(test_bit(DF_MIGRATED, &d->flags)) )
- inf->avt = CPU_SVT(cpu);
+ if ( einf->avt < CPU_SVT(cpu) ||
+ unlikely(test_bit(EDF_MIGRATED, &d->ed_flags)) )
+ einf->avt = CPU_SVT(cpu);
/* Deal with warping here. */
- inf->evt = calc_evt(d, inf->avt);
+ einf->evt = calc_evt(d, einf->avt);
curr = schedule_data[cpu].curr;
curr_evt = calc_evt(curr, calc_avt(curr, now));
/* Calculate the time the current domain would run assuming
the second smallest evt is of the newly woken domain */
r_time = curr->lastschd +
- ((inf->evt - curr_evt) / BVT_INFO(curr)->mcu_advance) +
+ ((einf->evt - curr_evt) / BVT_INFO(curr->domain)->mcu_advance) +
ctx_allow;
- if ( is_idle_task(curr) || (inf->evt <= curr_evt) )
+ if ( is_idle_task(curr->domain) || (einf->evt <= curr_evt) )
cpu_raise_softirq(cpu, SCHEDULE_SOFTIRQ);
else if ( schedule_data[cpu].s_timer.expires > r_time )
mod_ac_timer(&schedule_data[cpu].s_timer, r_time);
}
-static void bvt_sleep(struct domain *d)
+static void bvt_sleep(struct exec_domain *d)
{
- if ( test_bit(DF_RUNNING, &d->flags) )
+ if ( test_bit(EDF_RUNNING, &d->ed_flags) )
cpu_raise_softirq(d->processor, SCHEDULE_SOFTIRQ);
else if ( __task_on_runqueue(d) )
__del_from_runqueue(d);
@@ -274,7 +293,7 @@ static void bvt_sleep(struct domain *d)
void bvt_free_task(struct domain *d)
{
ASSERT(d->sched_priv != NULL);
- xmem_cache_free(dom_info_cache, d->sched_priv);
+ xfree(d->sched_priv);
}
/* Control the scheduler. */
@@ -347,24 +366,26 @@ int bvt_adjdom(
*/
static task_slice_t bvt_do_schedule(s_time_t now)
{
- struct domain *prev = current, *next = NULL, *next_prime, *p;
+ struct domain *d;
+ struct exec_domain *prev = current, *next = NULL, *next_prime, *ed;
int cpu = prev->processor;
s32 r_time; /* time for new dom to run */
u32 next_evt, next_prime_evt, min_avt;
- struct bvt_dom_info *prev_inf = BVT_INFO(prev);
- struct bvt_dom_info *p_inf = NULL;
- struct bvt_dom_info *next_inf = NULL;
- struct bvt_dom_info *next_prime_inf = NULL;
+ struct bvt_dom_info *prev_inf = BVT_INFO(prev->domain);
+ struct bvt_edom_info *prev_einf = EBVT_INFO(prev);
+ struct bvt_edom_info *p_einf = NULL;
+ struct bvt_edom_info *next_einf = NULL;
+ struct bvt_edom_info *next_prime_einf = NULL;
task_slice_t ret;
- ASSERT(prev->sched_priv != NULL);
- ASSERT(prev_inf != NULL);
+ ASSERT(prev->ed_sched_priv != NULL);
+ ASSERT(prev_einf != NULL);
ASSERT(__task_on_runqueue(prev));
- if ( likely(!is_idle_task(prev)) )
+ if ( likely(!is_idle_task(prev->domain)) )
{
- prev_inf->avt = calc_avt(prev, now);
- prev_inf->evt = calc_evt(prev, prev_inf->avt);
+ prev_einf->avt = calc_avt(prev, now);
+ prev_einf->evt = calc_evt(prev, prev_einf->avt);
if(prev_inf->warpback && prev_inf->warpl > 0)
rem_ac_timer(&prev_inf->warp_timer);
@@ -384,49 +405,49 @@ static task_slice_t bvt_do_schedule(s_time_t now)
* *and* the task the second lowest evt.
* this code is O(n) but we expect n to be small.
*/
- next_inf = BVT_INFO(schedule_data[cpu].idle);
- next_prime_inf = NULL;
+ next_einf = EBVT_INFO(schedule_data[cpu].idle);
+ next_prime_einf = NULL;
next_evt = ~0U;
next_prime_evt = ~0U;
min_avt = ~0U;
- list_for_each_entry ( p_inf, RUNQUEUE(cpu), run_list )
+ list_for_each_entry ( p_einf, RUNQUEUE(cpu), run_list )
{
- if ( p_inf->evt < next_evt )
+ if ( p_einf->evt < next_evt )
{
- next_prime_inf = next_inf;
+ next_prime_einf = next_einf;
next_prime_evt = next_evt;
- next_inf = p_inf;
- next_evt = p_inf->evt;
+ next_einf = p_einf;
+ next_evt = p_einf->evt;
}
else if ( next_prime_evt == ~0U )
{
- next_prime_evt = p_inf->evt;
- next_prime_inf = p_inf;
+ next_prime_evt = p_einf->evt;
+ next_prime_einf = p_einf;
}
- else if ( p_inf->evt < next_prime_evt )
+ else if ( p_einf->evt < next_prime_evt )
{
- next_prime_evt = p_inf->evt;
- next_prime_inf = p_inf;
+ next_prime_evt = p_einf->evt;
+ next_prime_einf = p_einf;
}
/* Determine system virtual time. */
- if ( p_inf->avt < min_avt )
- min_avt = p_inf->avt;
+ if ( p_einf->avt < min_avt )
+ min_avt = p_einf->avt;
}
- if(next_inf->warp && next_inf->warpl > 0)
+ if(next_einf->inf->warp && next_einf->inf->warpl > 0)
{
/* Set the timer up */
- next_inf->warp_timer.expires = now + next_inf->warpl;
+ next_einf->inf->warp_timer.expires = now + next_einf->inf->warpl;
/* Add it to the heap */
- add_ac_timer(&next_inf->warp_timer);
+ add_ac_timer(&next_einf->inf->warp_timer);
}
/* Extract the domain pointers from the dom infos */
- next = next_inf->domain;
- next_prime = next_prime_inf->domain;
+ next = next_einf->exec_domain;
+ next_prime = next_prime_einf->exec_domain;
/* Update system virtual time. */
if ( min_avt != ~0U )
@@ -439,13 +460,15 @@ static task_slice_t bvt_do_schedule(s_time_t now)
write_lock(&domlist_lock);
- for_each_domain ( p )
+ for_each_domain ( d )
{
- if ( p->processor == cpu )
- {
- p_inf = BVT_INFO(p);
- p_inf->evt -= 0xe0000000;
- p_inf->avt -= 0xe0000000;
+ for_each_exec_domain (d, ed) {
+ if ( ed->processor == cpu )
+ {
+ p_einf = EBVT_INFO(ed);
+ p_einf->evt -= 0xe0000000;
+ p_einf->avt -= 0xe0000000;
+ }
}
}
@@ -455,13 +478,13 @@ static task_slice_t bvt_do_schedule(s_time_t now)
}
/* work out time for next run through scheduler */
- if ( is_idle_task(next) )
+ if ( is_idle_task(next->domain) )
{
r_time = ctx_allow;
goto sched_done;
}
- if ( (next_prime == NULL) || is_idle_task(next_prime) )
+ if ( (next_prime == NULL) || is_idle_task(next_prime->domain) )
{
/* We have only one runnable task besides the idle task. */
r_time = 10 * ctx_allow; /* RN: random constant */
@@ -473,9 +496,9 @@ static task_slice_t bvt_do_schedule(s_time_t now)
* Work out how long 'next' can run till its evt is greater than
* 'next_prime's evt. Take context switch allowance into account.
*/
- ASSERT(next_prime_inf->evt >= next_inf->evt);
+ ASSERT(next_prime_einf->evt >= next_einf->evt);
- r_time = ((next_prime_inf->evt - next_inf->evt)/next_inf->mcu_advance)
+ r_time = ((next_prime_einf->evt - next_einf->evt)/next_einf->inf->mcu_advance)
+ ctx_allow;
ASSERT(r_time >= ctx_allow);
@@ -487,12 +510,12 @@ static task_slice_t bvt_do_schedule(s_time_t now)
}
-static void bvt_dump_runq_el(struct domain *p)
+static void bvt_dump_runq_el(struct exec_domain *p)
{
- struct bvt_dom_info *inf = BVT_INFO(p);
+ struct bvt_edom_info *inf = EBVT_INFO(p);
printk("mcua=%d ev=0x%08X av=0x%08X ",
- inf->mcu_advance, inf->evt, inf->avt);
+ inf->inf->mcu_advance, inf->evt, inf->avt);
}
static void bvt_dump_settings(void)
@@ -504,8 +527,8 @@ static void bvt_dump_cpu_state(int i)
{
struct list_head *queue;
int loop = 0;
- struct bvt_dom_info *d_inf;
- struct domain *d;
+ struct bvt_edom_info *d_inf;
+ struct exec_domain *d;
printk("svt=0x%08lX ", CPU_SVT(i));
@@ -515,9 +538,9 @@ static void bvt_dump_cpu_state(int i)
list_for_each_entry ( d_inf, queue, run_list )
{
- d = d_inf->domain;
- printk("%3d: %u has=%c ", loop++, d->id,
- test_bit(DF_RUNNING, &d->flags) ? 'T':'F');
+ d = d_inf->exec_domain;
+ printk("%3d: %u has=%c ", loop++, d->domain->id,
+ test_bit(EDF_RUNNING, &d->ed_flags) ? 'T':'F');
bvt_dump_runq_el(d);
printk("c=0x%X%08X\n", (u32)(d->cpu_time>>32), (u32)d->cpu_time);
printk(" l: %p n: %p p: %p\n",
@@ -532,7 +555,7 @@ int bvt_init_scheduler()
for ( i = 0; i < NR_CPUS; i++ )
{
- schedule_data[i].sched_priv = xmalloc(sizeof(struct bvt_cpu_info));
+ schedule_data[i].sched_priv = xmalloc(struct bvt_cpu_info);
if ( schedule_data[i].sched_priv == NULL )
{
@@ -545,14 +568,6 @@ int bvt_init_scheduler()
CPU_SVT(i) = 0; /* XXX do I really need to do this? */
}
- dom_info_cache = xmem_cache_create(
- "BVT dom info", sizeof(struct bvt_dom_info), 0, 0, NULL, NULL);
- if ( dom_info_cache == NULL )
- {
- printk("BVT: Failed to allocate domain info SLAB cache");
- return -1;
- }
-
return 0;
}
diff --git a/xen/common/sched_rrobin.c b/xen/common/sched_rrobin.c
index 2164ce22b4..469fa007a2 100644
--- a/xen/common/sched_rrobin.c
+++ b/xen/common/sched_rrobin.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/****************************************************************************
* Round Robin Scheduler for Xen
*
@@ -27,8 +28,6 @@ struct rrobin_dom_info
#define RUNLIST(d) ((struct list_head *)&(RR_INFO(d)->run_list))
#define RUNQUEUE(cpu) RUNLIST(schedule_data[cpu].idle)
-static xmem_cache_t *dom_info_cache;
-
static inline void __add_to_runqueue_head(struct domain *d)
{
list_add(RUNLIST(d), RUNQUEUE(d->processor));
@@ -59,21 +58,12 @@ static int rr_init_scheduler()
for ( i = 0; i < NR_CPUS; i++ )
INIT_LIST_HEAD(RUNQUEUE(i));
- dom_info_cache = xmem_cache_create(
- "RR dom info", sizeof(struct rrobin_dom_info), 0, 0, 0, NULL);
- if ( dom_info_cache == NULL )
- {
- printk("Could not allocate SLAB cache.\n");
- return -1;
- }
-
return 0;
}
-
/* Allocates memory for per domain private scheduling data*/
static int rr_alloc_task(struct domain *d)
{
- if ( (d->sched_priv = xmem_cache_alloc(dom_info_cache)) == NULL )
+ if ( (d->sched_priv = new(struct rrobin_dom_info) == NULL )
return -1;
memset(d->sched_priv, 0, sizeof(struct rrobin_dom_info));
return 0;
@@ -91,7 +81,7 @@ static void rr_add_task(struct domain *d)
static void rr_free_task(struct domain *d)
{
ASSERT(d->sched_priv != NULL);
- xmem_cache_free(dom_info_cache, d->sched_priv);
+ xfree(d->sched_priv);
}
/* Initialises idle task */
diff --git a/xen/common/schedule.c b/xen/common/schedule.c
index ec215d5ed9..f5c6daa77a 100644
--- a/xen/common/schedule.c
+++ b/xen/common/schedule.c
@@ -1,4 +1,4 @@
-/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*-
****************************************************************************
* (C) 2002-2003 - Rolf Neugebauer - Intel Research Cambridge
* (C) 2002-2003 University of Cambridge
@@ -70,12 +70,12 @@ static void dom_timer_fn(unsigned long data);
schedule_data_t schedule_data[NR_CPUS];
extern struct scheduler sched_bvt_def;
-extern struct scheduler sched_rrobin_def;
-extern struct scheduler sched_atropos_def;
+// extern struct scheduler sched_rrobin_def;
+// extern struct scheduler sched_atropos_def;
static struct scheduler *schedulers[] = {
&sched_bvt_def,
- &sched_rrobin_def,
- &sched_atropos_def,
+// &sched_rrobin_def,
+// &sched_atropos_def,
NULL
};
@@ -91,10 +91,60 @@ static struct ac_timer t_timer[NR_CPUS];
void free_domain_struct(struct domain *d)
{
+ struct exec_domain *ed;
+
SCHED_OP(free_task, d);
+ for_each_exec_domain(d, ed)
+ arch_free_exec_domain_struct(ed);
arch_free_domain_struct(d);
}
+struct exec_domain *alloc_exec_domain_struct(struct domain *d,
+ unsigned long vcpu)
+{
+ struct exec_domain *ed, *edc;
+
+ ASSERT( d->exec_domain[vcpu] == NULL );
+
+ if ( (ed = arch_alloc_exec_domain_struct()) == NULL )
+ return NULL;
+
+ memset(ed, 0, sizeof(*ed));
+
+ d->exec_domain[vcpu] = ed;
+ ed->domain = d;
+ ed->eid = vcpu;
+
+ if ( SCHED_OP(alloc_task, ed) < 0 )
+ goto out;
+
+ if (vcpu != 0) {
+ ed->vcpu_info = &d->shared_info->vcpu_data[ed->eid];
+
+ for_each_exec_domain(d, edc) {
+ if (edc->ed_next_list == NULL || edc->ed_next_list->eid > vcpu)
+ break;
+ }
+ ed->ed_next_list = edc->ed_next_list;
+ edc->ed_next_list = ed;
+
+ if (test_bit(EDF_CPUPINNED, &edc->ed_flags)) {
+ ed->processor = (edc->processor + 1) % smp_num_cpus;
+ set_bit(EDF_CPUPINNED, &ed->ed_flags);
+ } else {
+ ed->processor = (edc->processor + 1) % smp_num_cpus; /* XXX */
+ }
+ }
+
+ return ed;
+
+ out:
+ d->exec_domain[vcpu] = NULL;
+ arch_free_exec_domain_struct(ed);
+
+ return NULL;
+}
+
struct domain *alloc_domain_struct(void)
{
struct domain *d;
@@ -104,46 +154,50 @@ struct domain *alloc_domain_struct(void)
memset(d, 0, sizeof(*d));
- if ( SCHED_OP(alloc_task, d) < 0 )
- {
- arch_free_domain_struct(d);
- return NULL;
- }
+ if ( alloc_exec_domain_struct(d, 0) == NULL )
+ goto out;
return d;
+
+ out:
+ arch_free_domain_struct(d);
+ return NULL;
}
/*
* Add and remove a domain
*/
-void sched_add_domain(struct domain *d)
+void sched_add_domain(struct exec_domain *ed)
{
+ struct domain *d = ed->domain;
+
/* Must be unpaused by control software to start execution. */
- set_bit(DF_CTRLPAUSE, &d->flags);
+ set_bit(EDF_CTRLPAUSE, &ed->ed_flags);
if ( d->id != IDLE_DOMAIN_ID )
{
/* Initialise the per-domain timer. */
- init_ac_timer(&d->timer);
- d->timer.cpu = d->processor;
- d->timer.data = (unsigned long)d;
- d->timer.function = &dom_timer_fn;
+ init_ac_timer(&ed->timer);
+ ed->timer.cpu = ed->processor;
+ ed->timer.data = (unsigned long)ed;
+ ed->timer.function = &dom_timer_fn;
}
else
{
- schedule_data[d->processor].idle = d;
+ schedule_data[ed->processor].idle = ed;
}
- SCHED_OP(add_task, d);
+ SCHED_OP(add_task, ed);
- TRACE_2D(TRC_SCHED_DOM_ADD, d->id, d);
+ TRACE_2D(TRC_SCHED_DOM_ADD, d->id, ed);
}
-void sched_rem_domain(struct domain *d)
+void sched_rem_domain(struct exec_domain *ed)
{
- rem_ac_timer(&d->timer);
- SCHED_OP(rem_task, d);
- TRACE_2D(TRC_SCHED_DOM_REM, d->id, d);
+
+ rem_ac_timer(&ed->timer);
+ SCHED_OP(rem_task, ed);
+ TRACE_3D(TRC_SCHED_DOM_REM, ed->domain->id, ed->eid, ed);
}
void init_idle_task(void)
@@ -152,7 +206,7 @@ void init_idle_task(void)
BUG();
}
-void domain_sleep(struct domain *d)
+void domain_sleep(struct exec_domain *d)
{
unsigned long flags;
@@ -164,40 +218,40 @@ void domain_sleep(struct domain *d)
spin_unlock_irqrestore(&schedule_data[d->processor].schedule_lock, flags);
/* Synchronous. */
- while ( test_bit(DF_RUNNING, &d->flags) && !domain_runnable(d) )
+ while ( test_bit(EDF_RUNNING, &d->ed_flags) && !domain_runnable(d) )
{
smp_mb();
cpu_relax();
}
}
-void domain_wake(struct domain *d)
+void domain_wake(struct exec_domain *ed)
{
unsigned long flags;
- spin_lock_irqsave(&schedule_data[d->processor].schedule_lock, flags);
+ spin_lock_irqsave(&schedule_data[ed->processor].schedule_lock, flags);
- if ( likely(domain_runnable(d)) )
+ if ( likely(domain_runnable(ed)) )
{
- TRACE_2D(TRC_SCHED_WAKE, d->id, d);
- SCHED_OP(wake, d);
+ TRACE_2D(TRC_SCHED_WAKE, ed->domain->id, ed);
+ SCHED_OP(wake, ed);
#ifdef WAKE_HISTO
- d->wokenup = NOW();
+ ed->wokenup = NOW();
#endif
}
- clear_bit(DF_MIGRATED, &d->flags);
+ clear_bit(EDF_MIGRATED, &ed->ed_flags);
- spin_unlock_irqrestore(&schedule_data[d->processor].schedule_lock, flags);
+ spin_unlock_irqrestore(&schedule_data[ed->processor].schedule_lock, flags);
}
/* Block the currently-executing domain until a pertinent event occurs. */
long do_block(void)
{
- ASSERT(current->id != IDLE_DOMAIN_ID);
- current->shared_info->vcpu_data[0].evtchn_upcall_mask = 0;
- set_bit(DF_BLOCKED, &current->flags);
- TRACE_2D(TRC_SCHED_BLOCK, current->id, current);
+ ASSERT(current->domain->id != IDLE_DOMAIN_ID);
+ current->vcpu_info->evtchn_upcall_mask = 0;
+ set_bit(EDF_BLOCKED, &current->ed_flags);
+ TRACE_2D(TRC_SCHED_BLOCK, current->domain->id, current);
__enter_scheduler();
return 0;
}
@@ -205,7 +259,7 @@ long do_block(void)
/* Voluntarily yield the processor for this allocation. */
static long do_yield(void)
{
- TRACE_2D(TRC_SCHED_YIELD, current->id, current);
+ TRACE_2D(TRC_SCHED_YIELD, current->domain->id, current);
__enter_scheduler();
return 0;
}
@@ -248,7 +302,7 @@ long do_sched_op(unsigned long op)
/* Per-domain one-shot-timer hypercall. */
long do_set_timer_op(unsigned long timeout_hi, unsigned long timeout_lo)
{
- struct domain *p = current;
+ struct exec_domain *p = current;
rem_ac_timer(&p->timer);
@@ -258,7 +312,8 @@ long do_set_timer_op(unsigned long timeout_hi, unsigned long timeout_lo)
add_ac_timer(&p->timer);
}
- TRACE_4D(TRC_SCHED_SET_TIMER, p->id, p, timeout_hi, timeout_lo);
+ TRACE_5D(TRC_SCHED_SET_TIMER, p->domain->id, p->eid, p, timeout_hi,
+ timeout_lo);
return 0;
}
@@ -297,9 +352,9 @@ long sched_adjdom(struct sched_adjdom_cmd *cmd)
TRACE_1D(TRC_SCHED_ADJDOM, d->id);
- spin_lock_irq(&schedule_data[d->processor].schedule_lock);
+ spin_lock_irq(&schedule_data[d->exec_domain[0]->processor].schedule_lock);
SCHED_OP(adjdom, d, cmd);
- spin_unlock_irq(&schedule_data[d->processor].schedule_lock);
+ spin_unlock_irq(&schedule_data[d->exec_domain[0]->processor].schedule_lock);
put_domain(d);
return 0;
@@ -312,7 +367,7 @@ long sched_adjdom(struct sched_adjdom_cmd *cmd)
*/
void __enter_scheduler(void)
{
- struct domain *prev = current, *next = NULL;
+ struct exec_domain *prev = current, *next = NULL;
int cpu = prev->processor;
s_time_t now;
task_slice_t next_slice;
@@ -328,11 +383,11 @@ void __enter_scheduler(void)
ASSERT(!in_irq());
- if ( test_bit(DF_BLOCKED, &prev->flags) )
+ if ( test_bit(EDF_BLOCKED, &prev->ed_flags) )
{
/* This check is needed to avoid a race condition. */
if ( event_pending(prev) )
- clear_bit(DF_BLOCKED, &prev->flags);
+ clear_bit(EDF_BLOCKED, &prev->ed_flags);
else
SCHED_OP(do_block, prev);
}
@@ -354,20 +409,25 @@ void __enter_scheduler(void)
add_ac_timer(&schedule_data[cpu].s_timer);
/* Must be protected by the schedule_lock! */
- set_bit(DF_RUNNING, &next->flags);
+ set_bit(EDF_RUNNING, &next->ed_flags);
spin_unlock_irq(&schedule_data[cpu].schedule_lock);
/* Ensure that the domain has an up-to-date time base. */
- if ( !is_idle_task(next) )
- update_dom_time(next->shared_info);
+ if ( !is_idle_task(next->domain) )
+ update_dom_time(next->domain);
if ( unlikely(prev == next) )
return;
perfc_incrc(sched_ctx);
- cleanup_writable_pagetable(prev);
+ if ( !is_idle_task(prev->domain) )
+ {
+ LOCK_BIGLOCK(prev->domain);
+ cleanup_writable_pagetable(prev->domain);
+ UNLOCK_BIGLOCK(prev->domain);
+ }
#if defined(WAKE_HISTO)
if ( !is_idle_task(next) && next->wokenup ) {
@@ -387,7 +447,7 @@ void __enter_scheduler(void)
}
#endif
- TRACE_2D(TRC_SCHED_SWITCH, next->id, next);
+ TRACE_2D(TRC_SCHED_SWITCH, next->domain->id, next);
switch_to(prev, next);
@@ -397,10 +457,10 @@ void __enter_scheduler(void)
* 'prev' (after this point, a dying domain's info structure may be freed
* without warning).
*/
- clear_bit(DF_RUNNING, &prev->flags);
+ clear_bit(EDF_RUNNING, &prev->ed_flags);
/* Mark a timer event for the newly-scheduled domain. */
- if ( !is_idle_task(next) )
+ if ( !is_idle_task(next->domain) )
send_guest_virq(next, VIRQ_TIMER);
schedule_tail(next);
@@ -411,7 +471,7 @@ void __enter_scheduler(void)
/* No locking needed -- pointer comparison is safe :-) */
int idle_cpu(int cpu)
{
- struct domain *p = schedule_data[cpu].curr;
+ struct exec_domain *p = schedule_data[cpu].curr;
return p == idle_task[cpu];
}
@@ -434,27 +494,28 @@ static void s_timer_fn(unsigned long unused)
/* Periodic tick timer: send timer event to current domain*/
static void t_timer_fn(unsigned long unused)
{
- struct domain *d = current;
+ struct exec_domain *ed = current;
TRACE_0D(TRC_SCHED_T_TIMER_FN);
- if ( !is_idle_task(d) )
+ if ( !is_idle_task(ed->domain) )
{
- update_dom_time(d->shared_info);
- send_guest_virq(d, VIRQ_TIMER);
+ update_dom_time(ed->domain);
+ send_guest_virq(ed, VIRQ_TIMER);
}
- t_timer[d->processor].expires = NOW() + MILLISECS(10);
- add_ac_timer(&t_timer[d->processor]);
+ t_timer[ed->processor].expires = NOW() + MILLISECS(10);
+ add_ac_timer(&t_timer[ed->processor]);
}
/* Domain timer function, sends a virtual timer interrupt to domain */
static void dom_timer_fn(unsigned long data)
{
- struct domain *d = (struct domain *)data;
+ struct exec_domain *ed = (struct exec_domain *)data;
+
TRACE_0D(TRC_SCHED_DOM_TIMER_FN);
- update_dom_time(d->shared_info);
- send_guest_virq(d, VIRQ_TIMER);
+ update_dom_time(ed->domain);
+ send_guest_virq(ed, VIRQ_TIMER);
}
/* Initialise the data structures. */
@@ -467,7 +528,7 @@ void __init scheduler_init(void)
for ( i = 0; i < NR_CPUS; i++ )
{
spin_lock_init(&schedule_data[i].schedule_lock);
- schedule_data[i].curr = &idle0_task;
+ schedule_data[i].curr = &idle0_exec_domain;
init_ac_timer(&schedule_data[i].s_timer);
schedule_data[i].s_timer.cpu = i;
@@ -480,7 +541,7 @@ void __init scheduler_init(void)
t_timer[i].function = &t_timer_fn;
}
- schedule_data[0].idle = &idle0_task;
+ schedule_data[0].idle = &idle0_exec_domain;
for ( i = 0; schedulers[i] != NULL; i++ )
{
diff --git a/xen/common/slab.c b/xen/common/slab.c
deleted file mode 100644
index cfbf402261..0000000000
--- a/xen/common/slab.c
+++ /dev/null
@@ -1,1844 +0,0 @@
-/*
- * linux/mm/slab.c
- * Written by Mark Hemment, 1996/97.
- * (markhe@nextd.demon.co.uk)
- *
- * xmem_cache_destroy() + some cleanup - 1999 Andrea Arcangeli
- *
- * Major cleanup, different bufctl logic, per-cpu arrays
- * (c) 2000 Manfred Spraul
- *
- * An implementation of the Slab Allocator as described in outline in;
- * UNIX Internals: The New Frontiers by Uresh Vahalia
- * Pub: Prentice Hall ISBN 0-13-101908-2
- * or with a little more detail in;
- * The Slab Allocator: An Object-Caching Kernel Memory Allocator
- * Jeff Bonwick (Sun Microsystems).
- * Presented at: USENIX Summer 1994 Technical Conference
- *
- *
- * The memory is organized in caches, one cache for each object type.
- * (e.g. inode_cache, dentry_cache, buffer_head, vm_area_struct)
- * Each cache consists out of many slabs (they are small (usually one
- * page long) and always contiguous), and each slab contains multiple
- * initialized objects.
- *
- * In order to reduce fragmentation, the slabs are sorted in 3 groups:
- * full slabs with 0 free objects
- * partial slabs
- * empty slabs with no allocated objects
- *
- * If partial slabs exist, then new allocations come from these slabs,
- * otherwise from empty slabs or new slabs are allocated.
- *
- * xmem_cache_destroy() CAN CRASH if you try to allocate from the cache
- * during xmem_cache_destroy(). The caller must prevent concurrent allocs.
- *
- * On SMP systems, each cache has a short per-cpu head array, most allocs
- * and frees go into that array, and if that array overflows, then 1/2
- * of the entries in the array are given back into the global cache.
- * This reduces the number of spinlock operations.
- *
- * The c_cpuarray may not be read with enabled local interrupts.
- *
- * SMP synchronization:
- * constructors and destructors are called without any locking.
- * Several members in xmem_cache_t and slab_t never change, they
- * are accessed without any locking.
- * The per-cpu arrays are never accessed from the wrong cpu, no locking.
- * The non-constant members are protected with a per-cache irq spinlock.
- */
-
-#include <xen/config.h>
-#include <xen/init.h>
-#include <xen/types.h>
-#include <xen/lib.h>
-#include <xen/slab.h>
-#include <xen/list.h>
-#include <xen/spinlock.h>
-#include <xen/errno.h>
-#include <xen/smp.h>
-#include <xen/sched.h>
-
-/*
- * DEBUG - 1 for xmem_cache_create() to honour; SLAB_DEBUG_INITIAL,
- * SLAB_RED_ZONE & SLAB_POISON.
- * 0 for faster, smaller code (especially in the critical paths).
- *
- * STATS - 1 to collect stats for /proc/slabinfo.
- * 0 for faster, smaller code (especially in the critical paths).
- *
- * FORCED_DEBUG - 1 enables SLAB_RED_ZONE and SLAB_POISON (if possible)
- */
-#ifdef CONFIG_DEBUG_SLAB
-#define DEBUG 1
-#define STATS 1
-#define FORCED_DEBUG 1
-#else
-#define DEBUG 0
-#define STATS 0
-#define FORCED_DEBUG 0
-#endif
-
-/*
- * Parameters for xmem_cache_reap
- */
-#define REAP_SCANLEN 10
-#define REAP_PERFECT 10
-
-/* Shouldn't this be in a header file somewhere? */
-#define BYTES_PER_WORD sizeof(void *)
-
-/* Legal flag mask for xmem_cache_create(). */
-#if DEBUG
-#define CREATE_MASK (SLAB_DEBUG_INITIAL | SLAB_RED_ZONE | \
- SLAB_POISON | SLAB_HWCACHE_ALIGN | \
- SLAB_NO_REAP)
-#else
-#define CREATE_MASK (SLAB_HWCACHE_ALIGN | SLAB_NO_REAP)
-#endif
-
-/*
- * xmem_bufctl_t:
- *
- * Bufctl's are used for linking objs within a slab
- * linked offsets.
- *
- * This implementaion relies on "struct page" for locating the cache &
- * slab an object belongs to.
- * This allows the bufctl structure to be small (one int), but limits
- * the number of objects a slab (not a cache) can contain when off-slab
- * bufctls are used. The limit is the size of the largest general cache
- * that does not use off-slab slabs.
- * For 32bit archs with 4 kB pages, is this 56.
- * This is not serious, as it is only for large objects, when it is unwise
- * to have too many per slab.
- * Note: This limit can be raised by introducing a general cache whose size
- * is less than 512 (PAGE_SIZE<<3), but greater than 256.
- */
-
-#define BUFCTL_END (((xmem_bufctl_t)(~0U))-0)
-#define BUFCTL_FREE (((xmem_bufctl_t)(~0U))-1)
-#define SLAB_LIMIT (((xmem_bufctl_t)(~0U))-2)
-
-/* Max number of objs-per-slab for caches which use off-slab slabs.
- * Needed to avoid a possible looping condition in xmem_cache_grow().
- */
-static unsigned long offslab_limit;
-
-/*
- * slab_t
- *
- * Manages the objs in a slab. Placed either at the beginning of mem allocated
- * for a slab, or allocated from an general cache.
- * Slabs are chained into three list: fully used, partial, fully free slabs.
- */
-typedef struct slab_s {
- struct list_head list;
- unsigned long colouroff;
- void *s_mem; /* including colour offset */
- unsigned int inuse; /* num of objs active in slab */
- xmem_bufctl_t free;
-} slab_t;
-
-#define slab_bufctl(slabp) \
- ((xmem_bufctl_t *)(((slab_t*)slabp)+1))
-
-/*
- * cpucache_t
- *
- * Per cpu structures
- * The limit is stored in the per-cpu structure to reduce the data cache
- * footprint.
- */
-typedef struct cpucache_s {
- unsigned int avail;
- unsigned int limit;
-} cpucache_t;
-
-#define cc_entry(cpucache) \
- ((void **)(((cpucache_t*)(cpucache))+1))
-#define cc_data(cachep) \
- ((cachep)->cpudata[smp_processor_id()])
-/*
- * xmem_cache_t
- *
- * manages a cache.
- */
-
-#define CACHE_NAMELEN 20 /* max name length for a slab cache */
-
-struct xmem_cache_s {
-/* 1) each alloc & free */
- /* full, partial first, then free */
- struct list_head slabs_full;
- struct list_head slabs_partial;
- struct list_head slabs_free;
- unsigned int objsize;
- unsigned int flags; /* constant flags */
- unsigned int num; /* # of objs per slab */
- spinlock_t spinlock;
-#ifdef CONFIG_SMP
- unsigned int batchcount;
-#endif
-
-/* 2) slab additions /removals */
- /* order of pgs per slab (2^n) */
- unsigned int gfporder;
- size_t colour; /* cache colouring range */
- unsigned int colour_off; /* colour offset */
- unsigned int colour_next; /* cache colouring */
- xmem_cache_t *slabp_cache;
- unsigned int growing;
- unsigned int dflags; /* dynamic flags */
-
- /* constructor func */
- void (*ctor)(void *, xmem_cache_t *, unsigned long);
-
- /* de-constructor func */
- void (*dtor)(void *, xmem_cache_t *, unsigned long);
-
- unsigned long failures;
-
-/* 3) cache creation/removal */
- char name[CACHE_NAMELEN];
- struct list_head next;
-#ifdef CONFIG_SMP
-/* 4) per-cpu data */
- cpucache_t *cpudata[NR_CPUS];
-#endif
-#if STATS
- unsigned long num_active;
- unsigned long num_allocations;
- unsigned long high_mark;
- unsigned long grown;
- unsigned long reaped;
- unsigned long errors;
-#ifdef CONFIG_SMP
- atomic_t allochit;
- atomic_t allocmiss;
- atomic_t freehit;
- atomic_t freemiss;
-#endif
-#endif
-};
-
-/* internal c_flags */
-#define CFLGS_OFF_SLAB 0x010000UL /* slab management in own cache */
-#define CFLGS_OPTIMIZE 0x020000UL /* optimized slab lookup */
-
-/* c_dflags (dynamic flags). Need to hold the spinlock to access this member */
-#define DFLGS_GROWN 0x000001UL /* don't reap a recently grown */
-
-#define OFF_SLAB(x) ((x)->flags & CFLGS_OFF_SLAB)
-#define OPTIMIZE(x) ((x)->flags & CFLGS_OPTIMIZE)
-#define GROWN(x) ((x)->dlags & DFLGS_GROWN)
-
-#if STATS
-#define STATS_INC_ACTIVE(x) ((x)->num_active++)
-#define STATS_DEC_ACTIVE(x) ((x)->num_active--)
-#define STATS_INC_ALLOCED(x) ((x)->num_allocations++)
-#define STATS_INC_GROWN(x) ((x)->grown++)
-#define STATS_INC_REAPED(x) ((x)->reaped++)
-#define STATS_SET_HIGH(x) do { if ((x)->num_active > (x)->high_mark) \
- (x)->high_mark = (x)->num_active; \
- } while (0)
-#define STATS_INC_ERR(x) ((x)->errors++)
-#else
-#define STATS_INC_ACTIVE(x) do { } while (0)
-#define STATS_DEC_ACTIVE(x) do { } while (0)
-#define STATS_INC_ALLOCED(x) do { } while (0)
-#define STATS_INC_GROWN(x) do { } while (0)
-#define STATS_INC_REAPED(x) do { } while (0)
-#define STATS_SET_HIGH(x) do { } while (0)
-#define STATS_INC_ERR(x) do { } while (0)
-#endif
-
-#if STATS && defined(CONFIG_SMP)
-#define STATS_INC_ALLOCHIT(x) atomic_inc(&(x)->allochit)
-#define STATS_INC_ALLOCMISS(x) atomic_inc(&(x)->allocmiss)
-#define STATS_INC_FREEHIT(x) atomic_inc(&(x)->freehit)
-#define STATS_INC_FREEMISS(x) atomic_inc(&(x)->freemiss)
-#else
-#define STATS_INC_ALLOCHIT(x) do { } while (0)
-#define STATS_INC_ALLOCMISS(x) do { } while (0)
-#define STATS_INC_FREEHIT(x) do { } while (0)
-#define STATS_INC_FREEMISS(x) do { } while (0)
-#endif
-
-#if DEBUG
-/* Magic nums for obj red zoning.
- * Placed in the first word before and the first word after an obj.
- */
-#define RED_MAGIC1 0x5A2CF071UL /* when obj is active */
-#define RED_MAGIC2 0x170FC2A5UL /* when obj is inactive */
-
-/* ...and for poisoning */
-#define POISON_BYTE 0x5a /* byte value for poisoning */
-#define POISON_END 0xa5 /* end-byte of poisoning */
-
-#endif
-
-/* maximum size of an obj (in 2^order pages) */
-#define MAX_OBJ_ORDER 5 /* 32 pages */
-
-/*
- * Do not go above this order unless 0 objects fit into the slab.
- */
-#define BREAK_GFP_ORDER_HI 2
-#define BREAK_GFP_ORDER_LO 1
-static int slab_break_gfp_order = BREAK_GFP_ORDER_LO;
-
-/*
- * Absolute limit for the gfp order
- */
-#define MAX_GFP_ORDER 5 /* 32 pages */
-
-
-/* Macros for storing/retrieving the cachep and or slab from the
- * global 'mem_map'. These are used to find the slab an obj belongs to.
- * With xfree(), these are used to find the cache which an obj belongs to.
- */
-#define SET_PAGE_CACHE(pg,x) ((pg)->list.next = (struct list_head *)(x))
-#define GET_PAGE_CACHE(pg) ((xmem_cache_t *)(pg)->list.next)
-#define SET_PAGE_SLAB(pg,x) ((pg)->list.prev = (struct list_head *)(x))
-#define GET_PAGE_SLAB(pg) ((slab_t *)(pg)->list.prev)
-
-/* Size description struct for general caches. */
-typedef struct cache_sizes {
- size_t cs_size;
- xmem_cache_t *cs_cachep;
-} cache_sizes_t;
-
-static cache_sizes_t cache_sizes[] = {
- { 32, NULL},
- { 64, NULL},
- { 128, NULL},
- { 256, NULL},
- { 512, NULL},
- { 1024, NULL},
- { 2048, NULL},
- { 4096, NULL},
- { 8192, NULL},
- { 16384, NULL},
- { 32768, NULL},
- { 65536, NULL},
- { 0, NULL}
-};
-
-/* internal cache of cache description objs */
-static xmem_cache_t cache_cache = {
- slabs_full: LIST_HEAD_INIT(cache_cache.slabs_full),
- slabs_partial: LIST_HEAD_INIT(cache_cache.slabs_partial),
- slabs_free: LIST_HEAD_INIT(cache_cache.slabs_free),
- objsize: sizeof(xmem_cache_t),
- flags: SLAB_NO_REAP,
- spinlock: SPIN_LOCK_UNLOCKED,
- colour_off: L1_CACHE_BYTES,
- name: "xmem_cache"
-};
-
-/* Guard access to the cache-chain. */
-/* KAF: No semaphores, as we'll never wait around for I/O. */
-static spinlock_t cache_chain_sem;
-#define init_MUTEX(_m) spin_lock_init(_m)
-#define down(_m) spin_lock_irqsave(_m,spin_flags)
-#define up(_m) spin_unlock_irqrestore(_m,spin_flags)
-
-/* Place maintainer for reaping. */
-static xmem_cache_t *clock_searchp = &cache_cache;
-
-#define cache_chain (cache_cache.next)
-
-#ifdef CONFIG_SMP
-/*
- * chicken and egg problem: delay the per-cpu array allocation
- * until the general caches are up.
- */
-static int g_cpucache_up;
-
-static void enable_cpucache (xmem_cache_t *cachep);
-static void enable_all_cpucaches (void);
-#endif
-
-/* Cal the num objs, wastage, and bytes left over for a given slab size. */
-static void xmem_cache_estimate (unsigned long gfporder, size_t size,
- int flags, size_t *left_over, unsigned int *num)
-{
- int i;
- size_t wastage = PAGE_SIZE<<gfporder;
- size_t extra = 0;
- size_t base = 0;
-
- if (!(flags & CFLGS_OFF_SLAB)) {
- base = sizeof(slab_t);
- extra = sizeof(xmem_bufctl_t);
- }
- i = 0;
- while (i*size + L1_CACHE_ALIGN(base+i*extra) <= wastage)
- i++;
- if (i > 0)
- i--;
-
- if (i > SLAB_LIMIT)
- i = SLAB_LIMIT;
-
- *num = i;
- wastage -= i*size;
- wastage -= L1_CACHE_ALIGN(base+i*extra);
- *left_over = wastage;
-}
-
-/* Initialisation - setup the `cache' cache. */
-void __init xmem_cache_init(void)
-{
- size_t left_over;
-
- init_MUTEX(&cache_chain_sem);
- INIT_LIST_HEAD(&cache_chain);
-
- xmem_cache_estimate(0, cache_cache.objsize, 0,
- &left_over, &cache_cache.num);
- if (!cache_cache.num)
- BUG();
-
- cache_cache.colour = left_over/cache_cache.colour_off;
- cache_cache.colour_next = 0;
-}
-
-
-/* Initialisation - setup remaining internal and general caches.
- * Called after the gfp() functions have been enabled, and before smp_init().
- */
-void __init xmem_cache_sizes_init(unsigned long num_physpages)
-{
- cache_sizes_t *sizes = cache_sizes;
- char name[20];
- /*
- * Fragmentation resistance on low memory - only use bigger
- * page orders on machines with more than 32MB of memory.
- */
- if (num_physpages > (32 << 20) >> PAGE_SHIFT)
- slab_break_gfp_order = BREAK_GFP_ORDER_HI;
- do {
- /* For performance, all the general caches are L1 aligned.
- * This should be particularly beneficial on SMP boxes, as it
- * eliminates "false sharing".
- * Note for systems short on memory removing the alignment will
- * allow tighter packing of the smaller caches. */
- sprintf(name,"size-%Zd",sizes->cs_size);
- if (!(sizes->cs_cachep =
- xmem_cache_create(name, sizes->cs_size,
- 0, SLAB_HWCACHE_ALIGN, NULL, NULL))) {
- BUG();
- }
-
- /* Inc off-slab bufctl limit until the ceiling is hit. */
- if (!(OFF_SLAB(sizes->cs_cachep))) {
- offslab_limit = sizes->cs_size-sizeof(slab_t);
- offslab_limit /= 2;
- }
- sizes++;
- } while (sizes->cs_size);
-}
-
-int __init xmem_cpucache_init(void)
-{
-#ifdef CONFIG_SMP
- g_cpucache_up = 1;
- enable_all_cpucaches();
-#endif
- return 0;
-}
-
-/*__initcall(xmem_cpucache_init);*/
-
-/* Interface to system's page allocator. No need to hold the cache-lock.
- */
-static inline void *xmem_getpages(xmem_cache_t *cachep)
-{
- void *addr;
-
- addr = (void*) alloc_xenheap_pages(cachep->gfporder);
- /* Assume that now we have the pages no one else can legally
- * messes with the 'struct page's.
- * However vm_scan() might try to test the structure to see if
- * it is a named-page or buffer-page. The members it tests are
- * of no interest here.....
- */
- return addr;
-}
-
-/* Interface to system's page release. */
-static inline void xmem_freepages (xmem_cache_t *cachep, void *addr)
-{
- unsigned long i = (1<<cachep->gfporder);
- struct pfn_info *page = virt_to_page(addr);
-
- /* free_xenheap_pages() does not clear the type bit - we do that.
- * The pages have been unlinked from their cache-slab,
- * but their 'struct page's might be accessed in
- * vm_scan(). Shouldn't be a worry.
- */
- while (i--) {
- PageClearSlab(page);
- page++;
- }
-
- free_xenheap_pages((unsigned long)addr, cachep->gfporder);
-}
-
-#if DEBUG
-static inline void xmem_poison_obj (xmem_cache_t *cachep, void *addr)
-{
- int size = cachep->objsize;
- if (cachep->flags & SLAB_RED_ZONE) {
- addr += BYTES_PER_WORD;
- size -= 2*BYTES_PER_WORD;
- }
- memset(addr, POISON_BYTE, size);
- *(unsigned char *)(addr+size-1) = POISON_END;
-}
-
-static inline int xmem_check_poison_obj (xmem_cache_t *cachep, void *addr)
-{
- int size = cachep->objsize;
- void *end;
- if (cachep->flags & SLAB_RED_ZONE) {
- addr += BYTES_PER_WORD;
- size -= 2*BYTES_PER_WORD;
- }
- end = memchr(addr, POISON_END, size);
- if (end != (addr+size-1))
- return 1;
- return 0;
-}
-#endif
-
-/* Destroy all the objs in a slab, and release the mem back to the system.
- * Before calling the slab must have been unlinked from the cache.
- * The cache-lock is not held/needed.
- */
-static void xmem_slab_destroy (xmem_cache_t *cachep, slab_t *slabp)
-{
- if (cachep->dtor
-#if DEBUG
- || cachep->flags & (SLAB_POISON | SLAB_RED_ZONE)
-#endif
- ) {
- int i;
- for (i = 0; i < cachep->num; i++) {
- void* objp = slabp->s_mem+cachep->objsize*i;
-#if DEBUG
- if (cachep->flags & SLAB_RED_ZONE) {
- if (*((unsigned long*)(objp)) != RED_MAGIC1)
- BUG();
- if (*((unsigned long*)(objp + cachep->objsize
- -BYTES_PER_WORD)) != RED_MAGIC1)
- BUG();
- objp += BYTES_PER_WORD;
- }
-#endif
- if (cachep->dtor)
- (cachep->dtor)(objp, cachep, 0);
-#if DEBUG
- if (cachep->flags & SLAB_RED_ZONE) {
- objp -= BYTES_PER_WORD;
- }
- if ((cachep->flags & SLAB_POISON) &&
- xmem_check_poison_obj(cachep, objp))
- BUG();
-#endif
- }
- }
-
- xmem_freepages(cachep, slabp->s_mem-slabp->colouroff);
- if (OFF_SLAB(cachep))
- xmem_cache_free(cachep->slabp_cache, slabp);
-}
-
-/**
- * xmem_cache_create - Create a cache.
- * @name: A string which is used in /proc/slabinfo to identify this cache.
- * @size: The size of objects to be created in this cache.
- * @offset: The offset to use within the page.
- * @flags: SLAB flags
- * @ctor: A constructor for the objects.
- * @dtor: A destructor for the objects.
- *
- * Returns a ptr to the cache on success, NULL on failure.
- * Cannot be called within a int, but can be interrupted.
- * The @ctor is run when new pages are allocated by the cache
- * and the @dtor is run before the pages are handed back.
- * The flags are
- *
- * %SLAB_POISON - Poison the slab with a known test pattern (a5a5a5a5)
- * to catch references to uninitialised memory.
- *
- * %SLAB_RED_ZONE - Insert `Red' zones around the allocated memory to check
- * for buffer overruns.
- *
- * %SLAB_NO_REAP - Don't automatically reap this cache when we're under
- * memory pressure.
- *
- * %SLAB_HWCACHE_ALIGN - Align the objects in this cache to a hardware
- * cacheline. This can be beneficial if you're counting cycles as closely
- * as davem.
- */
-xmem_cache_t *
-xmem_cache_create (const char *name, size_t size, size_t offset,
- unsigned long flags,
- void (*ctor)(void*, xmem_cache_t *, unsigned long),
- void (*dtor)(void*, xmem_cache_t *, unsigned long))
-{
- const char *func_nm = KERN_ERR "xmem_create: ";
- size_t left_over, align, slab_size;
- xmem_cache_t *cachep = NULL;
- unsigned long spin_flags;
-
- /*
- * Sanity checks... these are all serious usage bugs.
- */
- if ((!name) ||
- ((strlen(name) >= CACHE_NAMELEN - 1)) ||
- (size < BYTES_PER_WORD) ||
- (size > (1<<MAX_OBJ_ORDER)*PAGE_SIZE) ||
- (dtor && !ctor) ||
- (offset < 0 || offset > size))
- BUG();
-
-#if DEBUG
- if ((flags & SLAB_DEBUG_INITIAL) && !ctor) {
- /* No constructor, but inital state check requested */
- printk("%sNo con, but init state check requested - %s\n",
- func_nm, name);
- flags &= ~SLAB_DEBUG_INITIAL;
- }
-
- if ((flags & SLAB_POISON) && ctor) {
- /* request for poisoning, but we can't do that with a constructor */
- printk("%sPoisoning requested, but con given - %s\n",
- func_nm, name);
- flags &= ~SLAB_POISON;
- }
-#if FORCED_DEBUG
- if (size < (PAGE_SIZE>>3))
- /*
- * do not red zone large object, causes severe
- * fragmentation.
- */
- flags |= SLAB_RED_ZONE;
- if (!ctor)
- flags |= SLAB_POISON;
-#endif
-#endif
-
- /*
- * Always checks flags, a caller might be expecting debug
- * support which isn't available.
- */
- if (flags & ~CREATE_MASK)
- BUG();
-
- /* Get cache's description obj. */
- cachep = (xmem_cache_t *)xmem_cache_alloc(&cache_cache);
- if (!cachep)
- goto opps;
- memset(cachep, 0, sizeof(xmem_cache_t));
-
- /* Check that size is in terms of words. This is needed to avoid
- * unaligned accesses for some archs when redzoning is used, and makes
- * sure any on-slab bufctl's are also correctly aligned.
- */
- if (size & (BYTES_PER_WORD-1)) {
- size += (BYTES_PER_WORD-1);
- size &= ~(BYTES_PER_WORD-1);
- printk("%sForcing size word alignment - %s\n", func_nm, name);
- }
-
-#if DEBUG
- if (flags & SLAB_RED_ZONE) {
- /*
- * There is no point trying to honour cache alignment
- * when redzoning.
- */
- flags &= ~SLAB_HWCACHE_ALIGN;
- size += 2*BYTES_PER_WORD; /* words for redzone */
- }
-#endif
- align = BYTES_PER_WORD;
- if (flags & SLAB_HWCACHE_ALIGN)
- align = L1_CACHE_BYTES;
-
- /* Determine if the slab management is 'on' or 'off' slab. */
- if (size >= (PAGE_SIZE>>3))
- /*
- * Size is large, assume best to place the slab management obj
- * off-slab (should allow better packing of objs).
- */
- flags |= CFLGS_OFF_SLAB;
-
- if (flags & SLAB_HWCACHE_ALIGN) {
- /* Need to adjust size so that objs are cache aligned. */
- /* Small obj size, can get at least two per cache line. */
- /* FIXME: only power of 2 supported, was better */
- while (size < align/2)
- align /= 2;
- size = (size+align-1)&(~(align-1));
- }
-
- /* Cal size (in pages) of slabs, and the num of objs per slab.
- * This could be made much more intelligent. For now, try to avoid
- * using high page-orders for slabs. When the gfp() funcs are more
- * friendly towards high-order requests, this should be changed.
- */
- do {
- unsigned int break_flag = 0;
- cal_wastage:
- xmem_cache_estimate(cachep->gfporder, size, flags,
- &left_over, &cachep->num);
- if (break_flag)
- break;
- if (cachep->gfporder >= MAX_GFP_ORDER)
- break;
- if (!cachep->num)
- goto next;
- if (flags & CFLGS_OFF_SLAB && cachep->num > offslab_limit) {
- /* Oops, this num of objs will cause problems. */
- cachep->gfporder--;
- break_flag++;
- goto cal_wastage;
- }
-
- /*
- * Large num of objs is good, but v. large slabs are currently
- * bad for the gfp()s.
- */
- if (cachep->gfporder >= slab_break_gfp_order)
- break;
-
- if ((left_over*8) <= (PAGE_SIZE<<cachep->gfporder))
- break; /* Acceptable internal fragmentation. */
- next:
- cachep->gfporder++;
- } while (1);
-
- if (!cachep->num) {
- printk("xmem_cache_create: couldn't create cache %s.\n", name);
- xmem_cache_free(&cache_cache, cachep);
- cachep = NULL;
- goto opps;
- }
- slab_size = L1_CACHE_ALIGN(cachep->num*sizeof(xmem_bufctl_t) +
- sizeof(slab_t));
-
- /*
- * If the slab has been placed off-slab, and we have enough space then
- * move it on-slab. This is at the expense of any extra colouring.
- */
- if (flags & CFLGS_OFF_SLAB && left_over >= slab_size) {
- flags &= ~CFLGS_OFF_SLAB;
- left_over -= slab_size;
- }
-
- /* Offset must be a multiple of the alignment. */
- offset += (align-1);
- offset &= ~(align-1);
- if (!offset)
- offset = L1_CACHE_BYTES;
- cachep->colour_off = offset;
- cachep->colour = left_over/offset;
-
- /* init remaining fields */
- if (!cachep->gfporder && !(flags & CFLGS_OFF_SLAB))
- flags |= CFLGS_OPTIMIZE;
-
- cachep->flags = flags;
- spin_lock_init(&cachep->spinlock);
- cachep->objsize = size;
- INIT_LIST_HEAD(&cachep->slabs_full);
- INIT_LIST_HEAD(&cachep->slabs_partial);
- INIT_LIST_HEAD(&cachep->slabs_free);
-
- if (flags & CFLGS_OFF_SLAB)
- cachep->slabp_cache = xmem_find_general_cachep(slab_size);
- cachep->ctor = ctor;
- cachep->dtor = dtor;
- /* Copy name over so we don't have problems with unloaded modules */
- strcpy(cachep->name, name);
-
-#ifdef CONFIG_SMP
- if (g_cpucache_up)
- enable_cpucache(cachep);
-#endif
- /* Need the semaphore to access the chain. */
- down(&cache_chain_sem);
- {
- xmem_cache_t *pc;
-
- list_for_each_entry(pc, &cache_chain, next) {
- /* The name field is constant - no lock needed. */
- if (!strcmp(pc->name, name))
- BUG();
- }
- }
-
- /* There is no reason to lock our new cache before we
- * link it in - no one knows about it yet...
- */
- list_add(&cachep->next, &cache_chain);
- up(&cache_chain_sem);
- opps:
- return cachep;
-}
-
-
-#if DEBUG
-/*
- * This check if the xmem_cache_t pointer is chained in the cache_cache
- * list. -arca
- */
-static int is_chained_xmem_cache(xmem_cache_t * cachep)
-{
- xmem_cache_t *pc;
- int ret = 0;
- unsigned long spin_flags;
-
- /* Find the cache in the chain of caches. */
- down(&cache_chain_sem);
- list_for_each_entry(pc, &cache_chain, next) {
- if (pc == &cachep) {
- ret = 1;
- break;
- }
- }
- up(&cache_chain_sem);
-
- return ret;
-}
-#else
-#define is_chained_xmem_cache(x) 1
-#endif
-
-#ifdef CONFIG_SMP
-/*
- * Waits for all CPUs to execute func().
- */
-static void smp_call_function_all_cpus(void (*func) (void *arg), void *arg)
-{
- local_irq_disable();
- func(arg);
- local_irq_enable();
-
- if (smp_call_function(func, arg, 1, 1))
- BUG();
-}
-typedef struct ccupdate_struct_s
-{
- xmem_cache_t *cachep;
- cpucache_t *new[NR_CPUS];
-} ccupdate_struct_t;
-
-static void do_ccupdate_local(void *info)
-{
- ccupdate_struct_t *new = (ccupdate_struct_t *)info;
- cpucache_t *old = cc_data(new->cachep);
-
- cc_data(new->cachep) = new->new[smp_processor_id()];
- new->new[smp_processor_id()] = old;
-}
-
-static void free_block (xmem_cache_t* cachep, void** objpp, int len);
-
-static void drain_cpu_caches(xmem_cache_t *cachep)
-{
- ccupdate_struct_t new;
- int i;
- unsigned long spin_flags;
-
- memset(&new.new,0,sizeof(new.new));
-
- new.cachep = cachep;
-
- down(&cache_chain_sem);
- smp_call_function_all_cpus(do_ccupdate_local, (void *)&new);
-
- for (i = 0; i < smp_num_cpus; i++) {
- cpucache_t* ccold = new.new[cpu_logical_map(i)];
- if (!ccold || (ccold->avail == 0))
- continue;
- local_irq_disable();
- free_block(cachep, cc_entry(ccold), ccold->avail);
- local_irq_enable();
- ccold->avail = 0;
- }
- smp_call_function_all_cpus(do_ccupdate_local, (void *)&new);
- up(&cache_chain_sem);
-}
-
-#else
-#define drain_cpu_caches(cachep) do { } while (0)
-#endif
-
-static int __xmem_cache_shrink(xmem_cache_t *cachep)
-{
- slab_t *slabp;
- int ret;
-
- drain_cpu_caches(cachep);
-
- spin_lock_irq(&cachep->spinlock);
-
- /* If the cache is growing, stop shrinking. */
- while (!cachep->growing) {
- struct list_head *p;
-
- p = cachep->slabs_free.prev;
- if (p == &cachep->slabs_free)
- break;
-
- slabp = list_entry(cachep->slabs_free.prev, slab_t, list);
-#if DEBUG
- if (slabp->inuse)
- BUG();
-#endif
- list_del(&slabp->list);
-
- spin_unlock_irq(&cachep->spinlock);
- xmem_slab_destroy(cachep, slabp);
- spin_lock_irq(&cachep->spinlock);
- }
- ret = (!list_empty(&cachep->slabs_full) ||
- !list_empty(&cachep->slabs_partial));
- spin_unlock_irq(&cachep->spinlock);
- return ret;
-}
-
-/**
- * xmem_cache_shrink - Shrink a cache.
- * @cachep: The cache to shrink.
- *
- * Releases as many slabs as possible for a cache.
- * To help debugging, a zero exit status indicates all slabs were released.
- */
-int xmem_cache_shrink(xmem_cache_t *cachep)
-{
- if (!cachep || !is_chained_xmem_cache(cachep))
- BUG();
-
- return __xmem_cache_shrink(cachep);
-}
-
-/**
- * xmem_cache_destroy - delete a cache
- * @cachep: the cache to destroy
- *
- * Remove a xmem_cache_t object from the slab cache.
- * Returns 0 on success.
- *
- * It is expected this function will be called by a module when it is
- * unloaded. This will remove the cache completely, and avoid a duplicate
- * cache being allocated each time a module is loaded and unloaded, if the
- * module doesn't have persistent in-kernel storage across loads and unloads.
- *
- * The caller must guarantee that noone will allocate memory from the cache
- * during the xmem_cache_destroy().
- */
-int xmem_cache_destroy (xmem_cache_t * cachep)
-{
- unsigned long spin_flags;
-
- if (!cachep || cachep->growing)
- BUG();
-
- /* Find the cache in the chain of caches. */
- down(&cache_chain_sem);
- /* the chain is never empty, cache_cache is never destroyed */
- if (clock_searchp == cachep)
- clock_searchp = list_entry(cachep->next.next,
- xmem_cache_t, next);
- list_del(&cachep->next);
- up(&cache_chain_sem);
-
- if (__xmem_cache_shrink(cachep)) {
- printk(KERN_ERR "xmem_cache_destroy: Can't free all objects %p\n",
- cachep);
- down(&cache_chain_sem);
- list_add(&cachep->next,&cache_chain);
- up(&cache_chain_sem);
- return 1;
- }
-#ifdef CONFIG_SMP
- {
- int i;
- for (i = 0; i < NR_CPUS; i++)
- xfree(cachep->cpudata[i]);
- }
-#endif
- xmem_cache_free(&cache_cache, cachep);
-
- return 0;
-}
-
-/* Get the memory for a slab management obj. */
-static inline slab_t *xmem_cache_slabmgmt(xmem_cache_t *cachep,
- void *objp, int colour_off,
- int local_flags)
-{
- slab_t *slabp;
-
- if (OFF_SLAB(cachep)) {
- /* Slab management obj is off-slab. */
- slabp = xmem_cache_alloc(cachep->slabp_cache);
- if (!slabp)
- return NULL;
- } else {
- /* FIXME: change to
- slabp = objp
- * if you enable OPTIMIZE
- */
- slabp = objp+colour_off;
- colour_off += L1_CACHE_ALIGN(cachep->num *
- sizeof(xmem_bufctl_t) + sizeof(slab_t));
- }
- slabp->inuse = 0;
- slabp->colouroff = colour_off;
- slabp->s_mem = objp+colour_off;
-
- return slabp;
-}
-
-static inline void xmem_cache_init_objs(xmem_cache_t *cachep,
- slab_t *slabp,
- unsigned long ctor_flags)
-{
- int i;
-
- for (i = 0; i < cachep->num; i++) {
- void* objp = slabp->s_mem+cachep->objsize*i;
-#if DEBUG
- if (cachep->flags & SLAB_RED_ZONE) {
- *((unsigned long*)(objp)) = RED_MAGIC1;
- *((unsigned long*)(objp + cachep->objsize -
- BYTES_PER_WORD)) = RED_MAGIC1;
- objp += BYTES_PER_WORD;
- }
-#endif
-
- /*
- * Constructors are not allowed to allocate memory from
- * the same cache which they are a constructor for.
- * Otherwise, deadlock. They must also be threaded.
- */
- if (cachep->ctor)
- cachep->ctor(objp, cachep, ctor_flags);
-#if DEBUG
- if (cachep->flags & SLAB_RED_ZONE)
- objp -= BYTES_PER_WORD;
- if (cachep->flags & SLAB_POISON)
- /* need to poison the objs */
- xmem_poison_obj(cachep, objp);
- if (cachep->flags & SLAB_RED_ZONE) {
- if (*((unsigned long*)(objp)) != RED_MAGIC1)
- BUG();
- if (*((unsigned long*)(objp + cachep->objsize -
- BYTES_PER_WORD)) != RED_MAGIC1)
- BUG();
- }
-#endif
- slab_bufctl(slabp)[i] = i+1;
- }
- slab_bufctl(slabp)[i-1] = BUFCTL_END;
- slabp->free = 0;
-}
-
-/*
- * Grow (by 1) the number of slabs within a cache. This is called by
- * xmem_cache_alloc() when there are no active objs left in a cache.
- */
-static int xmem_cache_grow(xmem_cache_t * cachep)
-{
- slab_t *slabp;
- struct pfn_info *page; unsigned int i;
- void *objp;
- size_t offset;
- unsigned long ctor_flags;
- unsigned long save_flags;
-
- ctor_flags = SLAB_CTOR_CONSTRUCTOR;
-
- /* About to mess with non-constant members - lock. */
- spin_lock_irqsave(&cachep->spinlock, save_flags);
-
- /* Get colour for the slab, and cal the next value. */
- offset = cachep->colour_next;
- cachep->colour_next++;
- if (cachep->colour_next >= cachep->colour)
- cachep->colour_next = 0;
- offset *= cachep->colour_off;
- cachep->dflags |= DFLGS_GROWN;
-
- cachep->growing++;
- spin_unlock_irqrestore(&cachep->spinlock, save_flags);
-
- /* A series of memory allocations for a new slab.
- * Neither the cache-chain semaphore, or cache-lock, are
- * held, but the incrementing c_growing prevents this
- * cache from being reaped or shrunk.
- * Note: The cache could be selected in for reaping in
- * xmem_cache_reap(), but when the final test is made the
- * growing value will be seen.
- */
-
- /* Get mem for the objs. */
- if (!(objp = xmem_getpages(cachep)))
- goto failed;
-
- /* Get slab management. */
- if (!(slabp = xmem_cache_slabmgmt(cachep, objp, offset, 0)))
- goto opps1;
-
- /* Nasty!!!!!! I hope this is OK. */
- i = 1 << cachep->gfporder;
- page = virt_to_page(objp);
- do {
- SET_PAGE_CACHE(page, cachep);
- SET_PAGE_SLAB(page, slabp);
- PageSetSlab(page);
- page++;
- } while (--i);
-
- xmem_cache_init_objs(cachep, slabp, ctor_flags);
-
- spin_lock_irqsave(&cachep->spinlock, save_flags);
- cachep->growing--;
-
- /* Make slab active. */
- list_add_tail(&slabp->list, &cachep->slabs_free);
- STATS_INC_GROWN(cachep);
- cachep->failures = 0;
-
- spin_unlock_irqrestore(&cachep->spinlock, save_flags);
- return 1;
- opps1:
- xmem_freepages(cachep, objp);
- failed:
- spin_lock_irqsave(&cachep->spinlock, save_flags);
- cachep->growing--;
- spin_unlock_irqrestore(&cachep->spinlock, save_flags);
- return 0;
-}
-
-/*
- * Perform extra freeing checks:
- * - detect double free
- * - detect bad pointers.
- * Called with the cache-lock held.
- */
-
-#if DEBUG
-static int xmem_extra_free_checks (xmem_cache_t * cachep,
- slab_t *slabp, void * objp)
-{
- int i;
- unsigned int objnr = (objp-slabp->s_mem)/cachep->objsize;
-
- if (objnr >= cachep->num)
- BUG();
- if (objp != slabp->s_mem + objnr*cachep->objsize)
- BUG();
-
- /* Check slab's freelist to see if this obj is there. */
- for (i = slabp->free; i != BUFCTL_END; i = slab_bufctl(slabp)[i]) {
- if (i == objnr)
- BUG();
- }
- return 0;
-}
-#endif
-
-static inline void * xmem_cache_alloc_one_tail (xmem_cache_t *cachep,
- slab_t *slabp)
-{
- void *objp;
-
- STATS_INC_ALLOCED(cachep);
- STATS_INC_ACTIVE(cachep);
- STATS_SET_HIGH(cachep);
-
- /* get obj pointer */
- slabp->inuse++;
- objp = slabp->s_mem + slabp->free*cachep->objsize;
- slabp->free=slab_bufctl(slabp)[slabp->free];
-
- if (unlikely(slabp->free == BUFCTL_END)) {
- list_del(&slabp->list);
- list_add(&slabp->list, &cachep->slabs_full);
- }
-#if DEBUG
- if (cachep->flags & SLAB_POISON)
- if (xmem_check_poison_obj(cachep, objp))
- BUG();
- if (cachep->flags & SLAB_RED_ZONE) {
- /* Set alloc red-zone, and check old one. */
- if (xchg((unsigned long *)objp, RED_MAGIC2) !=
- RED_MAGIC1)
- BUG();
- if (xchg((unsigned long *)(objp+cachep->objsize -
- BYTES_PER_WORD), RED_MAGIC2) != RED_MAGIC1)
- BUG();
- objp += BYTES_PER_WORD;
- }
-#endif
- return objp;
-}
-
-/*
- * Returns a ptr to an obj in the given cache.
- * caller must guarantee synchronization
- * #define for the goto optimization 8-)
- */
-#define xmem_cache_alloc_one(cachep) \
-({ \
- struct list_head * slabs_partial, * entry; \
- slab_t *slabp; \
- \
- slabs_partial = &(cachep)->slabs_partial; \
- entry = slabs_partial->next; \
- if (unlikely(entry == slabs_partial)) { \
- struct list_head * slabs_free; \
- slabs_free = &(cachep)->slabs_free; \
- entry = slabs_free->next; \
- if (unlikely(entry == slabs_free)) \
- goto alloc_new_slab; \
- list_del(entry); \
- list_add(entry, slabs_partial); \
- } \
- \
- slabp = list_entry(entry, slab_t, list); \
- xmem_cache_alloc_one_tail(cachep, slabp); \
-})
-
-#ifdef CONFIG_SMP
-void* xmem_cache_alloc_batch(xmem_cache_t* cachep)
-{
- int batchcount = cachep->batchcount;
- cpucache_t* cc = cc_data(cachep);
-
- spin_lock(&cachep->spinlock);
- while (batchcount--) {
- struct list_head * slabs_partial, * entry;
- slab_t *slabp;
- /* Get slab alloc is to come from. */
- slabs_partial = &(cachep)->slabs_partial;
- entry = slabs_partial->next;
- if (unlikely(entry == slabs_partial)) {
- struct list_head * slabs_free;
- slabs_free = &(cachep)->slabs_free;
- entry = slabs_free->next;
- if (unlikely(entry == slabs_free))
- break;
- list_del(entry);
- list_add(entry, slabs_partial);
- }
-
- slabp = list_entry(entry, slab_t, list);
- cc_entry(cc)[cc->avail++] =
- xmem_cache_alloc_one_tail(cachep, slabp);
- }
- spin_unlock(&cachep->spinlock);
-
- if (cc->avail)
- return cc_entry(cc)[--cc->avail];
- return NULL;
-}
-#endif
-
-static inline void *__xmem_cache_alloc(xmem_cache_t *cachep)
-{
- unsigned long flags;
- void* objp;
-
- try_again:
- local_irq_save(flags);
-#ifdef CONFIG_SMP
- {
- cpucache_t *cc = cc_data(cachep);
-
- if (cc) {
- if (cc->avail) {
- STATS_INC_ALLOCHIT(cachep);
- objp = cc_entry(cc)[--cc->avail];
- } else {
- STATS_INC_ALLOCMISS(cachep);
- objp = xmem_cache_alloc_batch(cachep);
- if (!objp)
- goto alloc_new_slab_nolock;
- }
- } else {
- spin_lock(&cachep->spinlock);
- objp = xmem_cache_alloc_one(cachep);
- spin_unlock(&cachep->spinlock);
- }
- }
-#else
- objp = xmem_cache_alloc_one(cachep);
-#endif
- local_irq_restore(flags);
- return objp;
- alloc_new_slab:
-#ifdef CONFIG_SMP
- spin_unlock(&cachep->spinlock);
- alloc_new_slab_nolock:
-#endif
- local_irq_restore(flags);
- if (xmem_cache_grow(cachep))
- /* Someone may have stolen our objs. Doesn't matter, we'll
- * just come back here again.
- */
- goto try_again;
- return NULL;
-}
-
-/*
- * Release an obj back to its cache. If the obj has a constructed
- * state, it should be in this state _before_ it is released.
- * - caller is responsible for the synchronization
- */
-
-#if DEBUG
-# define CHECK_NR(pg) \
- do { \
- if (!VALID_PAGE(pg)) { \
- printk(KERN_ERR "xfree: out of range ptr %lxh.\n", \
- (unsigned long)objp); \
- BUG(); \
- } \
- } while (0)
-# define CHECK_PAGE(page) \
- do { \
- CHECK_NR(page); \
- if (!PageSlab(page)) { \
- printk(KERN_ERR "xfree: bad ptr %lxh.\n", \
- (unsigned long)objp); \
- BUG(); \
- } \
- } while (0)
-
-#else
-# define CHECK_PAGE(pg) do { } while (0)
-#endif
-
-static inline void xmem_cache_free_one(xmem_cache_t *cachep, void *objp)
-{
- slab_t* slabp;
-
- CHECK_PAGE(virt_to_page(objp));
- /* reduces memory footprint
- *
- if (OPTIMIZE(cachep))
- slabp = (void*)((unsigned long)objp&(~(PAGE_SIZE-1)));
- else
- */
- slabp = GET_PAGE_SLAB(virt_to_page(objp));
-
-#if DEBUG
- if (cachep->flags & SLAB_DEBUG_INITIAL)
- /* Need to call the slab's constructor so the
- * caller can perform a verify of its state (debugging).
- * Called without the cache-lock held.
- */
- cachep->ctor(objp, cachep, SLAB_CTOR_CONSTRUCTOR|SLAB_CTOR_VERIFY);
-
- if (cachep->flags & SLAB_RED_ZONE) {
- objp -= BYTES_PER_WORD;
- if (xchg((unsigned long *)objp, RED_MAGIC1) != RED_MAGIC2)
- /* Either write before start, or a double free. */
- BUG();
- if (xchg((unsigned long *)(objp+cachep->objsize -
- BYTES_PER_WORD), RED_MAGIC1) != RED_MAGIC2)
- /* Either write past end, or a double free. */
- BUG();
- }
- if (cachep->flags & SLAB_POISON)
- xmem_poison_obj(cachep, objp);
- if (xmem_extra_free_checks(cachep, slabp, objp))
- return;
-#endif
- {
- unsigned int objnr = (objp-slabp->s_mem)/cachep->objsize;
-
- slab_bufctl(slabp)[objnr] = slabp->free;
- slabp->free = objnr;
- }
- STATS_DEC_ACTIVE(cachep);
-
- /* fixup slab chains */
- {
- int inuse = slabp->inuse;
- if (unlikely(!--slabp->inuse)) {
- /* Was partial or full, now empty. */
- list_del(&slabp->list);
- list_add(&slabp->list, &cachep->slabs_free);
- } else if (unlikely(inuse == cachep->num)) {
- /* Was full. */
- list_del(&slabp->list);
- list_add(&slabp->list, &cachep->slabs_partial);
- }
- }
-}
-
-#ifdef CONFIG_SMP
-static inline void __free_block (xmem_cache_t* cachep,
- void** objpp, int len)
-{
- for ( ; len > 0; len--, objpp++)
- xmem_cache_free_one(cachep, *objpp);
-}
-
-static void free_block (xmem_cache_t* cachep, void** objpp, int len)
-{
- spin_lock(&cachep->spinlock);
- __free_block(cachep, objpp, len);
- spin_unlock(&cachep->spinlock);
-}
-#endif
-
-/*
- * __xmem_cache_free
- * called with disabled ints
- */
-static inline void __xmem_cache_free (xmem_cache_t *cachep, void* objp)
-{
-#ifdef CONFIG_SMP
- cpucache_t *cc = cc_data(cachep);
-
- CHECK_PAGE(virt_to_page(objp));
- if (cc) {
- int batchcount;
- if (cc->avail < cc->limit) {
- STATS_INC_FREEHIT(cachep);
- cc_entry(cc)[cc->avail++] = objp;
- return;
- }
- STATS_INC_FREEMISS(cachep);
- batchcount = cachep->batchcount;
- cc->avail -= batchcount;
- free_block(cachep,
- &cc_entry(cc)[cc->avail],batchcount);
- cc_entry(cc)[cc->avail++] = objp;
- return;
- } else {
- free_block(cachep, &objp, 1);
- }
-#else
- xmem_cache_free_one(cachep, objp);
-#endif
-}
-
-/**
- * xmem_cache_alloc - Allocate an object
- * @cachep: The cache to allocate from.
- *
- * Allocate an object from this cache. The flags are only relevant
- * if the cache has no available objects.
- */
-void *xmem_cache_alloc(xmem_cache_t *cachep)
-{
- return __xmem_cache_alloc(cachep);
-}
-
-/**
- * xmalloc - allocate memory
- * @size: how many bytes of memory are required.
- */
-void *xmalloc(size_t size)
-{
- cache_sizes_t *csizep = cache_sizes;
-
- for (; csizep->cs_size; csizep++) {
- if (size > csizep->cs_size)
- continue;
- return __xmem_cache_alloc(csizep->cs_cachep);
- }
- return NULL;
-}
-
-/**
- * xmem_cache_free - Deallocate an object
- * @cachep: The cache the allocation was from.
- * @objp: The previously allocated object.
- *
- * Free an object which was previously allocated from this
- * cache.
- */
-void xmem_cache_free (xmem_cache_t *cachep, void *objp)
-{
- unsigned long flags;
-#if DEBUG
- CHECK_PAGE(virt_to_page(objp));
- if (cachep != GET_PAGE_CACHE(virt_to_page(objp)))
- BUG();
-#endif
-
- local_irq_save(flags);
- __xmem_cache_free(cachep, objp);
- local_irq_restore(flags);
-}
-
-/**
- * xfree - free previously allocated memory
- * @objp: pointer returned by xmalloc.
- *
- * Don't free memory not originally allocated by xmalloc()
- * or you will run into trouble.
- */
-void xfree (const void *objp)
-{
- xmem_cache_t *c;
- unsigned long flags;
-
- if (!objp)
- return;
- local_irq_save(flags);
- CHECK_PAGE(virt_to_page(objp));
- c = GET_PAGE_CACHE(virt_to_page(objp));
- __xmem_cache_free(c, (void*)objp);
- local_irq_restore(flags);
-}
-
-xmem_cache_t *xmem_find_general_cachep(size_t size)
-{
- cache_sizes_t *csizep = cache_sizes;
-
- /* This function could be moved to the header file, and
- * made inline so consumers can quickly determine what
- * cache pointer they require.
- */
- for ( ; csizep->cs_size; csizep++) {
- if (size > csizep->cs_size)
- continue;
- break;
- }
- return csizep->cs_cachep;
-}
-
-#ifdef CONFIG_SMP
-
-/* called with cache_chain_sem acquired. */
-static int xmem_tune_cpucache (xmem_cache_t* cachep, int limit, int batchcount)
-{
- ccupdate_struct_t new;
- int i;
-
- /*
- * These are admin-provided, so we are more graceful.
- */
- if (limit < 0)
- return -EINVAL;
- if (batchcount < 0)
- return -EINVAL;
- if (batchcount > limit)
- return -EINVAL;
- if (limit != 0 && !batchcount)
- return -EINVAL;
-
- memset(&new.new,0,sizeof(new.new));
- if (limit) {
- for (i = 0; i< smp_num_cpus; i++) {
- cpucache_t* ccnew;
-
- ccnew = xmalloc(sizeof(void*)*limit+sizeof(cpucache_t));
- if (!ccnew)
- goto oom;
- ccnew->limit = limit;
- ccnew->avail = 0;
- new.new[cpu_logical_map(i)] = ccnew;
- }
- }
- new.cachep = cachep;
- spin_lock_irq(&cachep->spinlock);
- cachep->batchcount = batchcount;
- spin_unlock_irq(&cachep->spinlock);
-
- smp_call_function_all_cpus(do_ccupdate_local, (void *)&new);
-
- for (i = 0; i < smp_num_cpus; i++) {
- cpucache_t* ccold = new.new[cpu_logical_map(i)];
- if (!ccold)
- continue;
- local_irq_disable();
- free_block(cachep, cc_entry(ccold), ccold->avail);
- local_irq_enable();
- xfree(ccold);
- }
- return 0;
- oom:
- for (i--; i >= 0; i--)
- xfree(new.new[cpu_logical_map(i)]);
- return -ENOMEM;
-}
-
-static void enable_cpucache (xmem_cache_t *cachep)
-{
- int err;
- int limit;
-
- /* FIXME: optimize */
- if (cachep->objsize > PAGE_SIZE)
- return;
- if (cachep->objsize > 1024)
- limit = 60;
- else if (cachep->objsize > 256)
- limit = 124;
- else
- limit = 252;
-
- err = xmem_tune_cpucache(cachep, limit, limit/2);
- if (err)
- printk(KERN_ERR "enable_cpucache failed for %s, error %d.\n",
- cachep->name, -err);
-}
-
-static void enable_all_cpucaches (void)
-{
- struct list_head* p;
- unsigned long spin_flags;
-
- down(&cache_chain_sem);
-
- p = &cache_cache.next;
- do {
- xmem_cache_t* cachep = list_entry(p, xmem_cache_t, next);
-
- enable_cpucache(cachep);
- p = cachep->next.next;
- } while (p != &cache_cache.next);
-
- up(&cache_chain_sem);
-}
-#endif
-
-/**
- * xmem_cache_reap - Reclaim memory from caches.
- */
-int xmem_cache_reap(void)
-{
- slab_t *slabp;
- xmem_cache_t *searchp;
- xmem_cache_t *best_cachep;
- unsigned int best_pages;
- unsigned int best_len;
- unsigned int scan;
- int ret = 0;
- unsigned long spin_flags;
-
- down(&cache_chain_sem);
-
- scan = REAP_SCANLEN;
- best_len = 0;
- best_pages = 0;
- best_cachep = NULL;
- searchp = clock_searchp;
- do {
- unsigned int pages;
- struct list_head* p;
- unsigned int full_free;
-
- /* It's safe to test this without holding the cache-lock. */
- if (searchp->flags & SLAB_NO_REAP)
- goto next;
- spin_lock_irq(&searchp->spinlock);
- if (searchp->growing)
- goto next_unlock;
- if (searchp->dflags & DFLGS_GROWN) {
- searchp->dflags &= ~DFLGS_GROWN;
- goto next_unlock;
- }
-#ifdef CONFIG_SMP
- {
- cpucache_t *cc = cc_data(searchp);
- if (cc && cc->avail) {
- __free_block(searchp, cc_entry(cc), cc->avail);
- cc->avail = 0;
- }
- }
-#endif
-
- full_free = 0;
- p = searchp->slabs_free.next;
- while (p != &searchp->slabs_free) {
- slabp = list_entry(p, slab_t, list);
-#if DEBUG
- if (slabp->inuse)
- BUG();
-#endif
- full_free++;
- p = p->next;
- }
-
- /*
- * Try to avoid slabs with constructors and/or
- * more than one page per slab (as it can be difficult
- * to get high orders from gfp()).
- */
- pages = full_free * (1<<searchp->gfporder);
- if (searchp->ctor)
- pages = (pages*4+1)/5;
- if (searchp->gfporder)
- pages = (pages*4+1)/5;
- if (pages > best_pages) {
- best_cachep = searchp;
- best_len = full_free;
- best_pages = pages;
- if (pages >= REAP_PERFECT) {
- clock_searchp = list_entry(searchp->next.next,
- xmem_cache_t,next);
- goto perfect;
- }
- }
- next_unlock:
- spin_unlock_irq(&searchp->spinlock);
- next:
- searchp = list_entry(searchp->next.next,xmem_cache_t,next);
- } while (--scan && searchp != clock_searchp);
-
- clock_searchp = searchp;
-
- if (!best_cachep)
- /* couldn't find anything to reap */
- goto out;
-
- spin_lock_irq(&best_cachep->spinlock);
- perfect:
- /* free only 50% of the free slabs */
- best_len = (best_len + 1)/2;
- for (scan = 0; scan < best_len; scan++) {
- struct list_head *p;
-
- if (best_cachep->growing)
- break;
- p = best_cachep->slabs_free.prev;
- if (p == &best_cachep->slabs_free)
- break;
- slabp = list_entry(p,slab_t,list);
-#if DEBUG
- if (slabp->inuse)
- BUG();
-#endif
- list_del(&slabp->list);
- STATS_INC_REAPED(best_cachep);
-
- /* Safe to drop the lock. The slab is no longer linked to the
- * cache.
- */
- spin_unlock_irq(&best_cachep->spinlock);
- xmem_slab_destroy(best_cachep, slabp);
- spin_lock_irq(&best_cachep->spinlock);
- }
- spin_unlock_irq(&best_cachep->spinlock);
- ret = scan * (1 << best_cachep->gfporder);
- out:
- up(&cache_chain_sem);
- return ret;
-}
-
-void dump_slabinfo()
-{
- struct list_head *p;
- unsigned long spin_flags;
-
- /* Output format version, so at least we can change it without _too_
- * many complaints.
- */
- printk( "slabinfo - version: 1.1"
-#if STATS
- " (statistics)"
-#endif
-#ifdef CONFIG_SMP
- " (SMP)"
-#endif
- "\n");
- down(&cache_chain_sem);
- p = &cache_cache.next;
- do {
- xmem_cache_t *cachep;
- slab_t *slabp;
- unsigned long active_objs;
- unsigned long num_objs;
- unsigned long active_slabs = 0;
- unsigned long num_slabs;
- cachep = list_entry(p, xmem_cache_t, next);
-
- spin_lock_irq(&cachep->spinlock);
- active_objs = 0;
- num_slabs = 0;
- list_for_each_entry(slabp, &cachep->slabs_full, list) {
- if (slabp->inuse != cachep->num)
- BUG();
- active_objs += cachep->num;
- active_slabs++;
- }
- list_for_each_entry(slabp, &cachep->slabs_partial, list) {
- if (slabp->inuse == cachep->num || !slabp->inuse)
- BUG();
- active_objs += slabp->inuse;
- active_slabs++;
- }
- list_for_each_entry(slabp, &cachep->slabs_free, list) {
- if (slabp->inuse)
- BUG();
- num_slabs++;
- }
- num_slabs+=active_slabs;
- num_objs = num_slabs*cachep->num;
-
- printk("%-17s %6lu %6lu %6u %4lu %4lu %4u",
- cachep->name, active_objs, num_objs, cachep->objsize,
- active_slabs, num_slabs, (1<<cachep->gfporder));
-
-#if STATS
- {
- unsigned long errors = cachep->errors;
- unsigned long high = cachep->high_mark;
- unsigned long grown = cachep->grown;
- unsigned long reaped = cachep->reaped;
- unsigned long allocs = cachep->num_allocations;
-
- printk(" : %6lu %7lu %5lu %4lu %4lu",
- high, allocs, grown, reaped, errors);
- }
-#endif
-#ifdef CONFIG_SMP
- {
- unsigned int batchcount = cachep->batchcount;
- unsigned int limit;
-
- if (cc_data(cachep))
- limit = cc_data(cachep)->limit;
- else
- limit = 0;
- printk(" : %4u %4u",
- limit, batchcount);
- }
-#endif
-#if STATS && defined(CONFIG_SMP)
- {
- unsigned long allochit = atomic_read(&cachep->allochit);
- unsigned long allocmiss = atomic_read(&cachep->allocmiss);
- unsigned long freehit = atomic_read(&cachep->freehit);
- unsigned long freemiss = atomic_read(&cachep->freemiss);
- printk(" : %6lu %6lu %6lu %6lu",
- allochit, allocmiss, freehit, freemiss);
- }
-#endif
- printk("\n");
- spin_unlock_irq(&cachep->spinlock);
-
- p = cachep->next.next;
- } while (p != &cache_cache.next);
-
- up(&cache_chain_sem);
-
- return;
-}
diff --git a/xen/common/softirq.c b/xen/common/softirq.c
index 17e850b3f6..dc635d1ab5 100644
--- a/xen/common/softirq.c
+++ b/xen/common/softirq.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* common/softirq.c
*
diff --git a/xen/common/string.c b/xen/common/string.c
index 1f51b65ecb..c78652509a 100644
--- a/xen/common/string.c
+++ b/xen/common/string.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
* linux/lib/string.c
*
diff --git a/xen/common/trace.c b/xen/common/trace.c
index 83bf5ce55e..0fcb8dbfd6 100644
--- a/xen/common/trace.c
+++ b/xen/common/trace.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* common/trace.c
*
diff --git a/xen/common/vsprintf.c b/xen/common/vsprintf.c
index 906e7734db..d710d0bd72 100644
--- a/xen/common/vsprintf.c
+++ b/xen/common/vsprintf.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/*
* linux/lib/vsprintf.c
*
@@ -115,13 +116,13 @@ static int skip_atoi(const char **s)
return i;
}
-#define ZEROPAD 1 /* pad with zero */
-#define SIGN 2 /* unsigned/signed long */
-#define PLUS 4 /* show plus */
-#define SPACE 8 /* space if plus */
-#define LEFT 16 /* left justified */
-#define SPECIAL 32 /* 0x */
-#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
+#define ZEROPAD 1 /* pad with zero */
+#define SIGN 2 /* unsigned/signed long */
+#define PLUS 4 /* show plus */
+#define SPACE 8 /* space if plus */
+#define LEFT 16 /* left justified */
+#define SPECIAL 32 /* 0x */
+#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
static char * number(char * buf, char * end, long long num, int base, int size, int precision, int type)
{
@@ -239,14 +240,14 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
char *str, *end, c;
const char *s;
- int flags; /* flags to number() */
+ int flags; /* flags to number() */
- int field_width; /* width of output field */
- int precision; /* min. # of digits for integers; max
- number of chars for from string */
- int qualifier; /* 'h', 'l', or 'L' for integer fields */
- /* 'z' support added 23/7/1999 S.H. */
- /* 'z' changed to 'Z' --davidm 1/25/99 */
+ int field_width; /* width of output field */
+ int precision; /* min. # of digits for integers; max
+ number of chars for from string */
+ int qualifier; /* 'h', 'l', or 'L' for integer fields */
+ /* 'z' support added 23/7/1999 S.H. */
+ /* 'z' changed to 'Z' --davidm 1/25/99 */
str = buf;
end = buf + size - 1;
@@ -267,7 +268,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
/* process flags */
flags = 0;
repeat:
- ++fmt; /* this also skips first '%' */
+ ++fmt; /* this also skips first '%' */
switch (*fmt) {
case '-': flags |= LEFT; goto repeat;
case '+': flags |= PLUS; goto repeat;
@@ -293,12 +294,12 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
/* get the precision */
precision = -1;
if (*fmt == '.') {
- ++fmt;
+ ++fmt;
if (isdigit(*fmt))
precision = skip_atoi(&fmt);
else if (*fmt == '*') {
++fmt;
- /* it's the next argument */
+ /* it's the next argument */
precision = va_arg(args, int);
}
if (precision < 0)
@@ -381,8 +382,8 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
case 'n':
- /* FIXME:
- * What does C99 say about the overflow case here? */
+ /* FIXME:
+ * What does C99 say about the overflow case here? */
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
*ip = (str - buf);
@@ -401,7 +402,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
++str;
continue;
- /* integer number formats - set up the flags and "break" */
+ /* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
break;
diff --git a/xen/common/xmalloc.c b/xen/common/xmalloc.c
new file mode 100644
index 0000000000..8addc7e4d0
--- /dev/null
+++ b/xen/common/xmalloc.c
@@ -0,0 +1,173 @@
+/* -*- Mode:C; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
+/******************************************************************************
+ * Simple allocator for Xen. If larger than a page, simply use the
+ * page-order allocator.
+ *
+ * Copyright (C) 2005 Rusty Russell IBM Corporation
+ *
+ * This program 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 program 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 program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <xen/mm.h>
+#include <xen/spinlock.h>
+#include <xen/ac_timer.h>
+#include <xen/cache.h>
+
+#define BUG_ON(x) do { if (x) BUG(); }while(0)
+
+static LIST_HEAD(freelist);
+static spinlock_t freelist_lock = SPIN_LOCK_UNLOCKED;
+
+struct xmalloc_hdr
+{
+ /* Total including this hdr. */
+ size_t size;
+ struct list_head freelist;
+} __attribute__((__aligned__(SMP_CACHE_BYTES)));
+
+static void maybe_split(struct xmalloc_hdr *hdr, size_t size, size_t block)
+{
+ size_t leftover = block - size;
+
+ /* If enough left to make a block, put it on free list. */
+ if (leftover >= sizeof(struct xmalloc_hdr)) {
+ struct xmalloc_hdr *extra;
+
+ extra = (void *)hdr + size;
+ extra->size = leftover;
+ list_add(&extra->freelist, &freelist);
+ } else
+ size = block;
+
+ hdr->size = size;
+ /* Debugging aid. */
+ hdr->freelist.next = hdr->freelist.prev = NULL;
+}
+
+static void *xmalloc_new_page(size_t size)
+{
+ struct xmalloc_hdr *hdr;
+ unsigned long flags;
+
+ hdr = (void *)alloc_xenheap_pages(0);
+ if (!hdr)
+ return NULL;
+
+ spin_lock_irqsave(&freelist_lock, flags);
+ maybe_split(hdr, size, PAGE_SIZE);
+ spin_unlock_irqrestore(&freelist_lock, flags);
+ return hdr+1;
+}
+
+/* Big object? Just use page allocator. */
+static void *xmalloc_whole_pages(size_t size)
+{
+ struct xmalloc_hdr *hdr;
+ unsigned int pageorder = get_order(size);
+
+ hdr = (void *)alloc_xenheap_pages(pageorder);
+ if (!hdr)
+ return NULL;
+
+ hdr->size = (1 << (pageorder + PAGE_SHIFT));
+ /* Debugging aid. */
+ hdr->freelist.next = hdr->freelist.prev = NULL;
+ return hdr+1;
+}
+
+/* Return size, increased to alignment with align. */
+static inline size_t align_up(size_t size, size_t align)
+{
+ return (size + align-1) & ~(align - 1);
+}
+
+void *_xmalloc(size_t size, size_t align)
+{
+ struct xmalloc_hdr *i;
+ unsigned long flags;
+
+ /* We currently always return cacheline aligned. */
+ BUG_ON(align > SMP_CACHE_BYTES);
+
+ /* Add room for header, pad to align next header. */
+ size += sizeof(struct xmalloc_hdr);
+ size = align_up(size, __alignof__(struct xmalloc_hdr));
+
+ /* For big allocs, give them whole pages. */
+ if (size >= PAGE_SIZE)
+ return xmalloc_whole_pages(size);
+
+ /* Search free list */
+ spin_lock_irqsave(&freelist_lock, flags);
+ list_for_each_entry(i, &freelist, freelist) {
+ if (i->size >= size) {
+ list_del(&i->freelist);
+ maybe_split(i, size, i->size);
+ spin_unlock_irqrestore(&freelist_lock, flags);
+ return i+1;
+ }
+ }
+ spin_unlock_irqrestore(&freelist_lock, flags);
+
+ /* Alloc a new page and return from that. */
+ return xmalloc_new_page(size);
+}
+
+void xfree(const void *p)
+{
+ unsigned long flags;
+ struct xmalloc_hdr *i, *tmp, *hdr;
+
+ if (!p)
+ return;
+
+ hdr = (struct xmalloc_hdr *)p - 1;
+
+ /* We know hdr will be on same page. */
+ BUG_ON(((long)p & PAGE_MASK) != ((long)hdr & PAGE_MASK));
+
+ /* Not previously freed. */
+ BUG_ON(hdr->freelist.next || hdr->freelist.prev);
+
+ /* Big allocs free directly. */
+ if (hdr->size >= PAGE_SIZE) {
+ free_xenheap_pages((unsigned long)hdr, get_order(hdr->size));
+ return;
+ }
+
+ /* Merge with other free block, or put in list. */
+ spin_lock_irqsave(&freelist_lock, flags);
+ list_for_each_entry_safe(i, tmp, &freelist, freelist) {
+ /* We follow this block? Swallow it. */
+ if ((void *)i + i->size == (void *)hdr) {
+ list_del(&i->freelist);
+ i->size += hdr->size;
+ hdr = i;
+ }
+ /* It follows us? Delete it and add it to us. */
+ if ((void *)hdr + hdr->size == (void *)i) {
+ list_del(&i->freelist);
+ hdr->size += i->size;
+ }
+ }
+
+ /* Did we free entire page? */
+ if (hdr->size == PAGE_SIZE) {
+ BUG_ON((((unsigned long)hdr) & (PAGE_SIZE-1)) != 0);
+ free_xenheap_pages((unsigned long)hdr, 0);
+ } else
+ list_add(&hdr->freelist, &freelist);
+ spin_unlock_irqrestore(&freelist_lock, flags);
+}
diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c
index ba4c53f927..009935efc0 100644
--- a/xen/drivers/char/console.c
+++ b/xen/drivers/char/console.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* console.c
*
@@ -21,7 +22,7 @@
#include <asm/mm.h>
/* opt_console: comma-separated list of console outputs. */
-static unsigned char opt_console[30] = "com1,vga";
+static unsigned char opt_console[30] = OPT_CONSOLE_STR;
string_param("console", opt_console);
/* opt_conswitch: a character pair controlling console switching. */
@@ -267,7 +268,7 @@ static void __serial_rx(unsigned char c, struct xen_regs *regs)
{
serial_rx_ring[SERIAL_RX_MASK(serial_rx_prod)] = c;
if ( serial_rx_prod++ == serial_rx_cons )
- send_guest_virq(dom0, VIRQ_CONSOLE);
+ send_guest_virq(dom0->exec_domain[0], VIRQ_CONSOLE);
}
}
@@ -300,7 +301,7 @@ long do_console_io(int cmd, int count, char *buffer)
#ifndef VERBOSE
/* Only domain-0 may access the emergency console. */
- if ( current->id != 0 )
+ if ( current->domain->id != 0 )
return -EPERM;
#endif
diff --git a/xen/drivers/char/serial.c b/xen/drivers/char/serial.c
index 2c6fc895b4..9ccad0ff4a 100644
--- a/xen/drivers/char/serial.c
+++ b/xen/drivers/char/serial.c
@@ -1,3 +1,4 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
/******************************************************************************
* serial.c
*
@@ -12,7 +13,6 @@
#include <xen/init.h>
#include <xen/irq.h>
#include <xen/keyhandler.h>
-#include <asm/pdb.h>
#include <xen/reboot.h>
#include <xen/sched.h>
#include <xen/serial.h>
@@ -33,14 +33,14 @@ string_param("com2", opt_com2);
#define MCR 0x04 /* Modem control */
#define LSR 0x05 /* line status */
#define MSR 0x06 /* Modem status */
-#define DLL 0x00 /* divisor latch (ls) ( DLAB=1) */
-#define DLM 0x01 /* divisor latch (ms) ( DLAB=1) */
+#define DLL 0x00 /* divisor latch (ls) (DLAB=1) */
+#define DLM 0x01 /* divisor latch (ms) (DLAB=1) */
/* Interrupt Enable Register */
#define IER_ERDAI 0x01 /* rx data recv'd */
#define IER_ETHREI 0x02 /* tx reg. empty */
#define IER_ELSI 0x04 /* rx line status */
-#define IER_EMSI 0x08 /* MODEM status */
+#define IER_EMSI 0x08 /* MODEM status */
/* FIFO control register */
#define FCR_ENABLE 0x01 /* enable FIFO */
@@ -331,11 +331,13 @@ int parse_serial_handle(char *conf)
goto fail;
}
+#ifndef NO_UART_CONFIG_OK
if ( !UART_ENABLED(&com[handle]) )
{
printk("ERROR: cannot use unconfigured serial port COM%d\n", handle+1);
return -1;
}
+#endif
if ( conf[4] == 'H' )
handle |= SERHND_HI;
diff --git a/xen/drivers/pci/pci.c b/xen/drivers/pci/pci.c
index 50a4ebb5e0..c3c25b1dba 100644
--- a/xen/drivers/pci/pci.c
+++ b/xen/drivers/pci/pci.c
@@ -1126,7 +1126,7 @@ static struct pci_bus * __devinit pci_alloc_bus(void)
{
struct pci_bus *b;
- b = xmalloc(sizeof(*b));
+ b = xmalloc(struct pci_bus);
if (b) {
memset(b, 0, sizeof(*b));
INIT_LIST_HEAD(&b->children);
@@ -1351,7 +1351,7 @@ struct pci_dev * __devinit pci_scan_device(struct pci_dev *temp)
if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
return NULL;
- dev = xmalloc(sizeof(*dev));
+ dev = xmalloc(struct pci_dev);
if (!dev)
return NULL;
@@ -1431,7 +1431,7 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
max = bus->secondary;
/* Create a device template */
- dev0 = xmalloc(sizeof(struct pci_dev));
+ dev0 = xmalloc(struct pci_dev);
if(!dev0) {
panic("Out of memory scanning PCI bus!\n");
}
diff --git a/xen/drivers/pci/setup-res.c b/xen/drivers/pci/setup-res.c
index 3435b2ac9c..59652dbcc7 100644
--- a/xen/drivers/pci/setup-res.c
+++ b/xen/drivers/pci/setup-res.c
@@ -171,10 +171,10 @@ pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
ln->res->start;
}
if (r_align > align) {
- tmp = xmalloc(sizeof(*tmp));
+ tmp = xmalloc(struct resource_list);
if (!tmp)
panic("pdev_sort_resources(): "
- "xmalloc() failed!\n");
+ "malloc() failed!\n");
tmp->next = ln;
tmp->res = r;
tmp->dev = dev;
diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h
index 5166c3f484..78fd023a76 100644
--- a/xen/include/asm-x86/config.h
+++ b/xen/include/asm-x86/config.h
@@ -4,8 +4,12 @@
* A Linux-style configuration list.
*/
-#ifndef __XEN_I386_CONFIG_H__
-#define __XEN_I386_CONFIG_H__
+#ifndef __X86_CONFIG_H__
+#define __X86_CONFIG_H__
+
+#ifdef __i386__
+#define CONFIG_VMX 1
+#endif
#define CONFIG_X86 1
@@ -48,6 +52,8 @@
#define HZ 100
+#define OPT_CONSOLE_STR "com1,vga"
+
/*
* Just to keep compiler happy.
* NB. DO NOT CHANGE SMP_CACHE_BYTES WITHOUT FIXING arch/i386/entry.S!!!
@@ -57,7 +63,6 @@
#define NR_CPUS 16
/* Linkage for x86 */
-#define asmlinkage __attribute__((regparm(0)))
#define __ALIGN .align 16,0x90
#define __ALIGN_STR ".align 16,0x90"
#define SYMBOL_NAME_STR(X) #X
@@ -78,7 +83,15 @@
#ifndef NDEBUG
#define MEMORY_GUARD
+#ifdef __x86_64__
+#define STACK_ORDER 2
+#endif
+#endif
+
+#ifndef STACK_ORDER
+#define STACK_ORDER 1
#endif
+#define STACK_SIZE (PAGE_SIZE << STACK_ORDER)
#ifndef __ASSEMBLY__
extern unsigned long _end; /* standard ELF symbol */
@@ -93,10 +106,15 @@ extern void __out_of_line_bug(int line) __attribute__((noreturn));
#if defined(__x86_64__)
+#define asmlinkage
+
#define XENHEAP_DEFAULT_MB (16)
#define PML4_ENTRY_BITS 39
-#define PML4_ENTRY_BYTES (1UL<<PML4_ENTRY_BITS)
+#define PML4_ENTRY_BYTES (1UL << PML4_ENTRY_BITS)
+#define PML4_ADDR(_slot) \
+ ((((_slot ## UL) >> 8) * 0xffff000000000000UL) | \
+ (_slot ## UL << PML4_ENTRY_BITS))
/*
* Memory layout:
@@ -116,7 +134,13 @@ extern void __out_of_line_bug(int line) __attribute__((noreturn));
* Shadow linear page table.
* 0xffff820000000000 - 0xffff827fffffffff [512GB, 2^39 bytes, PML4:260]
* Per-domain mappings (e.g., GDT, LDT).
- * 0xffff828000000000 - 0xffff8287ffffffff [512GB, 2^39 bytes, PML4:261]
+ * 0xffff828000000000 - 0xffff8283ffffffff [16GB, 2^34 bytes, PML4:261]
+ * Machine-to-phys translation table.
+ * 0xffff828400000000 - 0xffff8287ffffffff [16GB, 2^34 bytes, PML4:261]
+ * Page-frame information array.
+ * 0xffff828800000000 - 0xffff828bffffffff [16GB, 2^34 bytes, PML4:261]
+ * ioremap()/fixmap area.
+ * 0xffff828c00000000 - 0xffff82ffffffffff [464GB, PML4:261]
* Reserved for future use.
* 0xffff830000000000 - 0xffff83ffffffffff [1TB, 2^40 bytes, PML4:262-263]
* 1:1 direct mapping of all physical memory. Xen and its heap live here.
@@ -126,33 +150,46 @@ extern void __out_of_line_bug(int line) __attribute__((noreturn));
* Guest-defined use.
*/
+
/* Hypervisor reserves PML4 slots 256 to 271 inclusive. */
-#define HYPERVISOR_VIRT_START (0xFFFF800000000000UL)
-#define HYPERVISOR_VIRT_END (0xFFFF880000000000UL)
+#define HYPERVISOR_VIRT_START (PML4_ADDR(256))
+#define HYPERVISOR_VIRT_END (HYPERVISOR_VIRT_START + PML4_ENTRY_BYTES*16)
/* Slot 256: read-only guest-accessible machine-to-phys translation table. */
-#define RO_MPT_VIRT_START (HYPERVISOR_VIRT_START)
+#define RO_MPT_VIRT_START (PML4_ADDR(256))
#define RO_MPT_VIRT_END (RO_MPT_VIRT_START + PML4_ENTRY_BYTES/2)
/* Slot 257: read-only guest-accessible linear page table. */
-#define RO_LINEAR_PT_VIRT_START (RO_MPT_VIRT_END + PML4_ENTRY_BYTES/2)
+#define RO_LINEAR_PT_VIRT_START (PML4_ADDR(257))
#define RO_LINEAR_PT_VIRT_END (RO_LINEAR_PT_VIRT_START + PML4_ENTRY_BYTES)
/* Slot 258: linear page table (guest table). */
-#define LINEAR_PT_VIRT_START (RO_LINEAR_PT_VIRT_END)
+#define LINEAR_PT_VIRT_START (PML4_ADDR(258))
#define LINEAR_PT_VIRT_END (LINEAR_PT_VIRT_START + PML4_ENTRY_BYTES)
/* Slot 259: linear page table (shadow table). */
-#define SH_LINEAR_PT_VIRT_START (LINEAR_PT_VIRT_END)
+#define SH_LINEAR_PT_VIRT_START (PML4_ADDR(259))
#define SH_LINEAR_PT_VIRT_END (SH_LINEAR_PT_VIRT_START + PML4_ENTRY_BYTES)
/* Slot 260: per-domain mappings. */
-#define PERDOMAIN_VIRT_START (SH_LINEAR_PT_VIRT_END)
+#define PERDOMAIN_VIRT_START (PML4_ADDR(260))
#define PERDOMAIN_VIRT_END (PERDOMAIN_VIRT_START + PML4_ENTRY_BYTES)
+/* Slot 261: machine-to-phys conversion table (16GB). */
+#define RDWR_MPT_VIRT_START (PML4_ADDR(261))
+#define RDWR_MPT_VIRT_END (RDWR_MPT_VIRT_START + (16UL<<30))
+/* Slot 261: page-frame information array (16GB). */
+#define FRAMETABLE_VIRT_START (RDWR_MPT_VIRT_END)
+#define FRAMETABLE_VIRT_END (FRAMETABLE_VIRT_START + (16UL<<30))
+/* Slot 261: ioremap()/fixmap area (16GB). */
+#define IOREMAP_VIRT_START (FRAMETABLE_VIRT_END)
+#define IOREMAP_VIRT_END (IOREMAP_VIRT_START + (16UL<<30))
/* Slot 262-263: A direct 1:1 mapping of all of physical memory. */
-#define DIRECTMAP_VIRT_START (PERDOMAIN_VIRT_END + PML4_ENTRY_BYTES)
+#define DIRECTMAP_VIRT_START (PML4_ADDR(262))
#define DIRECTMAP_VIRT_END (DIRECTMAP_VIRT_START + PML4_ENTRY_BYTES*2)
#define PGT_base_page_table PGT_l4_page_table
#define __HYPERVISOR_CS64 0x0810
#define __HYPERVISOR_CS32 0x0808
-#define __HYPERVISOR_DS 0x0818
+#define __HYPERVISOR_CS __HYPERVISOR_CS64
+#define __HYPERVISOR_DS64 0x0000
+#define __HYPERVISOR_DS32 0x0818
+#define __HYPERVISOR_DS __HYPERVISOR_DS64
/* For generic assembly code: use macros to define operation/operand sizes. */
#define __OS "q" /* Operation Suffix */
@@ -160,6 +197,8 @@ extern void __out_of_line_bug(int line) __attribute__((noreturn));
#elif defined(__i386__)
+#define asmlinkage __attribute__((regparm(0)))
+
#define XENHEAP_DEFAULT_MB (12)
#define DIRECTMAP_PHYS_END (12*1024*1024)
@@ -176,10 +215,8 @@ extern void __out_of_line_bug(int line) __attribute__((noreturn));
/* Xen heap extends to end of 1:1 direct-mapped memory region. */
#define DIRECTMAP_VIRT_START (RO_MPT_VIRT_END)
#define DIRECTMAP_VIRT_END (DIRECTMAP_VIRT_START + DIRECTMAP_PHYS_END)
-#define XENHEAP_VIRT_START (DIRECTMAP_VIRT_START)
-#define XENHEAP_VIRT_END (DIRECTMAP_VIRT_END)
/* Machine-to-phys conversion table. */
-#define RDWR_MPT_VIRT_START (XENHEAP_VIRT_END)
+#define RDWR_MPT_VIRT_START (DIRECTMAP_VIRT_END)
#define RDWR_MPT_VIRT_END (RDWR_MPT_VIRT_START + (4*1024*1024))
/* Variable-length page-frame information array. */
#define FRAMETABLE_VIRT_START (RDWR_MPT_VIRT_END)
@@ -215,10 +252,13 @@ extern void __out_of_line_bug(int line) __attribute__((noreturn));
extern unsigned long xenheap_phys_end; /* user-configurable */
#endif
-#define GDT_VIRT_START (PERDOMAIN_VIRT_START)
-#define GDT_VIRT_END (GDT_VIRT_START + (64*1024))
-#define LDT_VIRT_START (GDT_VIRT_END)
-#define LDT_VIRT_END (LDT_VIRT_START + (64*1024))
+#define GDT_VIRT_START(ed) (PERDOMAIN_VIRT_START + ((ed)->eid << PDPT_VCPU_VA_SHIFT))
+#define GDT_VIRT_END(ed) (GDT_VIRT_START(ed) + (64*1024))
+#define LDT_VIRT_START(ed) (PERDOMAIN_VIRT_START + (64*1024) + ((ed)->eid << PDPT_VCPU_VA_SHIFT))
+#define LDT_VIRT_END(ed) (LDT_VIRT_START(ed) + (64*1024))
+
+#define PDPT_VCPU_SHIFT 5
+#define PDPT_VCPU_VA_SHIFT (PDPT_VCPU_SHIFT + PAGE_SHIFT)
#if defined(__x86_64__)
#define ELFSIZE 64
@@ -226,4 +266,4 @@ extern unsigned long xenheap_phys_end; /* user-configurable */
#define ELFSIZE 32
#endif
-#endif /* __XEN_I386_CONFIG_H__ */
+#endif /* __X86_CONFIG_H__ */
diff --git a/xen/include/asm-x86/cpufeature.h b/xen/include/asm-x86/cpufeature.h
index 8b2e913bff..117ca6a9d7 100644
--- a/xen/include/asm-x86/cpufeature.h
+++ b/xen/include/asm-x86/cpufeature.h
@@ -8,7 +8,7 @@
#define __ASM_X86_CPUFEATURE_H
/* Sample usage: CPU_FEATURE_P(cpu.x86_capability, FPU) */
-#define CPU_FEATURE_P(CAP, FEATURE) test_bit(CAP, X86_FEATURE_##FEATURE ##_BIT)
+#define CPU_FEATURE_P(CAP, FEATURE) test_bit(CAP, X86_FEATURE_##FEATURE)
#define NCAPINTS 6 /* Currently we have 6 32-bit words worth of info */
@@ -71,6 +71,8 @@
#define X86_FEATURE_P4 (3*32+ 7) /* P4 */
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
+#define X86_FEATURE_MWAIT (4*32+ 3) /* Monitor/Mwait support */
+#define X86_FEATURE_VMXE (4*32+ 5) /* Virtual Machine Extensions */
#define X86_FEATURE_EST (4*32+ 7) /* Enhanced SpeedStep */
/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
diff --git a/xen/include/asm-x86/desc.h b/xen/include/asm-x86/desc.h
index 0d6fc65b32..53f4f91e1f 100644
--- a/xen/include/asm-x86/desc.h
+++ b/xen/include/asm-x86/desc.h
@@ -1,16 +1,9 @@
#ifndef __ARCH_DESC_H
#define __ARCH_DESC_H
+#ifndef __ASSEMBLY__
#define LDT_ENTRY_SIZE 8
-#define __DOUBLEFAULT_TSS_ENTRY FIRST_RESERVED_GDT_ENTRY
-
-#define __FIRST_TSS_ENTRY (FIRST_RESERVED_GDT_ENTRY + 8)
-#define __FIRST_LDT_ENTRY (__FIRST_TSS_ENTRY + 1)
-
-#define __TSS(n) (((n)<<1) + __FIRST_TSS_ENTRY)
-#define __LDT(n) (((n)<<1) + __FIRST_LDT_ENTRY)
-
#define load_TR(n) __asm__ __volatile__ ("ltr %%ax" : : "a" (__TSS(n)<<3) )
/*
@@ -25,7 +18,7 @@
(((_s)>>3) > LAST_RESERVED_GDT_ENTRY) || \
((_s)&4)) && \
(((_s)&3) == 1))
-#define VALID_CODESEL(_s) ((_s) == FLAT_RING1_CS || VALID_SEL(_s))
+#define VALID_CODESEL(_s) ((_s) == FLAT_GUESTOS_CS || VALID_SEL(_s))
/* These are bitmasks for the high 32 bits of a descriptor table entry. */
#define _SEGMENT_TYPE (15<< 8)
@@ -38,25 +31,101 @@
#define _SEGMENT_DB ( 1<<22) /* 16- or 32-bit segment */
#define _SEGMENT_G ( 1<<23) /* Granularity */
-#ifndef __ASSEMBLY__
struct desc_struct {
- unsigned long a,b;
+ u32 a, b;
};
+#if defined(__x86_64__)
+
+#define __FIRST_TSS_ENTRY (FIRST_RESERVED_GDT_ENTRY + 8)
+#define __FIRST_LDT_ENTRY (__FIRST_TSS_ENTRY + 2)
+
+#define __TSS(n) (((n)<<2) + __FIRST_TSS_ENTRY)
+#define __LDT(n) (((n)<<2) + __FIRST_LDT_ENTRY)
+
+typedef struct {
+ u64 a, b;
+} idt_entry_t;
+
+#define _set_gate(gate_addr,type,dpl,addr) \
+do { \
+ (gate_addr)->a = \
+ (((unsigned long)(addr) & 0xFFFF0000UL) << 32) | \
+ ((unsigned long)(dpl) << 45) | \
+ ((unsigned long)(type) << 40) | \
+ ((unsigned long)(addr) & 0xFFFFUL) | \
+ ((unsigned long)__HYPERVISOR_CS64 << 16) | \
+ (1UL << 47); \
+ (gate_addr)->b = \
+ ((unsigned long)(addr) >> 32); \
+} while (0)
+
+#define _set_tssldt_desc(desc,addr,limit,type) \
+do { \
+ (desc)[0].a = \
+ ((u32)(addr) << 16) | ((u32)(limit) & 0xFFFF); \
+ (desc)[0].b = \
+ ((u32)(addr) & 0xFF000000U) | \
+ ((u32)(type) << 8) | 0x8000U | \
+ (((u32)(addr) & 0x00FF0000U) >> 16); \
+ (desc)[1].a = (u32)(((unsigned long)(addr)) >> 32); \
+ (desc)[1].b = 0; \
+} while (0)
+
+#elif defined(__i386__)
+
+#define __DOUBLEFAULT_TSS_ENTRY FIRST_RESERVED_GDT_ENTRY
+
+#define __FIRST_TSS_ENTRY (FIRST_RESERVED_GDT_ENTRY + 8)
+#define __FIRST_LDT_ENTRY (__FIRST_TSS_ENTRY + 1)
+
+#define __TSS(n) (((n)<<1) + __FIRST_TSS_ENTRY)
+#define __LDT(n) (((n)<<1) + __FIRST_LDT_ENTRY)
+
+typedef struct desc_struct idt_entry_t;
+
+#define _set_gate(gate_addr,type,dpl,addr) \
+do { \
+ int __d0, __d1; \
+ __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
+ "movw %4,%%dx\n\t" \
+ "movl %%eax,%0\n\t" \
+ "movl %%edx,%1" \
+ :"=m" (*((long *) (gate_addr))), \
+ "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
+ :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
+ "3" ((char *) (addr)),"2" (__HYPERVISOR_CS << 16)); \
+} while (0)
+
+#define _set_tssldt_desc(n,addr,limit,type) \
+__asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
+ "movw %%ax,2(%2)\n\t" \
+ "rorl $16,%%eax\n\t" \
+ "movb %%al,4(%2)\n\t" \
+ "movb %4,5(%2)\n\t" \
+ "movb $0,6(%2)\n\t" \
+ "movb %%ah,7(%2)\n\t" \
+ "rorl $16,%%eax" \
+ : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type|0x80))
+
+#endif
+
extern struct desc_struct gdt_table[];
-extern struct desc_struct *idt, *gdt;
+extern struct desc_struct *gdt;
+extern idt_entry_t *idt;
struct Xgt_desc_struct {
- unsigned short size;
- unsigned long address __attribute__((packed));
+ unsigned short size;
+ unsigned long address __attribute__((packed));
};
#define idt_descr (*(struct Xgt_desc_struct *)((char *)&idt - 2))
#define gdt_descr (*(struct Xgt_desc_struct *)((char *)&gdt - 2))
extern void set_intr_gate(unsigned int irq, void * addr);
+extern void set_system_gate(unsigned int n, void *addr);
+extern void set_task_gate(unsigned int n, unsigned int sel);
extern void set_tss_desc(unsigned int n, void *addr);
#endif /* !__ASSEMBLY__ */
-
-#endif
+#endif /* __ARCH_DESC_H */
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
new file mode 100644
index 0000000000..e3b2016cab
--- /dev/null
+++ b/xen/include/asm-x86/domain.h
@@ -0,0 +1,119 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+
+#ifndef __ASM_DOMAIN_H__
+#define __ASM_DOMAIN_H__
+
+struct trap_bounce {
+ unsigned long error_code;
+ unsigned long cr2;
+ unsigned short flags; /* TBF_ */
+ unsigned short cs;
+ unsigned long eip;
+};
+
+struct arch_domain
+{
+ l1_pgentry_t *mm_perdomain_pt;
+
+ /* shadow mode status and controls */
+ unsigned int shadow_mode; /* flags to control shadow table operation */
+ spinlock_t shadow_lock;
+ unsigned long min_pfn; /* min host physical */
+ unsigned long max_pfn; /* max host physical */
+
+ /* shadow hashtable */
+ struct shadow_status *shadow_ht;
+ struct shadow_status *shadow_ht_free;
+ struct shadow_status *shadow_ht_extras; /* extra allocation units */
+ unsigned int shadow_extras_count;
+
+ /* shadow dirty bitmap */
+ unsigned long *shadow_dirty_bitmap;
+ unsigned int shadow_dirty_bitmap_size; /* in pages, bit per page */
+
+ /* shadow mode stats */
+ unsigned int shadow_page_count;
+ unsigned int shadow_fault_count;
+ unsigned int shadow_dirty_count;
+ unsigned int shadow_dirty_net_count;
+ unsigned int shadow_dirty_block_count;
+} __cacheline_aligned;
+
+struct arch_exec_domain
+{
+ unsigned long guestos_sp;
+ unsigned long guestos_ss;
+
+ unsigned long flags; /* TF_ */
+
+ /* Hardware debugging registers */
+ unsigned long debugreg[8]; /* %%db0-7 debug registers */
+
+ /* floating point info */
+ struct i387_state i387;
+
+ /* general user-visible register state */
+ execution_context_t user_ctxt;
+
+ void (*schedule_tail) (struct exec_domain *);
+
+ /*
+ * Return vectors pushed to us by guest OS.
+ * The stack frame for events is exactly that of an x86 hardware interrupt.
+ * The stack frame for a failsafe callback is augmented with saved values
+ * for segment registers %ds, %es, %fs and %gs:
+ * %ds, %es, %fs, %gs, %eip, %cs, %eflags [, %oldesp, %oldss]
+ */
+ unsigned long event_selector; /* entry CS */
+ unsigned long event_address; /* entry EIP */
+
+ unsigned long failsafe_selector; /* entry CS */
+ unsigned long failsafe_address; /* entry EIP */
+
+ /* Bounce information for propagating an exception to guest OS. */
+ struct trap_bounce trap_bounce;
+
+ /* I/O-port access bitmap. */
+ u64 io_bitmap_sel; /* Selector to tell us which part of the IO bitmap are
+ * "interesting" (i.e. have clear bits) */
+ u8 *io_bitmap; /* Pointer to task's IO bitmap or NULL */
+
+ /* Trap info. */
+#ifdef ARCH_HAS_FAST_TRAP
+ int fast_trap_idx;
+ struct desc_struct fast_trap_desc;
+#endif
+ trap_info_t traps[256];
+#ifdef CONFIG_VMX
+ struct arch_vmx_struct arch_vmx; /* Virtual Machine Extensions */
+#endif
+
+ /*
+ * Every domain has a L1 pagetable of its own. Per-domain mappings
+ * are put in this table (eg. the current GDT is mapped here).
+ */
+ l1_pgentry_t *perdomain_ptes;
+ pagetable_t pagetable;
+
+ pagetable_t monitor_table;
+ pagetable_t shadow_table;
+ l2_pgentry_t *vpagetable; /* virtual address of pagetable */
+ l2_pgentry_t *shadow_vtable; /* virtual address of shadow_table */
+ l2_pgentry_t *guest_pl2e_cache; /* guest page directory cache */
+
+ /* Virtual CR2 value. Can be read/written by guest. */
+ unsigned long guest_cr2;
+
+ /* Current LDT details. */
+ unsigned long ldt_base, ldt_ents, shadow_ldt_mapcnt;
+ /* Next entry is passed to LGDT on domain switch. */
+ char gdt[10]; /* NB. 10 bytes needed for x86_64. Use 6 bytes for x86_32. */
+} __cacheline_aligned;
+
+#define IDLE0_ARCH_EXEC_DOMAIN \
+{ \
+ perdomain_ptes: 0, \
+ pagetable: mk_pagetable(__pa(idle_pg_table)) \
+}
+
+#endif /* __ASM_DOMAIN_H__ */
diff --git a/xen/include/asm-x86/domain_page.h b/xen/include/asm-x86/domain_page.h
index d8cdf0b74e..3eae53933d 100644
--- a/xen/include/asm-x86/domain_page.h
+++ b/xen/include/asm-x86/domain_page.h
@@ -1,29 +1,5 @@
-/******************************************************************************
- * domain_page.h
- *
- * Allow temporary mapping of domain page frames into Xen space.
- */
-
-#ifndef __ASM_DOMAIN_PAGE_H__
-#define __ASM_DOMAIN_PAGE_H__
-
-#include <xen/config.h>
-#include <xen/sched.h>
-
-extern unsigned long *mapcache;
-#define MAPCACHE_ENTRIES 1024
-
-/*
- * Maps a given physical address, returning corresponding virtual address.
- * The entire page containing that VA is now accessible until a
- * corresponding call to unmap_domain_mem().
- */
-extern void *map_domain_mem(unsigned long pa);
-
-/*
- * Pass a VA within a page previously mapped with map_domain_mem().
- * That page will then be removed from the mapping lists.
- */
-extern void unmap_domain_mem(void *va);
-
-#endif /* __ASM_DOMAIN_PAGE_H__ */
+#ifdef __x86_64__
+#include <asm/x86_64/domain_page.h>
+#else
+#include <asm/x86_32/domain_page.h>
+#endif
diff --git a/xen/include/asm-x86/e820.h b/xen/include/asm-x86/e820.h
index 52d342b523..060ef94a96 100644
--- a/xen/include/asm-x86/e820.h
+++ b/xen/include/asm-x86/e820.h
@@ -5,10 +5,12 @@
#define E820MAX 32
-#define E820_RAM 1
-#define E820_RESERVED 2
-#define E820_ACPI 3
-#define E820_NVS 4
+#define E820_RAM 1
+#define E820_RESERVED 2
+#define E820_ACPI 3
+#define E820_NVS 4
+#define E820_IO 16
+#define E820_SHARED_PAGE 17
#ifndef __ASSEMBLY__
struct e820entry {
diff --git a/xen/include/asm-x86/fixmap.h b/xen/include/asm-x86/fixmap.h
index 211d4cf895..e123cb791a 100644
--- a/xen/include/asm-x86/fixmap.h
+++ b/xen/include/asm-x86/fixmap.h
@@ -26,7 +26,7 @@
*/
enum fixed_addresses {
#ifdef CONFIG_X86_LOCAL_APIC
- FIX_APIC_BASE, /* local (CPU) APIC) -- required for SMP or not */
+ FIX_APIC_BASE, /* local (CPU) APIC -- required for SMP or not */
#endif
#ifdef CONFIG_X86_IO_APIC
FIX_IO_APIC_BASE_0,
@@ -39,18 +39,18 @@ enum fixed_addresses {
__end_of_fixed_addresses
};
-#define FIXADDR_TOP (0xffffe000UL)
+#define FIXADDR_TOP (IOREMAP_VIRT_END - PAGE_SIZE)
#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
-extern void __set_fixmap(enum fixed_addresses idx,
- l1_pgentry_t entry);
+extern void __set_fixmap(
+ enum fixed_addresses idx, unsigned long p, unsigned long flags);
#define set_fixmap(idx, phys) \
- __set_fixmap(idx, mk_l1_pgentry(phys|PAGE_HYPERVISOR))
+ __set_fixmap(idx, phys, PAGE_HYPERVISOR)
#define set_fixmap_nocache(idx, phys) \
- __set_fixmap(idx, mk_l1_pgentry(phys|PAGE_HYPERVISOR_NOCACHE))
+ __set_fixmap(idx, phys, PAGE_HYPERVISOR_NOCACHE)
#define fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
diff --git a/xen/include/asm-x86/i387.h b/xen/include/asm-x86/i387.h
index 5221da49db..a09422d74f 100644
--- a/xen/include/asm-x86/i387.h
+++ b/xen/include/asm-x86/i387.h
@@ -15,16 +15,16 @@
#include <asm/processor.h>
extern void init_fpu(void);
-extern void save_init_fpu( struct domain *tsk );
-extern void restore_fpu( struct domain *tsk );
+extern void save_init_fpu( struct exec_domain *tsk );
+extern void restore_fpu( struct exec_domain *tsk );
#define unlazy_fpu( tsk ) do { \
- if ( test_bit(DF_USEDFPU, &tsk->flags) ) \
+ if ( test_bit(EDF_USEDFPU, &tsk->ed_flags) ) \
save_init_fpu( tsk ); \
} while (0)
#define clear_fpu( tsk ) do { \
- if ( test_and_clear_bit(DF_USEDFPU, &tsk->flags) ) { \
+ if ( test_and_clear_bit(EDF_USEDFPU, &tsk->ed_flags) ) { \
asm volatile("fwait"); \
stts(); \
} \
diff --git a/xen/include/asm-x86/init.h b/xen/include/asm-x86/init.h
new file mode 100644
index 0000000000..8f1e764080
--- /dev/null
+++ b/xen/include/asm-x86/init.h
@@ -0,0 +1,29 @@
+#ifndef _XEN_ASM_INIT_H
+#define _XEN_ASM_INIT_H
+
+/*
+ * Mark functions and data as being only used at initialization
+ * or exit time.
+ */
+#define __init \
+ __attribute__ ((__section__ (".init.text")))
+#define __exit \
+ __attribute_used__ __attribute__ ((__section__(".text.exit")))
+#define __initdata \
+ __attribute__ ((__section__ (".init.data")))
+#define __exitdata \
+ __attribute_used__ __attribute__ ((__section__ (".data.exit")))
+#define __initsetup \
+ __attribute_used__ __attribute__ ((__section__ (".setup.init")))
+#define __init_call \
+ __attribute_used__ __attribute__ ((__section__ (".initcall.init")))
+#define __exit_call \
+ __attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
+
+/* For assembly routines
+#define __INIT .section ".text.init","ax"
+#define __FINIT .previous
+#define __INITDATA .section ".data.init","aw"
+*/
+
+#endif /* _XEN_ASM_INIT_H */
diff --git a/xen/include/asm-x86/irq.h b/xen/include/asm-x86/irq.h
index 2779282659..bc7ecfa317 100644
--- a/xen/include/asm-x86/irq.h
+++ b/xen/include/asm-x86/irq.h
@@ -15,11 +15,11 @@ extern void enable_irq(unsigned int);
* IDT vectors usable for external interrupt sources start
* at 0x20:
*/
-#define FIRST_EXTERNAL_VECTOR 0x30
+#define FIRST_EXTERNAL_VECTOR 0x30
#define NR_IRQS (256 - FIRST_EXTERNAL_VECTOR)
-#define HYPERCALL_VECTOR 0x82
+#define HYPERCALL_VECTOR 0x82
/*
* Vectors 0x30-0x3f are used for ISA interrupts.
@@ -28,30 +28,30 @@ extern void enable_irq(unsigned int);
/*
* Special IRQ vectors used by the SMP architecture, 0xf0-0xff
*/
-#define SPURIOUS_APIC_VECTOR 0xff
-#define ERROR_APIC_VECTOR 0xfe
-#define INVALIDATE_TLB_VECTOR 0xfd
-#define EVENT_CHECK_VECTOR 0xfc
-#define CALL_FUNCTION_VECTOR 0xfb
-#define KDB_VECTOR 0xfa
+#define SPURIOUS_APIC_VECTOR 0xff
+#define ERROR_APIC_VECTOR 0xfe
+#define INVALIDATE_TLB_VECTOR 0xfd
+#define EVENT_CHECK_VECTOR 0xfc
+#define CALL_FUNCTION_VECTOR 0xfb
+#define KDB_VECTOR 0xfa
/*
* Local APIC timer IRQ vector is on a different priority level,
* to work around the 'lost local interrupt if more than 2 IRQ
* sources per level' errata.
*/
-#define LOCAL_TIMER_VECTOR 0xef
+#define LOCAL_TIMER_VECTOR 0xef
/*
* First APIC vector available to drivers: (vectors 0x40-0xee)
* we start at 0x41 to spread out vectors evenly between priority
* levels. (0x82 is the hypercall vector)
*/
-#define FIRST_DEVICE_VECTOR 0x41
-#define FIRST_SYSTEM_VECTOR 0xef
+#define FIRST_DEVICE_VECTOR 0x41
+#define FIRST_SYSTEM_VECTOR 0xef
extern int irq_vector[NR_IRQS];
-#define IO_APIC_VECTOR(irq) irq_vector[irq]
+#define IO_APIC_VECTOR(irq) irq_vector[irq]
/*
* Various low-level irq details needed by irq.c, process.c,
@@ -84,68 +84,13 @@ extern char _stext, _etext;
#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
-#define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v)
-#define XBUILD_SMP_INTERRUPT(x,v)\
-asmlinkage void x(void); \
-asmlinkage void call_##x(void); \
-__asm__( \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(x) ":\n\t" \
- "push"__OS" $"#v"<<16\n\t" \
- SAVE_ALL(a) \
- SYMBOL_NAME_STR(call_##x)":\n\t" \
- "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
- "jmp ret_from_intr\n");
-
-#define BUILD_SMP_TIMER_INTERRUPT(x,v) XBUILD_SMP_TIMER_INTERRUPT(x,v)
-#define XBUILD_SMP_TIMER_INTERRUPT(x,v) \
-asmlinkage void x(struct xen_regs * regs); \
-asmlinkage void call_##x(void); \
-__asm__( \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(x) ":\n\t" \
- "push"__OS" $"#v"<<16\n\t" \
- SAVE_ALL(a) \
- "mov %"__OP"sp,%"__OP"ax\n\t" \
- "push %"__OP"ax\n\t" \
- SYMBOL_NAME_STR(call_##x)":\n\t" \
- "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
- "add $4,%"__OP"sp\n\t" \
- "jmp ret_from_intr\n");
-
-#define BUILD_COMMON_IRQ() \
-asmlinkage void call_do_IRQ(void); \
-__asm__( \
- "\n" __ALIGN_STR"\n" \
- "common_interrupt:\n\t" \
- SAVE_ALL(a) \
- SYMBOL_NAME_STR(call_do_IRQ)":\n\t" \
- "call " SYMBOL_NAME_STR(do_IRQ) "\n\t" \
- "jmp ret_from_intr\n");
-
-#define IRQ_NAME2(nr) nr##_interrupt(void)
-#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
-
-#define BUILD_IRQ(nr) \
-asmlinkage void IRQ_NAME(nr); \
-__asm__( \
-"\n"__ALIGN_STR"\n" \
-SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
- "push"__OS" $"#nr"<<16\n\t" \
- "jmp common_interrupt");
-
-extern unsigned long prof_cpu_mask;
-extern unsigned int *prof_buffer;
-extern unsigned long prof_len;
-extern unsigned long prof_shift;
-
#include <xen/irq.h>
static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
{
#if defined(CONFIG_X86_IO_APIC)
- if (IO_APIC_IRQ(i))
- send_IPI_self(IO_APIC_VECTOR(i));
+ if (IO_APIC_IRQ(i))
+ send_IPI_self(IO_APIC_VECTOR(i));
#endif
}
diff --git a/xen/include/asm-x86/ldt.h b/xen/include/asm-x86/ldt.h
index 5b13bec994..d44d896de1 100644
--- a/xen/include/asm-x86/ldt.h
+++ b/xen/include/asm-x86/ldt.h
@@ -1,25 +1,27 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+
#ifndef __ARCH_LDT_H
#define __ARCH_LDT_H
#ifndef __ASSEMBLY__
-static inline void load_LDT(struct domain *p)
+static inline void load_LDT(struct exec_domain *ed)
{
unsigned int cpu;
struct desc_struct *desc;
unsigned long ents;
-
- if ( (ents = p->mm.ldt_ents) == 0 )
+
+ if ( (ents = ed->arch.ldt_ents) == 0 )
{
__asm__ __volatile__ ( "lldt %%ax" : : "a" (0) );
}
else
{
cpu = smp_processor_id();
- desc = (struct desc_struct *)GET_GDT_ADDRESS(p) + __LDT(cpu);
- desc->a = ((LDT_VIRT_START&0xffff)<<16) | (ents*8-1);
- desc->b = (LDT_VIRT_START&(0xff<<24)) | 0x8200 |
- ((LDT_VIRT_START&0xff0000)>>16);
+ desc = (struct desc_struct *)GET_GDT_ADDRESS(ed) + __LDT(cpu);
+ desc->a = ((LDT_VIRT_START(ed)&0xffff)<<16) | (ents*8-1);
+ desc->b = (LDT_VIRT_START(ed)&(0xff<<24)) | 0x8200 |
+ ((LDT_VIRT_START(ed)&0xff0000)>>16);
__asm__ __volatile__ ( "lldt %%ax" : : "a" (__LDT(cpu)<<3) );
}
}
diff --git a/xen/include/asm-x86/mm.h b/xen/include/asm-x86/mm.h
index 2af462e37d..a16a005fb5 100644
--- a/xen/include/asm-x86/mm.h
+++ b/xen/include/asm-x86/mm.h
@@ -30,6 +30,9 @@ struct pfn_info
/* Each frame can be threaded onto a doubly-linked list. */
struct list_head list;
+ /* Timestamp from 'TLB clock', used to reduce need for safety flushes. */
+ u32 tlbflush_timestamp;
+
/* Reference count and various PGC_xxx flags and fields. */
u32 count_info;
@@ -39,24 +42,22 @@ struct pfn_info
/* Page is in use: ((count_info & PGC_count_mask) != 0). */
struct {
/* Owner of this page (NULL if page is anonymous). */
- struct domain *domain;
+ u32 _domain; /* pickled format */
/* Type reference count and various PGT_xxx flags and fields. */
u32 type_info;
- } inuse;
+ } PACKED inuse;
/* Page is on a free list: ((count_info & PGC_count_mask) == 0). */
struct {
/* Mask of possibly-tainted TLBs. */
- unsigned long cpu_mask;
+ u32 cpu_mask;
/* Order-size of the free chunk this page is the head of. */
u8 order;
- } free;
+ } PACKED free;
- } u;
+ } PACKED u;
- /* Timestamp from 'TLB clock', used to reduce need for safety flushes. */
- u32 tlbflush_timestamp;
-};
+} PACKED;
/* The following page types are MUTUALLY EXCLUSIVE. */
#define PGT_none (0<<29) /* no special uses of this page */
@@ -97,9 +98,25 @@ struct pfn_info
#define IS_XEN_HEAP_FRAME(_pfn) (page_to_phys(_pfn) < xenheap_phys_end)
+#if defined(__i386__)
+
+#define pickle_domptr(_d) ((u32)(unsigned long)(_d))
+#define unpickle_domptr(_d) ((struct domain *)(unsigned long)(_d))
+
+#elif defined(__x86_64__)
+static inline struct domain *unpickle_domptr(u32 _domain)
+{ return (_domain == 0) ? NULL : __va(_domain); }
+static inline u32 pickle_domptr(struct domain *domain)
+{ return (domain == NULL) ? 0 : (u32)__pa(domain); }
+
+#endif
+
+#define page_get_owner(_p) (unpickle_domptr((_p)->u.inuse._domain))
+#define page_set_owner(_p,_d) ((_p)->u.inuse._domain = pickle_domptr(_d))
+
#define SHARE_PFN_WITH_DOMAIN(_pfn, _dom) \
do { \
- (_pfn)->u.inuse.domain = (_dom); \
+ page_set_owner((_pfn), (_dom)); \
/* The incremented type count is intended to pin to 'writable'. */ \
(_pfn)->u.inuse.type_info = PGT_writable_page | PGT_validated | 1; \
wmb(); /* install valid domain ptr before updating refcnt. */ \
@@ -142,7 +159,8 @@ static inline int get_page(struct pfn_info *page,
struct domain *domain)
{
u32 x, nx, y = page->count_info;
- struct domain *d, *nd = page->u.inuse.domain;
+ u32 d, nd = page->u.inuse._domain;
+ u32 _domain = pickle_domptr(domain);
do {
x = y;
@@ -150,10 +168,10 @@ static inline int get_page(struct pfn_info *page,
d = nd;
if ( unlikely((x & PGC_count_mask) == 0) || /* Not allocated? */
unlikely((nx & PGC_count_mask) == 0) || /* Count overflow? */
- unlikely(d != domain) ) /* Wrong owner? */
+ unlikely(d != _domain) ) /* Wrong owner? */
{
DPRINTK("Error pfn %08lx: ed=%p, sd=%p, caf=%08x, taf=%08x\n",
- page_to_pfn(page), domain, d,
+ page_to_pfn(page), domain, unpickle_domptr(d),
x, page->u.inuse.type_info);
return 0;
}
@@ -198,7 +216,7 @@ static inline int get_page_and_type(struct pfn_info *page,
ASSERT(((_p)->u.inuse.type_info & PGT_count_mask) != 0)
#define ASSERT_PAGE_IS_DOMAIN(_p, _d) \
ASSERT(((_p)->count_info & PGC_count_mask) != 0); \
- ASSERT((_p)->u.inuse.domain == (_d))
+ ASSERT(page_get_owner(_p) == (_d))
int check_descriptor(unsigned long *d);
@@ -215,14 +233,15 @@ void synchronise_pagetables(unsigned long cpu_mask);
* contiguous (or near contiguous) physical memory.
*/
#undef machine_to_phys_mapping
-#ifdef __x86_64__
-extern unsigned long *machine_to_phys_mapping;
-#else
-/* Don't call virt_to_phys on this: it isn't direct mapped. Using
- m2p_start_mfn instead. */
+
+/*
+ * The phys_to_machine_mapping is the reversed mapping of MPT for full
+ * virtualization.
+ */
+#undef phys_to_machine_mapping
+
#define machine_to_phys_mapping ((unsigned long *)RDWR_MPT_VIRT_START)
-extern unsigned long m2p_start_mfn;
-#endif
+#define phys_to_machine_mapping ((unsigned long *)PERDOMAIN_VIRT_START)
#define set_machinetophys(_mfn, _pfn) machine_to_phys_mapping[(_mfn)] = (_pfn)
@@ -231,14 +250,14 @@ extern unsigned long m2p_start_mfn;
#ifdef MEMORY_GUARD
void *memguard_init(void *heap_start);
+void memguard_guard_stack(void *p);
void memguard_guard_range(void *p, unsigned long l);
void memguard_unguard_range(void *p, unsigned long l);
-int memguard_is_guarded(void *p);
#else
#define memguard_init(_s) (_s)
+#define memguard_guard_stack(_p) ((void)0)
#define memguard_guard_range(_p,_l) ((void)0)
#define memguard_unguard_range(_p,_l) ((void)0)
-#define memguard_is_guarded(_p) (0)
#endif
@@ -276,6 +295,8 @@ extern ptwr_info_t ptwr_info[];
void ptwr_flush(const int);
int ptwr_do_page_fault(unsigned long);
+int new_guest_cr3(unsigned long pfn);
+
#define __cleanup_writable_pagetable(_what) \
do { \
int cpu = smp_processor_id(); \
diff --git a/xen/include/asm-x86/msr.h b/xen/include/asm-x86/msr.h
index a412963fd9..ea17a45aef 100644
--- a/xen/include/asm-x86/msr.h
+++ b/xen/include/asm-x86/msr.h
@@ -84,6 +84,10 @@
#define MSR_MTRRcap 0x0fe
#define MSR_IA32_BBL_CR_CTL 0x119
+#define MSR_IA32_SYSENTER_CS 0x174
+#define MSR_IA32_SYSENTER_ESP 0x175
+#define MSR_IA32_SYSENTER_EIP 0x176
+
#define MSR_IA32_MCG_CAP 0x179
#define MSR_IA32_MCG_STATUS 0x17a
#define MSR_IA32_MCG_CTL 0x17b
@@ -91,12 +95,6 @@
#define MSR_IA32_EVNTSEL0 0x186
#define MSR_IA32_EVNTSEL1 0x187
-#define MSR_IA32_DEBUGCTLMSR 0x1d9
-#define MSR_IA32_LASTBRANCHFROMIP 0x1db
-#define MSR_IA32_LASTBRANCHTOIP 0x1dc
-#define MSR_IA32_LASTINTFROMIP 0x1dd
-#define MSR_IA32_LASTINTTOIP 0x1de
-
#define MSR_MTRRfix64K_00000 0x250
#define MSR_MTRRfix16K_80000 0x258
#define MSR_MTRRfix16K_A0000 0x259
@@ -115,6 +113,8 @@
#define MSR_IA32_MC0_ADDR 0x402
#define MSR_IA32_MC0_MISC 0x403
+#define MSR_IA32_DS_AREA 0x600
+
#define MSR_IA32_APICBASE 0x1b
#define MSR_IA32_APICBASE_BSP (1<<8)
#define MSR_IA32_APICBASE_ENABLE (1<<11)
@@ -134,11 +134,22 @@
#define MSR_IA32_THERM_STATUS 0x19c
#define MSR_IA32_MISC_ENABLE 0x1a0
+#define MSR_IA32_MISC_ENABLE_PERF_AVAIL (1<<7)
+#define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL (1<<11)
+#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL (1<<12)
+
#define MSR_IA32_DEBUGCTLMSR 0x1d9
-#define MSR_IA32_LASTBRANCHFROMIP 0x1db
-#define MSR_IA32_LASTBRANCHTOIP 0x1dc
-#define MSR_IA32_LASTINTFROMIP 0x1dd
-#define MSR_IA32_LASTINTTOIP 0x1de
+#define MSR_IA32_DEBUGCTLMSR_LBR (1<<0)
+#define MSR_IA32_DEBUGCTLMSR_BTF (1<<1)
+#define MSR_IA32_DEBUGCTLMSR_TR (1<<2)
+#define MSR_IA32_DEBUGCTLMSR_BTS (1<<3)
+#define MSR_IA32_DEBUGCTLMSR_BTINT (1<<4)
+
+#define MSR_IA32_LASTBRANCH_TOS 0x1da
+#define MSR_IA32_LASTBRANCH_0 0x1db
+#define MSR_IA32_LASTBRANCH_1 0x1dc
+#define MSR_IA32_LASTBRANCH_2 0x1dd
+#define MSR_IA32_LASTBRANCH_3 0x1de
#define MSR_IA32_MC0_CTL 0x400
#define MSR_IA32_MC0_STATUS 0x401
@@ -150,6 +161,7 @@
#define MSR_P6_EVNTSEL0 0x186
#define MSR_P6_EVNTSEL1 0x187
+
/* K7/K8 MSRs. Not complete. See the architecture manual for a more complete list. */
#define MSR_K7_EVNTSEL0 0xC0010000
#define MSR_K7_PERFCTR0 0xC0010004
diff --git a/xen/include/asm-x86/page.h b/xen/include/asm-x86/page.h
index c016f4b5e0..06346dc9d9 100644
--- a/xen/include/asm-x86/page.h
+++ b/xen/include/asm-x86/page.h
@@ -34,7 +34,11 @@
#endif
#define PAGE_SHIFT L1_PAGETABLE_SHIFT
+#ifndef __ASSEMBLY__
#define PAGE_SIZE (1UL << PAGE_SHIFT)
+#else
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+#endif
#define PAGE_MASK (~(PAGE_SIZE-1))
#define clear_page(_p) memset((void *)(_p), 0, PAGE_SIZE)
@@ -46,7 +50,6 @@ typedef struct { unsigned long l1_lo; } l1_pgentry_t;
typedef struct { unsigned long l2_lo; } l2_pgentry_t;
typedef struct { unsigned long l3_lo; } l3_pgentry_t;
typedef struct { unsigned long l4_lo; } l4_pgentry_t;
-typedef struct { unsigned long pt_lo; } pagetable_t;
#endif /* !__ASSEMBLY__ */
/* Strip type from a table entry. */
@@ -54,14 +57,12 @@ typedef struct { unsigned long pt_lo; } pagetable_t;
#define l2_pgentry_val(_x) ((_x).l2_lo)
#define l3_pgentry_val(_x) ((_x).l3_lo)
#define l4_pgentry_val(_x) ((_x).l4_lo)
-#define pagetable_val(_x) ((_x).pt_lo)
/* Add type to a table entry. */
#define mk_l1_pgentry(_x) ( (l1_pgentry_t) { (_x) } )
#define mk_l2_pgentry(_x) ( (l2_pgentry_t) { (_x) } )
#define mk_l3_pgentry(_x) ( (l3_pgentry_t) { (_x) } )
#define mk_l4_pgentry(_x) ( (l4_pgentry_t) { (_x) } )
-#define mk_pagetable(_x) ( (pagetable_t) { (_x) } )
/* Turn a typed table entry into a page index. */
#define l1_pgentry_to_pagenr(_x) (l1_pgentry_val(_x) >> PAGE_SHIFT)
@@ -91,11 +92,23 @@ typedef struct { unsigned long pt_lo; } pagetable_t;
((_a) >> L2_PAGETABLE_SHIFT)
#elif defined(__x86_64__)
#define l2_table_offset(_a) \
- (((_a) >> L2_PAGETABLE_SHIFT) & (ENTRIES_PER_L2_PAGETABLE -1))
+ (((_a) >> L2_PAGETABLE_SHIFT) & (ENTRIES_PER_L2_PAGETABLE - 1))
#define l3_table_offset(_a) \
- (((_a) >> L3_PAGETABLE_SHIFT) & (ENTRIES_PER_L3_PAGETABLE -1))
+ (((_a) >> L3_PAGETABLE_SHIFT) & (ENTRIES_PER_L3_PAGETABLE - 1))
#define l4_table_offset(_a) \
- ((_a) >> L4_PAGETABLE_SHIFT)
+ (((_a) >> L4_PAGETABLE_SHIFT) & (ENTRIES_PER_L4_PAGETABLE - 1))
+#endif
+
+#if defined(__i386__)
+#define pagetable_t l2_pgentry_t
+#define pagetable_val(_x) ((_x).l2_lo)
+#define mk_pagetable(_x) ( (l2_pgentry_t) { (_x) } )
+#define ENTRIES_PER_PAGETABLE ENTRIES_PER_L2_PAGETABLE
+#elif defined(__x86_64__)
+#define pagetable_t l4_pgentry_t
+#define pagetable_val(_x) ((_x).l4_lo)
+#define mk_pagetable(_x) ( (l4_pgentry_t) { (_x) } )
+#define ENTRIES_PER_PAGETABLE ENTRIES_PER_L4_PAGETABLE
#endif
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
@@ -131,7 +144,8 @@ typedef struct { unsigned long pt_lo; } pagetable_t;
#define va_to_l1mfn(_va) (l2_pgentry_val(linear_l2_table[_va>>L2_PAGETABLE_SHIFT]) >> PAGE_SHIFT)
-extern l2_pgentry_t idle_pg_table[ENTRIES_PER_L2_PAGETABLE];
+extern pagetable_t idle_pg_table[ENTRIES_PER_PAGETABLE];
+
extern void paging_init(void);
/* Flush global pages as well. */
@@ -186,6 +200,7 @@ __asm__ __volatile__("invlpg %0": :"m" (*(char *) (__addr)))
#define PAGE_HYPERVISOR_NOCACHE MAKE_GLOBAL(__PAGE_HYPERVISOR_NOCACHE)
#ifndef __ASSEMBLY__
+
static __inline__ int get_order(unsigned long size)
{
int order;
@@ -200,6 +215,16 @@ static __inline__ int get_order(unsigned long size)
}
extern void zap_low_mappings(void);
-#endif
+
+/* Map physical byte range (@p, @p+@s) at virt address @v in pagetable @pt. */
+extern int
+map_pages(
+ pagetable_t *pt,
+ unsigned long v,
+ unsigned long p,
+ unsigned long s,
+ unsigned long flags);
+
+#endif /* !__ASSEMBLY__ */
#endif /* __I386_PAGE_H__ */
diff --git a/xen/include/asm-x86/pda.h b/xen/include/asm-x86/pda.h
deleted file mode 100644
index dcecc48f20..0000000000
--- a/xen/include/asm-x86/pda.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef X86_64_PDA_H
-#define X86_64_PDA_H
-
-#include <xen/cache.h>
-
-/* Per processor datastructure. %gs points to it while the kernel runs */
-/* To use a new field with the *_pda macros it needs to be added to tools/offset.c */
-struct x8664_pda {
- unsigned long kernelstack; /* TOS for current process */
- unsigned long oldrsp; /* user rsp for system call */
- unsigned long irqrsp; /* Old rsp for interrupts. */
- struct domain *pcurrent; /* Current process */
- int irqcount; /* Irq nesting counter. Starts with -1 */
- int cpunumber; /* Logical CPU number */
- char *irqstackptr; /* top of irqstack */
- unsigned long volatile *level4_pgt;
-} __cacheline_aligned;
-
-#define PDA_STACKOFFSET (5*8)
-
-#define IRQSTACK_ORDER 2
-#define IRQSTACKSIZE (PAGE_SIZE << IRQSTACK_ORDER)
-
-extern struct x8664_pda cpu_pda[];
-
-/*
- * There is no fast way to get the base address of the PDA, all the accesses
- * have to mention %fs/%gs. So it needs to be done this Torvaldian way.
- */
-#define sizeof_field(type,field) (sizeof(((type *)0)->field))
-#define typeof_field(type,field) typeof(((type *)0)->field)
-
-extern void __bad_pda_field(void);
-/* Don't use offsetof because it requires too much infrastructure */
-#define pda_offset(field) ((unsigned long)&((struct x8664_pda *)0)->field)
-
-#define pda_to_op(op,field,val) do { \
- switch (sizeof_field(struct x8664_pda, field)) { \
- case 2: asm volatile(op "w %0,%%gs:%P1" :: "r" (val), "i"(pda_offset(field)):"memory"); break; \
- case 4: asm volatile(op "l %0,%%gs:%P1" :: "r" (val), "i"(pda_offset(field)):"memory"); break; \
- case 8: asm volatile(op "q %0,%%gs:%P1" :: "r" (val), "i"(pda_offset(field)):"memory"); break; \
- default: __bad_pda_field(); \
- } \
- } while (0)
-
-
-#define pda_from_op(op,field) ({ \
- typedef typeof_field(struct x8664_pda, field) T__; T__ ret__; \
- switch (sizeof_field(struct x8664_pda, field)) { \
- case 2: asm volatile(op "w %%gs:%P1,%0":"=r" (ret__): "i" (pda_offset(field)):"memory"); break; \
- case 4: asm volatile(op "l %%gs:%P1,%0":"=r" (ret__): "i" (pda_offset(field)):"memory"); break; \
- case 8: asm volatile(op "q %%gs:%P1,%0":"=r" (ret__): "i" (pda_offset(field)):"memory"); break; \
- default: __bad_pda_field(); \
- } \
- ret__; })
-
-
-#define read_pda(field) pda_from_op("mov",field)
-#define write_pda(field,val) pda_to_op("mov",field,val)
-#define add_pda(field,val) pda_to_op("add",field,val)
-#define sub_pda(field,val) pda_to_op("sub",field,val)
-
-#endif
diff --git a/xen/include/asm-x86/pdb.h b/xen/include/asm-x86/pdb.h
deleted file mode 100644
index 79b0c4183b..0000000000
--- a/xen/include/asm-x86/pdb.h
+++ /dev/null
@@ -1,89 +0,0 @@
-
-/*
- * pervasive debugger
- * www.cl.cam.ac.uk/netos/pdb
- *
- * alex ho
- * 2004
- * university of cambridge computer laboratory
- */
-
-
-#ifndef __PDB_H__
-#define __PDB_H__
-
-#include <asm/regs.h>
-#include <xen/list.h>
-#include <public/dom0_ops.h>
-#include <public/xen.h> /* for domain id */
-
-extern int pdb_initialized;
-extern int pdb_com_port;
-extern int pdb_high_bit;
-extern int pdb_page_fault_possible;
-extern int pdb_page_fault_scratch;
-extern int pdb_page_fault;
-
-extern void initialize_pdb(void);
-
-/* Get/set values from generic debug interface. */
-extern int pdb_set_values(u_char *buffer, int length,
- unsigned long cr3, unsigned long addr);
-extern int pdb_get_values(u_char *buffer, int length,
- unsigned long cr3, unsigned long addr);
-
-/* External entry points. */
-extern int pdb_handle_exception(int exceptionVector,
- struct xen_regs *xen_regs);
-extern void pdb_do_debug(dom0_op_t *op);
-
-/* PDB Context. */
-struct pdb_context
-{
- int valid;
- int domain;
- int process;
- int system_call; /* 0x01 break on enter, 0x02 break on exit */
- unsigned long ptbr;
-};
-extern struct pdb_context pdb_ctx;
-
-/* Breakpoints. */
-struct pdb_breakpoint
-{
- struct list_head list;
- unsigned long address;
- unsigned long cr3;
- domid_t domain;
-};
-extern void pdb_bkpt_add (unsigned long cr3, unsigned long address);
-extern struct pdb_breakpoint* pdb_bkpt_search (unsigned long cr3,
- unsigned long address);
-extern int pdb_bkpt_remove (unsigned long cr3, unsigned long address);
-
-/* Conversions. */
-extern int hex (char);
-extern char *mem2hex (char *, char *, int);
-extern char *hex2mem (char *, char *, int);
-extern int hexToInt (char **ptr, int *intValue);
-
-/* Temporary Linux specific definitions */
-extern int pdb_system_call;
-extern unsigned char pdb_system_call_enter_instr; /* original enter instr */
-extern unsigned char pdb_system_call_leave_instr; /* original next instr */
-extern unsigned long pdb_system_call_next_addr; /* instr after int 0x80 */
-extern unsigned long pdb_system_call_eflags_addr; /* saved eflags on stack */
-
-unsigned long pdb_linux_pid_ptbr (unsigned long cr3, int pid);
-void pdb_linux_get_values(char *buffer, int length, unsigned long address,
- int pid, unsigned long cr3);
-void pdb_linux_set_values(char *buffer, int length, unsigned long address,
- int pid, unsigned long cr3);
-void pdb_linux_syscall_enter_bkpt (struct xen_regs *regs, long error_code,
- trap_info_t *ti);
-void pdb_linux_syscall_exit_bkpt (struct xen_regs *regs,
- struct pdb_context *pdb_ctx);
-
-void pdb_handle_debug_trap(struct xen_regs *regs, long error_code);
-
-#endif /* __PDB_H__ */
diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h
index e3446aaeae..abbb21e3cf 100644
--- a/xen/include/asm-x86/processor.h
+++ b/xen/include/asm-x86/processor.h
@@ -1,8 +1,6 @@
-/*
- * include/asm-x86/processor.h
- *
- * Copyright (C) 1994 Linus Torvalds
- */
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+
+/* Portions are: Copyright (c) 1994 Linus Torvalds */
#ifndef __ASM_X86_PROCESSOR_H
#define __ASM_X86_PROCESSOR_H
@@ -13,9 +11,10 @@
#include <asm/cpufeature.h>
#include <asm/desc.h>
#include <asm/flushtlb.h>
-#include <asm/pdb.h>
#include <xen/config.h>
#include <xen/spinlock.h>
+#include <xen/cache.h>
+#include <asm/vmx_vmcs.h>
#include <public/xen.h>
#endif
@@ -84,6 +83,7 @@
#define X86_CR4_PCE 0x0100 /* enable performance counters at ipl 3 */
#define X86_CR4_OSFXSR 0x0200 /* enable fast FPU save and restore */
#define X86_CR4_OSXMMEXCPT 0x0400 /* enable unmasked SSE exceptions */
+#define X86_CR4_VMXE 0x2000 /* enable VMX */
/*
* Trap/fault mnemonics.
@@ -136,6 +136,7 @@
#ifndef __ASSEMBLY__
struct domain;
+struct exec_domain;
/*
* Default implementation of macro that returns current
@@ -375,67 +376,13 @@ struct tss_struct {
u8 io_bitmap[IOBMP_BYTES+1];
/* Pads the TSS to be cacheline-aligned (total size is 0x2080). */
u8 __cacheline_filler[23];
-};
-
-struct trap_bounce {
- unsigned long error_code;
- unsigned long cr2;
- unsigned short flags; /* TBF_ */
- unsigned short cs;
- unsigned long eip;
-};
-
-struct thread_struct {
- unsigned long guestos_sp;
- unsigned long guestos_ss;
-
- unsigned long flags; /* TF_ */
-
- /* Hardware debugging registers */
- unsigned long debugreg[8]; /* %%db0-7 debug registers */
-
- /* floating point info */
- struct i387_state i387;
-
- /* general user-visible register state */
- execution_context_t user_ctxt;
-
- void (*schedule_tail) (struct domain *);
-
- /*
- * Return vectors pushed to us by guest OS.
- * The stack frame for events is exactly that of an x86 hardware interrupt.
- * The stack frame for a failsafe callback is augmented with saved values
- * for segment registers %ds, %es, %fs and %gs:
- * %ds, %es, %fs, %gs, %eip, %cs, %eflags [, %oldesp, %oldss]
- */
- unsigned long event_selector; /* 08: entry CS */
- unsigned long event_address; /* 12: entry EIP */
-
- unsigned long failsafe_selector; /* 16: entry CS */
- unsigned long failsafe_address; /* 20: entry EIP */
-
- /* Bounce information for propagating an exception to guest OS. */
- struct trap_bounce trap_bounce;
-
- /* I/O-port access bitmap. */
- u64 io_bitmap_sel; /* Selector to tell us which part of the IO bitmap are
- * "interesting" (i.e. have clear bits) */
- u8 *io_bitmap; /* Pointer to task's IO bitmap or NULL */
-
- /* Trap info. */
-#ifdef __i386__
- int fast_trap_idx;
- struct desc_struct fast_trap_desc;
-#endif
- trap_info_t traps[256];
-};
+} __cacheline_aligned PACKED;
#define IDT_ENTRIES 256
-extern struct desc_struct idt_table[];
-extern struct desc_struct *idt_tables[];
+extern idt_entry_t idt_table[];
+extern idt_entry_t *idt_tables[];
-#if defined(__i386__)
+#ifdef ARCH_HAS_FAST_TRAP
#define SET_DEFAULT_FAST_TRAP(_p) \
(_p)->fast_trap_idx = 0x20; \
@@ -446,92 +393,40 @@ extern struct desc_struct *idt_tables[];
(memset(idt_tables[smp_processor_id()] + (_p)->fast_trap_idx, \
0, 8))
-#ifdef XEN_DEBUGGER
-#define SET_FAST_TRAP(_p) \
- (pdb_initialized ? (void *) 0 : \
- (memcpy(idt_tables[smp_processor_id()] + (_p)->fast_trap_idx, \
- &((_p)->fast_trap_desc), 8)))
-#else
#define SET_FAST_TRAP(_p) \
(memcpy(idt_tables[smp_processor_id()] + (_p)->fast_trap_idx, \
&((_p)->fast_trap_desc), 8))
-#endif
-long set_fast_trap(struct domain *p, int idx);
+long set_fast_trap(struct exec_domain *p, int idx);
-#endif
-
-#define INIT_THREAD { 0 }
-
-extern int gpf_emulate_4gb(struct xen_regs *regs);
-
-struct mm_struct {
- /*
- * Every domain has a L1 pagetable of its own. Per-domain mappings
- * are put in this table (eg. the current GDT is mapped here).
- */
- l1_pgentry_t *perdomain_pt;
- pagetable_t pagetable;
-
- /* shadow mode status and controls */
- unsigned int shadow_mode; /* flags to control shadow table operation */
- pagetable_t shadow_table;
- spinlock_t shadow_lock;
- unsigned int shadow_max_page_count; // currently unused
-
- /* shadow hashtable */
- struct shadow_status *shadow_ht;
- struct shadow_status *shadow_ht_free;
- struct shadow_status *shadow_ht_extras; /* extra allocation units */
- unsigned int shadow_extras_count;
-
- /* shadow dirty bitmap */
- unsigned long *shadow_dirty_bitmap;
- unsigned int shadow_dirty_bitmap_size; /* in pages, bit per page */
-
- /* shadow mode stats */
- unsigned int shadow_page_count;
- unsigned int shadow_fault_count;
- unsigned int shadow_dirty_count;
- unsigned int shadow_dirty_net_count;
- unsigned int shadow_dirty_block_count;
-
- /* Current LDT details. */
- unsigned long ldt_base, ldt_ents, shadow_ldt_mapcnt;
- /* Next entry is passed to LGDT on domain switch. */
- char gdt[10]; /* NB. 10 bytes needed for x86_64. Use 6 bytes for x86_32. */
-};
+#else
-static inline void write_ptbase(struct mm_struct *mm)
-{
- unsigned long pa;
+#define SET_DEFAULT_FAST_TRAP(_p) ((void)0)
+#define CLEAR_FAST_TRAP(_p) ((void)0)
+#define SET_FAST_TRAP(_p) ((void)0)
+#define set_fast_trap(_p, _i) (0)
- if ( unlikely(mm->shadow_mode) )
- pa = pagetable_val(mm->shadow_table);
- else
- pa = pagetable_val(mm->pagetable);
+#endif
- write_cr3(pa);
-}
+extern int gpf_emulate_4gb(struct xen_regs *regs);
-#define IDLE0_MM \
-{ \
- perdomain_pt: 0, \
- pagetable: mk_pagetable(__pa(idle_pg_table)) \
-}
+extern void write_ptbase(struct exec_domain *ed);
-/* Convenient accessor for mm.gdt. */
-#define SET_GDT_ENTRIES(_p, _e) ((*(u16 *)((_p)->mm.gdt + 0)) = (((_e)<<3)-1))
-#define SET_GDT_ADDRESS(_p, _a) ((*(unsigned long *)((_p)->mm.gdt + 2)) = (_a))
-#define GET_GDT_ENTRIES(_p) (((*(u16 *)((_p)->mm.gdt + 0))+1)>>3)
-#define GET_GDT_ADDRESS(_p) (*(unsigned long *)((_p)->mm.gdt + 2))
+#define SET_GDT_ENTRIES(_p, _e) \
+ ((*(u16 *)((_p)->arch.gdt + 0)) = (((_e)<<3)-1))
+#define SET_GDT_ADDRESS(_p, _a) \
+ ((*(unsigned long *)((_p)->arch.gdt + 2)) = (_a))
+#define GET_GDT_ENTRIES(_p) \
+ (((*(u16 *)((_p)->arch.gdt + 0))+1)>>3)
+#define GET_GDT_ADDRESS(_p) \
+ (*(unsigned long *)((_p)->arch.gdt + 2))
-void destroy_gdt(struct domain *d);
-long set_gdt(struct domain *d,
+void destroy_gdt(struct exec_domain *d);
+long set_gdt(struct exec_domain *d,
unsigned long *frames,
unsigned int entries);
-long set_debugreg(struct domain *p, int reg, unsigned long value);
+long set_debugreg(struct exec_domain *p, int reg, unsigned long value);
struct microcode_header {
unsigned int hdrver;
@@ -608,6 +503,7 @@ void show_guest_stack();
void show_trace(unsigned long *esp);
void show_stack(unsigned long *esp);
void show_registers(struct xen_regs *regs);
+void show_page_walk(unsigned long addr);
asmlinkage void fatal_trap(int trapnr, struct xen_regs *regs);
#endif /* !__ASSEMBLY__ */
diff --git a/xen/include/asm-x86/regs.h b/xen/include/asm-x86/regs.h
index 1f4ccdddf7..3a9f5edb02 100644
--- a/xen/include/asm-x86/regs.h
+++ b/xen/include/asm-x86/regs.h
@@ -1,6 +1,36 @@
+#ifndef __X86_REGS_H__
+#define __X86_REGS_H__
+
#ifdef __x86_64__
#include <asm/x86_64/regs.h>
#else
#include <asm/x86_32/regs.h>
#endif
+
+enum EFLAGS {
+ EF_CF = 0x00000001,
+ EF_PF = 0x00000004,
+ EF_AF = 0x00000010,
+ EF_ZF = 0x00000040,
+ EF_SF = 0x00000080,
+ EF_TF = 0x00000100,
+ EF_IE = 0x00000200,
+ EF_DF = 0x00000400,
+ EF_OF = 0x00000800,
+ EF_IOPL = 0x00003000,
+ EF_IOPL_RING0 = 0x00000000,
+ EF_IOPL_RING1 = 0x00001000,
+ EF_IOPL_RING2 = 0x00002000,
+ EF_NT = 0x00004000, /* nested task */
+ EF_RF = 0x00010000, /* resume */
+ EF_VM = 0x00020000, /* virtual mode */
+ EF_AC = 0x00040000, /* alignment */
+ EF_VIF = 0x00080000, /* virtual interrupt */
+ EF_VIP = 0x00100000, /* virtual interrupt pending */
+ EF_ID = 0x00200000, /* id */
+};
+
+#define GUEST_FAULT(_r) (likely(VM86_MODE(_r) || !RING_0(_r)))
+
+#endif /* __X86_REGS_H__ */
diff --git a/xen/include/asm-x86/shadow.h b/xen/include/asm-x86/shadow.h
index 33172926ef..c95a4de693 100644
--- a/xen/include/asm-x86/shadow.h
+++ b/xen/include/asm-x86/shadow.h
@@ -1,4 +1,4 @@
-/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*- */
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
#ifndef _XEN_SHADOW_H
#define _XEN_SHADOW_H
@@ -12,20 +12,21 @@
#define PSH_shadowed (1<<31) /* page has a shadow. PFN points to shadow */
#define PSH_pfn_mask ((1<<21)-1)
-/* Shadow PT operation mode : shadowmode variable in mm_struct */
+/* Shadow PT operation mode : shadow-mode variable in arch_domain. */
#define SHM_test (1) /* just run domain on shadow PTs */
#define SHM_logdirty (2) /* log pages that are dirtied */
#define SHM_translate (3) /* lookup machine pages in translation table */
#define SHM_cow (4) /* copy on write all dirtied pages */
+#define SHM_full_32 (8) /* full virtualization for 32-bit */
#define shadow_linear_pg_table ((l1_pgentry_t *)SH_LINEAR_PT_VIRT_START)
#define shadow_linear_l2_table ((l2_pgentry_t *)(SH_LINEAR_PT_VIRT_START + \
(SH_LINEAR_PT_VIRT_START >> (L2_PAGETABLE_SHIFT - L1_PAGETABLE_SHIFT))))
-#define shadow_mode(_d) ((_d)->mm.shadow_mode)
-#define shadow_lock_init(_d) spin_lock_init(&(_d)->mm.shadow_lock)
-#define shadow_lock(_m) spin_lock(&(_m)->shadow_lock)
-#define shadow_unlock(_m) spin_unlock(&(_m)->shadow_lock)
+#define shadow_mode(_d) ((_d)->arch.shadow_mode)
+#define shadow_lock_init(_d) spin_lock_init(&(_d)->arch.shadow_lock)
+#define shadow_lock(_d) spin_lock(&(_d)->arch.shadow_lock)
+#define shadow_unlock(_d) spin_unlock(&(_d)->arch.shadow_lock)
extern void shadow_mode_init(void);
extern int shadow_mode_control(struct domain *p, dom0_shadow_control_t *sc);
@@ -37,6 +38,23 @@ extern void shadow_l2_normal_pt_update(unsigned long pa, unsigned long gpte);
extern void unshadow_table(unsigned long gpfn, unsigned int type);
extern int shadow_mode_enable(struct domain *p, unsigned int mode);
+#ifdef CONFIG_VMX
+extern void vmx_shadow_clear_state(struct domain *);
+extern void vmx_shadow_invlpg(struct domain *, unsigned long);
+#endif
+
+#define __get_machine_to_phys(_d, guest_gpfn, gpfn) \
+ if ((_d)->arch.shadow_mode == SHM_full_32) \
+ (guest_gpfn) = machine_to_phys_mapping[(gpfn)]; \
+ else \
+ (guest_gpfn) = (gpfn);
+
+#define __get_phys_to_machine(_d, host_gpfn, gpfn) \
+ if ((_d)->arch.shadow_mode == SHM_full_32) \
+ (host_gpfn) = phys_to_machine_mapping[(gpfn)]; \
+ else \
+ (host_gpfn) = (gpfn);
+
extern void __shadow_mode_disable(struct domain *d);
static inline void shadow_mode_disable(struct domain *d)
{
@@ -45,10 +63,16 @@ static inline void shadow_mode_disable(struct domain *d)
}
extern unsigned long shadow_l2_table(
- struct mm_struct *m, unsigned long gpfn);
+ struct domain *d, unsigned long gpfn);
+
+static inline void shadow_invalidate(struct exec_domain *ed) {
+ if ( ed->domain->arch.shadow_mode != SHM_full_32 )
+ BUG();
+ memset(ed->arch.shadow_vtable, 0, PAGE_SIZE);
+}
-#define SHADOW_DEBUG 0
-#define SHADOW_HASH_DEBUG 0
+#define SHADOW_DEBUG 1
+#define SHADOW_HASH_DEBUG 1
struct shadow_status {
unsigned long pfn; /* Guest pfn. */
@@ -62,7 +86,7 @@ struct shadow_status {
#ifdef VERBOSE
#define SH_LOG(_f, _a...) \
printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \
- current->id , __LINE__ , ## _a )
+ current->domain->id , __LINE__ , ## _a )
#else
#define SH_LOG(_f, _a...)
#endif
@@ -70,7 +94,7 @@ printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \
#if SHADOW_DEBUG
#define SH_VLOG(_f, _a...) \
printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \
- current->id , __LINE__ , ## _a )
+ current->domain->id , __LINE__ , ## _a )
#else
#define SH_VLOG(_f, _a...)
#endif
@@ -78,21 +102,64 @@ printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \
#if 0
#define SH_VVLOG(_f, _a...) \
printk("DOM%u: (file=shadow.c, line=%d) " _f "\n", \
- current->id , __LINE__ , ## _a )
+ current->domain->id , __LINE__ , ## _a )
#else
-#define SH_VVLOG(_f, _a...)
+#define SH_VVLOG(_f, _a...)
#endif
+static inline void __shadow_get_pl2e(
+ struct exec_domain *ed, unsigned long va, unsigned long *sl2e)
+{
+ *sl2e = (ed->domain->arch.shadow_mode == SHM_full_32) ?
+ l2_pgentry_val(ed->arch.shadow_vtable[l2_table_offset(va)]) :
+ l2_pgentry_val(linear_l2_table[l2_table_offset(va)]);
+}
+
+static inline void __shadow_set_pl2e(
+ struct exec_domain *ed, unsigned long va, unsigned long value)
+{
+ if ( ed->domain->arch.shadow_mode == SHM_full_32 )
+ ed->arch.shadow_vtable[l2_table_offset(va)] = mk_l2_pgentry(value);
+ else
+ linear_l2_table[l2_table_offset(va)] = mk_l2_pgentry(value);
+}
+
+static inline void __guest_get_pl2e(
+ struct exec_domain *ed, unsigned long va, unsigned long *l2e)
+{
+ *l2e = (ed->domain->arch.shadow_mode == SHM_full_32) ?
+ l2_pgentry_val(ed->arch.vpagetable[l2_table_offset(va)]) :
+ l2_pgentry_val(linear_l2_table[l2_table_offset(va)]);
+}
+
+static inline void __guest_set_pl2e(
+ struct exec_domain *ed, unsigned long va, unsigned long value)
+{
+ if ( ed->domain->arch.shadow_mode == SHM_full_32 )
+ {
+ unsigned long pfn;
+
+ pfn = phys_to_machine_mapping[value >> PAGE_SHIFT];
+ ed->arch.guest_pl2e_cache[l2_table_offset(va)] =
+ mk_l2_pgentry((pfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
+
+ ed->arch.vpagetable[l2_table_offset(va)] = mk_l2_pgentry(value);
+ }
+ else
+ {
+ linear_l2_table[l2_table_offset(va)] = mk_l2_pgentry(value);
+ }
+}
/************************************************************************/
-static inline int __mark_dirty( struct mm_struct *m, unsigned int mfn)
+static inline int __mark_dirty(struct domain *d, unsigned int mfn)
{
unsigned long pfn;
int rc = 0;
- ASSERT(spin_is_locked(&m->shadow_lock));
- ASSERT(m->shadow_dirty_bitmap != NULL);
+ ASSERT(spin_is_locked(&d->arch.shadow_lock));
+ ASSERT(d->arch.shadow_dirty_bitmap != NULL);
pfn = machine_to_phys_mapping[mfn];
@@ -104,27 +171,24 @@ static inline int __mark_dirty( struct mm_struct *m, unsigned int mfn)
if ( unlikely(pfn & 0x80000000UL) )
return rc;
- if ( likely(pfn < m->shadow_dirty_bitmap_size) )
+ if ( likely(pfn < d->arch.shadow_dirty_bitmap_size) )
{
/* N.B. Can use non-atomic TAS because protected by shadow_lock. */
- if ( !__test_and_set_bit(pfn, m->shadow_dirty_bitmap) )
+ if ( !__test_and_set_bit(pfn, d->arch.shadow_dirty_bitmap) )
{
- m->shadow_dirty_count++;
+ d->arch.shadow_dirty_count++;
rc = 1;
}
}
#ifndef NDEBUG
else if ( mfn < max_page )
{
- unsigned long *esp;
- SH_LOG("mark_dirty OOR! mfn=%x pfn=%lx max=%x (mm %p)",
- mfn, pfn, m->shadow_dirty_bitmap_size, m );
+ SH_LOG("mark_dirty OOR! mfn=%x pfn=%lx max=%x (dom %p)",
+ mfn, pfn, d->arch.shadow_dirty_bitmap_size, d);
SH_LOG("dom=%p caf=%08x taf=%08x\n",
- frame_table[mfn].u.inuse.domain,
+ page_get_owner(&frame_table[mfn]),
frame_table[mfn].count_info,
frame_table[mfn].u.inuse.type_info );
- __asm__ __volatile__ ("movl %%esp,%0" : "=r" (esp) : );
- show_trace(esp);
}
#endif
@@ -132,12 +196,12 @@ static inline int __mark_dirty( struct mm_struct *m, unsigned int mfn)
}
-static inline int mark_dirty(struct mm_struct *m, unsigned int mfn)
+static inline int mark_dirty(struct domain *d, unsigned int mfn)
{
int rc;
- shadow_lock(m);
- rc = __mark_dirty(m, mfn);
- shadow_unlock(m);
+ shadow_lock(d);
+ rc = __mark_dirty(d, mfn);
+ shadow_unlock(d);
return rc;
}
@@ -145,16 +209,15 @@ static inline int mark_dirty(struct mm_struct *m, unsigned int mfn)
/************************************************************************/
static inline void l1pte_write_fault(
- struct mm_struct *m, unsigned long *gpte_p, unsigned long *spte_p)
+ struct domain *d, unsigned long *gpte_p, unsigned long *spte_p)
{
unsigned long gpte = *gpte_p;
unsigned long spte = *spte_p;
ASSERT(gpte & _PAGE_RW);
-
gpte |= _PAGE_DIRTY | _PAGE_ACCESSED;
- switch ( m->shadow_mode )
+ switch ( d->arch.shadow_mode )
{
case SHM_test:
spte = gpte | _PAGE_RW;
@@ -162,23 +225,33 @@ static inline void l1pte_write_fault(
case SHM_logdirty:
spte = gpte | _PAGE_RW;
- __mark_dirty(m, gpte >> PAGE_SHIFT);
+ __mark_dirty(d, gpte >> PAGE_SHIFT);
+
+ case SHM_full_32:
+ {
+ unsigned long host_pfn, host_gpte;
+
+ host_pfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT];
+ host_gpte = (host_pfn << PAGE_SHIFT) | (gpte & ~PAGE_MASK);
+ spte = host_gpte | _PAGE_RW;
+ }
break;
}
+ SH_VVLOG("updating spte=%lx gpte=%lx", spte, gpte);
*gpte_p = gpte;
*spte_p = spte;
}
static inline void l1pte_read_fault(
- struct mm_struct *m, unsigned long *gpte_p, unsigned long *spte_p)
+ struct domain *d, unsigned long *gpte_p, unsigned long *spte_p)
{
unsigned long gpte = *gpte_p;
unsigned long spte = *spte_p;
gpte |= _PAGE_ACCESSED;
- switch ( m->shadow_mode )
+ switch ( d->arch.shadow_mode )
{
case SHM_test:
spte = (gpte & _PAGE_DIRTY) ? gpte : (gpte & ~_PAGE_RW);
@@ -187,6 +260,17 @@ static inline void l1pte_read_fault(
case SHM_logdirty:
spte = gpte & ~_PAGE_RW;
break;
+
+ case SHM_full_32:
+ {
+ unsigned long host_pfn, host_gpte;
+
+ host_pfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT];
+ host_gpte = (host_pfn << PAGE_SHIFT) | (gpte & ~PAGE_MASK);
+ spte = (host_gpte & _PAGE_DIRTY) ? host_gpte : (host_gpte & ~_PAGE_RW);
+ }
+ break;
+
}
*gpte_p = gpte;
@@ -194,12 +278,13 @@ static inline void l1pte_read_fault(
}
static inline void l1pte_propagate_from_guest(
- struct mm_struct *m, unsigned long *gpte_p, unsigned long *spte_p)
+ struct domain *d, unsigned long *gpte_p, unsigned long *spte_p)
{
unsigned long gpte = *gpte_p;
unsigned long spte = *spte_p;
+ unsigned long host_pfn, host_gpte;
- switch ( m->shadow_mode )
+ switch ( d->arch.shadow_mode )
{
case SHM_test:
spte = 0;
@@ -214,6 +299,25 @@ static inline void l1pte_propagate_from_guest(
(_PAGE_PRESENT|_PAGE_ACCESSED) )
spte = gpte & ~_PAGE_RW;
break;
+
+ case SHM_full_32:
+ spte = 0;
+
+ if ( mmio_space(gpte & 0xFFFFF000) )
+ {
+ *spte_p = spte;
+ return;
+ }
+
+ host_pfn = phys_to_machine_mapping[gpte >> PAGE_SHIFT];
+ host_gpte = (host_pfn << PAGE_SHIFT) | (gpte & ~PAGE_MASK);
+
+ if ( (host_gpte & (_PAGE_PRESENT|_PAGE_ACCESSED) ) ==
+ (_PAGE_PRESENT|_PAGE_ACCESSED) )
+ spte = (host_gpte & _PAGE_DIRTY) ?
+ host_gpte : (host_gpte & ~_PAGE_RW);
+
+ break;
}
*gpte_p = gpte;
@@ -221,7 +325,7 @@ static inline void l1pte_propagate_from_guest(
}
static inline void l2pde_general(
- struct mm_struct *m,
+ struct domain *d,
unsigned long *gpde_p,
unsigned long *spde_p,
unsigned long sl1pfn)
@@ -239,8 +343,12 @@ static inline void l2pde_general(
/* Detect linear p.t. mappings and write-protect them. */
if ( (frame_table[sl1pfn].u.inuse.type_info & PGT_type_mask) ==
- PGT_l2_page_table )
- spde = gpde & ~_PAGE_RW;
+ PGT_l2_page_table )
+ {
+ if ( d->arch.shadow_mode != SHM_full_32 )
+ spde = gpde & ~_PAGE_RW;
+
+ }
}
*gpde_p = gpde;
@@ -250,14 +358,14 @@ static inline void l2pde_general(
/*********************************************************************/
#if SHADOW_HASH_DEBUG
-static void shadow_audit(struct mm_struct *m, int print)
+static void shadow_audit(struct domain *d, int print)
{
int live = 0, free = 0, j = 0, abs;
struct shadow_status *a;
for ( j = 0; j < shadow_ht_buckets; j++ )
{
- a = &m->shadow_ht[j];
+ a = &d->arch.shadow_ht[j];
if ( a->pfn ) { live++; ASSERT(a->spfn_and_flags & PSH_pfn_mask); }
ASSERT(a->pfn < 0x00100000UL);
a = a->next;
@@ -277,7 +385,7 @@ static void shadow_audit(struct mm_struct *m, int print)
ASSERT(live < 9999);
}
- for ( a = m->shadow_ht_free; a != NULL; a = a->next )
+ for ( a = d->arch.shadow_ht_free; a != NULL; a = a->next )
free++;
if ( print)
@@ -296,24 +404,23 @@ static void shadow_audit(struct mm_struct *m, int print)
#endif
-
static inline struct shadow_status *hash_bucket(
- struct mm_struct *m, unsigned int gpfn)
+ struct domain *d, unsigned int gpfn)
{
- return &m->shadow_ht[gpfn % shadow_ht_buckets];
+ return &d->arch.shadow_ht[gpfn % shadow_ht_buckets];
}
static inline unsigned long __shadow_status(
- struct mm_struct *m, unsigned int gpfn)
+ struct domain *d, unsigned int gpfn)
{
struct shadow_status *p, *x, *head;
- x = head = hash_bucket(m, gpfn);
+ x = head = hash_bucket(d, gpfn);
p = NULL;
SH_VVLOG("lookup gpfn=%08x bucket=%p", gpfn, x);
- shadow_audit(m, 0);
+ shadow_audit(d, 0);
do
{
@@ -351,11 +458,11 @@ static inline unsigned long __shadow_status(
* anyway it's probably not worth being too clever.
*/
static inline unsigned long get_shadow_status(
- struct mm_struct *m, unsigned int gpfn )
+ struct domain *d, unsigned int gpfn )
{
unsigned long res;
- ASSERT(m->shadow_mode);
+ ASSERT(d->arch.shadow_mode);
/*
* If we get here we know that some sort of update has happened to the
@@ -365,37 +472,37 @@ static inline unsigned long get_shadow_status(
* N.B. The VA update path doesn't use this and is handled independently.
*/
- shadow_lock(m);
+ shadow_lock(d);
- if ( m->shadow_mode == SHM_logdirty )
- __mark_dirty( m, gpfn );
+ if ( d->arch.shadow_mode == SHM_logdirty )
+ __mark_dirty(d, gpfn);
- if ( !(res = __shadow_status(m, gpfn)) )
- shadow_unlock(m);
+ if ( !(res = __shadow_status(d, gpfn)) )
+ shadow_unlock(d);
return res;
}
static inline void put_shadow_status(
- struct mm_struct *m)
+ struct domain *d)
{
- shadow_unlock(m);
+ shadow_unlock(d);
}
static inline void delete_shadow_status(
- struct mm_struct *m, unsigned int gpfn)
+ struct domain *d, unsigned int gpfn)
{
struct shadow_status *p, *x, *n, *head;
- ASSERT(spin_is_locked(&m->shadow_lock));
+ ASSERT(spin_is_locked(&d->arch.shadow_lock));
ASSERT(gpfn != 0);
- head = hash_bucket(m, gpfn);
+ head = hash_bucket(d, gpfn);
- SH_VVLOG("delete gpfn=%08x bucket=%p", gpfn, b);
- shadow_audit(m, 0);
+ SH_VVLOG("delete gpfn=%08x bucket=%p", gpfn, head);
+ shadow_audit(d, 0);
/* Match on head item? */
if ( head->pfn == gpfn )
@@ -412,8 +519,8 @@ static inline void delete_shadow_status(
/* Add deleted node to the free list. */
n->pfn = 0;
n->spfn_and_flags = 0;
- n->next = m->shadow_ht_free;
- m->shadow_ht_free = n;
+ n->next = d->arch.shadow_ht_free;
+ d->arch.shadow_ht_free = n;
}
else
{
@@ -438,8 +545,8 @@ static inline void delete_shadow_status(
/* Add deleted node to the free list. */
x->pfn = 0;
x->spfn_and_flags = 0;
- x->next = m->shadow_ht_free;
- m->shadow_ht_free = x;
+ x->next = d->arch.shadow_ht_free;
+ d->arch.shadow_ht_free = x;
goto found;
}
@@ -453,24 +560,24 @@ static inline void delete_shadow_status(
BUG();
found:
- shadow_audit(m, 0);
+ shadow_audit(d, 0);
}
static inline void set_shadow_status(
- struct mm_struct *m, unsigned int gpfn, unsigned long s)
+ struct domain *d, unsigned int gpfn, unsigned long s)
{
struct shadow_status *x, *head, *extra;
int i;
- ASSERT(spin_is_locked(&m->shadow_lock));
+ ASSERT(spin_is_locked(&d->arch.shadow_lock));
ASSERT(gpfn != 0);
ASSERT(s & PSH_shadowed);
- x = head = hash_bucket(m, gpfn);
+ x = head = hash_bucket(d, gpfn);
- SH_VVLOG("set gpfn=%08x s=%08lx bucket=%p(%p)", gpfn, s, b, b->next);
- shadow_audit(m, 0);
+ SH_VVLOG("set gpfn=%08x s=%08lx bucket=%p(%p)", gpfn, s, x, x->next);
+ shadow_audit(d, 0);
/*
* STEP 1. If page is already in the table, update it in place.
@@ -502,11 +609,11 @@ static inline void set_shadow_status(
}
/* We need to allocate a new node. Ensure the quicklist is non-empty. */
- if ( unlikely(m->shadow_ht_free == NULL) )
+ if ( unlikely(d->arch.shadow_ht_free == NULL) )
{
SH_LOG("Allocate more shadow hashtable blocks.");
- extra = xmalloc(
+ extra = xmalloc_bytes(
sizeof(void *) + (shadow_ht_extra_size * sizeof(*x)));
/* XXX Should be more graceful here. */
@@ -516,10 +623,10 @@ static inline void set_shadow_status(
memset(extra, 0, sizeof(void *) + (shadow_ht_extra_size * sizeof(*x)));
/* Record the allocation block so it can be correctly freed later. */
- m->shadow_extras_count++;
+ d->arch.shadow_extras_count++;
*((struct shadow_status **)&extra[shadow_ht_extra_size]) =
- m->shadow_ht_extras;
- m->shadow_ht_extras = &extra[0];
+ d->arch.shadow_ht_extras;
+ d->arch.shadow_ht_extras = &extra[0];
/* Thread a free chain through the newly-allocated nodes. */
for ( i = 0; i < (shadow_ht_extra_size - 1); i++ )
@@ -527,12 +634,12 @@ static inline void set_shadow_status(
extra[i].next = NULL;
/* Add the new nodes to the free list. */
- m->shadow_ht_free = &extra[0];
+ d->arch.shadow_ht_free = &extra[0];
}
/* Allocate a new node from the quicklist. */
- x = m->shadow_ht_free;
- m->shadow_ht_free = x->next;
+ x = d->arch.shadow_ht_free;
+ d->arch.shadow_ht_free = x->next;
/* Initialise the new node and insert directly after the head item. */
x->pfn = gpfn;
@@ -541,41 +648,111 @@ static inline void set_shadow_status(
head->next = x;
done:
- shadow_audit(m, 0);
+ shadow_audit(d, 0);
}
+
+#ifdef CONFIG_VMX
+#include <asm/domain_page.h>
-static inline void __shadow_mk_pagetable(struct mm_struct *mm)
+static inline void vmx_update_shadow_state(
+ struct exec_domain *ed, unsigned long gpfn, unsigned long spfn)
{
- unsigned long gpfn = pagetable_val(mm->pagetable) >> PAGE_SHIFT;
- unsigned long spfn = __shadow_status(mm, gpfn);
- if ( unlikely(spfn == 0) )
- spfn = shadow_l2_table(mm, gpfn);
+ l2_pgentry_t *mpl2e = 0;
+ l2_pgentry_t *gpl2e, *spl2e;
- mm->shadow_table = mk_pagetable(spfn << PAGE_SHIFT);
+ /* unmap the old mappings */
+ if ( ed->arch.shadow_vtable )
+ unmap_domain_mem(ed->arch.shadow_vtable);
+ if ( ed->arch.vpagetable )
+ unmap_domain_mem(ed->arch.vpagetable);
+
+ /* new mapping */
+ mpl2e = (l2_pgentry_t *)
+ map_domain_mem(pagetable_val(ed->arch.monitor_table));
+
+ mpl2e[l2_table_offset(SH_LINEAR_PT_VIRT_START)] =
+ mk_l2_pgentry((spfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
+ __flush_tlb_one(SH_LINEAR_PT_VIRT_START);
+
+ spl2e = (l2_pgentry_t *)map_domain_mem(spfn << PAGE_SHIFT);
+ gpl2e = (l2_pgentry_t *)map_domain_mem(gpfn << PAGE_SHIFT);
+ memset(spl2e, 0, ENTRIES_PER_L2_PAGETABLE * sizeof(l2_pgentry_t));
+
+ ed->arch.shadow_table = mk_pagetable(spfn<<PAGE_SHIFT);
+ ed->arch.shadow_vtable = spl2e;
+ ed->arch.vpagetable = gpl2e; /* expect the guest did clean this up */
+ unmap_domain_mem(mpl2e);
}
-static inline void shadow_mk_pagetable(struct mm_struct *mm)
+static inline void __shadow_mk_pagetable(struct exec_domain *ed)
{
- SH_VVLOG("shadow_mk_pagetable( gptbase=%08lx, mode=%d )",
- pagetable_val(mm->pagetable), mm->shadow_mode );
+ struct domain *d = ed->domain;
+ unsigned long gpfn = pagetable_val(ed->arch.pagetable) >> PAGE_SHIFT;
+ unsigned long spfn;
+ SH_VLOG("0: __shadow_mk_pagetable(gpfn=%08lx\n", gpfn);
- if ( unlikely(mm->shadow_mode) )
+ if (d->arch.shadow_mode == SHM_full_32)
{
- shadow_lock(mm);
- __shadow_mk_pagetable(mm);
- shadow_unlock(mm);
+ unsigned long guest_gpfn;
+ guest_gpfn = machine_to_phys_mapping[gpfn];
+
+ SH_VVLOG("__shadow_mk_pagetable(guest_gpfn=%08lx, gpfn=%08lx\n",
+ guest_gpfn, gpfn);
+
+ spfn = __shadow_status(d, guest_gpfn) & PSH_pfn_mask;
+ if ( unlikely(spfn == 0) ) {
+ spfn = shadow_l2_table(d, gpfn);
+ ed->arch.shadow_table = mk_pagetable(spfn<<PAGE_SHIFT);
+ } else {
+ vmx_update_shadow_state(ed, gpfn, spfn);
+ }
+ } else {
+ spfn = __shadow_status(d, gpfn) & PSH_pfn_mask;
+
+ if ( unlikely(spfn == 0) ) {
+ spfn = shadow_l2_table(d, gpfn);
+ }
+ ed->arch.shadow_table = mk_pagetable(spfn<<PAGE_SHIFT);
}
+}
+#else
+static inline void __shadow_mk_pagetable(struct exec_domain *ed)
+{
+ unsigned long gpfn = pagetable_val(ed->arch.pagetable) >> PAGE_SHIFT;
+ unsigned long spfn = __shadow_status(ed->domain, gpfn);
+
+ if ( unlikely(spfn == 0) )
+ spfn = shadow_l2_table(ed->domain, gpfn);
- SH_VVLOG("leaving shadow_mk_pagetable( gptbase=%08lx, mode=%d ) sh=%08lx",
- pagetable_val(mm->pagetable), mm->shadow_mode,
- pagetable_val(mm->shadow_table) );
+ ed->arch.shadow_table = mk_pagetable(spfn << PAGE_SHIFT);
+}
+#endif /* CONFIG_VMX */
+
+static inline void shadow_mk_pagetable(struct exec_domain *ed)
+{
+ if ( unlikely(ed->domain->arch.shadow_mode) )
+ {
+ SH_VVLOG("shadow_mk_pagetable( gptbase=%08lx, mode=%d )",
+ pagetable_val(ed->arch.pagetable),
+ ed->domain->arch.shadow_mode);
+
+ shadow_lock(ed->domain);
+ __shadow_mk_pagetable(ed);
+ shadow_unlock(ed->domain);
+
+ SH_VVLOG("leaving shadow_mk_pagetable:\n"
+ "( gptbase=%08lx, mode=%d ) sh=%08lx",
+ pagetable_val(ed->arch.pagetable),
+ ed->domain->arch.shadow_mode,
+ pagetable_val(ed->arch.shadow_table) );
+ }
}
#if SHADOW_DEBUG
-extern int check_pagetable(struct mm_struct *m, pagetable_t pt, char *s);
+extern int check_pagetable(struct domain *d, pagetable_t pt, char *s);
#else
-#define check_pagetable(m, pt, s) ((void)0)
+#define check_pagetable(d, pt, s) ((void)0)
#endif
#endif /* XEN_SHADOW_H */
diff --git a/xen/include/asm-x86/smp.h b/xen/include/asm-x86/smp.h
index b4d79087c5..e1e9443035 100644
--- a/xen/include/asm-x86/smp.h
+++ b/xen/include/asm-x86/smp.h
@@ -61,12 +61,7 @@ extern void smp_store_cpu_info(int id); /* Store per CPU info (like the initial
* so this is correct in the x86 case.
*/
-#if defined(__i386__)
#define smp_processor_id() (current->processor)
-#elif defined(__x86_64__)
-#include <asm/pda.h>
-#define smp_processor_id() read_pda(cpunumber)
-#endif
static __inline int hard_smp_processor_id(void)
{
diff --git a/xen/include/asm-x86/time.h b/xen/include/asm-x86/time.h
new file mode 100644
index 0000000000..2256145bec
--- /dev/null
+++ b/xen/include/asm-x86/time.h
@@ -0,0 +1,7 @@
+
+#ifndef __X86_TIME_H__
+#define __X86_TIME_H__
+
+/* nothing */
+
+#endif /* __X86_TIME_H__ */
diff --git a/xen/include/asm-x86/vmx.h b/xen/include/asm-x86/vmx.h
new file mode 100644
index 0000000000..b59f8d3216
--- /dev/null
+++ b/xen/include/asm-x86/vmx.h
@@ -0,0 +1,251 @@
+/*
+ * vmx.h: VMX Architecture related definitions
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, 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 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.
+ *
+ */
+#ifndef __ASM_X86_VMX_H__
+#define __ASM_X86_VMX_H__
+
+#include <xen/sched.h>
+#include <asm/types.h>
+#include <asm/regs.h>
+#include <asm/processor.h>
+#include <asm/vmx_vmcs.h>
+
+extern void vmx_asm_vmexit_handler(struct xen_regs);
+extern void vmx_asm_do_resume(void);
+extern void vmx_asm_do_launch(void);
+extern void vmx_intr_assist(struct exec_domain *d);
+
+extern void arch_vmx_do_launch(struct exec_domain *);
+extern void arch_vmx_do_resume(struct exec_domain *);
+
+extern int vmcs_size;
+extern unsigned int cpu_rev;
+
+/*
+ * Need fill bits for SENTER
+ */
+
+#define MONITOR_PIN_BASED_EXEC_CONTROLS 0x0000001f
+#define MONITOR_CPU_BASED_EXEC_CONTROLS 0x0581e7f2
+#define MONITOR_VM_EXIT_CONTROLS 0x0003edff
+#define MONITOR_VM_ENTRY_CONTROLS 0x000011ff
+
+/*
+ * Exit Reasons
+ */
+#define VMX_EXIT_REASONS_FAILED_VMENTRY 0x80000000
+
+#define EXIT_REASON_EXCEPTION_NMI 0
+#define EXIT_REASON_EXTERNAL_INTERRUPT 1
+
+#define EXIT_REASON_PENDING_INTERRUPT 7
+
+#define EXIT_REASON_TASK_SWITCH 9
+#define EXIT_REASON_CPUID 10
+#define EXIT_REASON_HLT 12
+#define EXIT_REASON_INVLPG 14
+#define EXIT_REASON_RDPMC 15
+#define EXIT_REASON_RDTSC 16
+#define EXIT_REASON_VMCALL 18
+
+#define EXIT_REASON_CR_ACCESS 28
+#define EXIT_REASON_DR_ACCESS 29
+#define EXIT_REASON_IO_INSTRUCTION 30
+#define EXIT_REASON_MSR_READ 31
+#define EXIT_REASON_MSR_WRITE 32
+#define EXIT_REASON_MWAIT_INSTRUCTION 36
+
+/*
+ * Interruption-information format
+ */
+#define INTR_INFO_VECTOR_MASK 0xff /* 7:0 */
+#define INTR_INFO_INTR_TYPE_MASK 0x700 /* 10:8 */
+#define INTR_INFO_DELIEVER_CODE_MASK 0x800 /* 11 */
+#define INTR_INFO_VALID_MASK 0x80000000 /* 31 */
+
+#define INTR_TYPE_EXT_INTR (0 << 8) /* external interrupt */
+#define INTR_TYPE_EXCEPTION (3 << 8) /* processor exception */
+
+/*
+ * Exit Qualifications for MOV for Control Register Access
+ */
+#define CONTROL_REG_ACCESS_NUM 0x7 /* 2:0, number of control register */
+#define CONTROL_REG_ACCESS_TYPE 0x30 /* 5:4, access type */
+#define TYPE_MOV_TO_CR (0 << 4)
+#define TYPE_MOV_FROM_CR (1 << 4)
+#define TYPE_CLTS (2 << 4)
+#define CONTROL_REG_ACCESS_REG 0x700 /* 10:8, general purpose register */
+#define REG_EAX (0 << 8)
+#define REG_ECX (1 << 8)
+#define REG_EDX (2 << 8)
+#define REG_EBX (3 << 8)
+#define REG_ESP (4 << 8)
+#define REG_EBP (5 << 8)
+#define REG_ESI (6 << 8)
+#define REG_EDI (7 << 8)
+
+/*
+ * Exit Qualifications for MOV for Debug Register Access
+ */
+#define DEBUG_REG_ACCESS_NUM 0x7 /* 2:0, number of debug register */
+#define DEBUG_REG_ACCESS_TYPE 0x10 /* 4, direction of access */
+#define TYPE_MOV_TO_DR (0 << 4)
+#define TYPE_MOV_FROM_DR (1 << 4)
+#define DEBUG_REG_ACCESS_REG 0x700 /* 11:8, general purpose register */
+
+#define EXCEPTION_BITMAP_DE (1 << 0) /* Divide Error */
+#define EXCEPTION_BITMAP_DB (1 << 1) /* Debug */
+#define EXCEPTION_BITMAP_NMI (1 << 2) /* NMI */
+#define EXCEPTION_BITMAP_BP (1 << 3) /* Breakpoint */
+#define EXCEPTION_BITMAP_OF (1 << 4) /* Overflow */
+#define EXCEPTION_BITMAP_BR (1 << 5) /* BOUND Range Exceeded */
+#define EXCEPTION_BITMAP_UD (1 << 6) /* Invalid Opcode */
+#define EXCEPTION_BITMAP_NM (1 << 7) /* Device Not Available */
+#define EXCEPTION_BITMAP_DF (1 << 8) /* Double Fault */
+/* reserved */
+#define EXCEPTION_BITMAP_TS (1 << 10) /* Invalid TSS */
+#define EXCEPTION_BITMAP_NP (1 << 11) /* Segment Not Present */
+#define EXCEPTION_BITMAP_SS (1 << 12) /* Stack-Segment Fault */
+#define EXCEPTION_BITMAP_GP (1 << 13) /* General Protection */
+#define EXCEPTION_BITMAP_PG (1 << 14) /* Page Fault */
+#define EXCEPTION_BITMAP_MF (1 << 16) /* x87 FPU Floating-Point Error (Math Fault) */
+#define EXCEPTION_BITMAP_AC (1 << 17) /* Alignment Check */
+#define EXCEPTION_BITMAP_MC (1 << 18) /* Machine Check */
+#define EXCEPTION_BITMAP_XF (1 << 19) /* SIMD Floating-Point Exception */
+
+#ifdef XEN_DEBUGGER
+#define MONITOR_DEFAULT_EXCEPTION_BITMAP \
+ ( EXCEPTION_BITMAP_PG | \
+ EXCEPTION_BITMAP_DB | \
+ EXCEPTION_BITMAP_BP | \
+ EXCEPTION_BITMAP_GP )
+#else
+#define MONITOR_DEFAULT_EXCEPTION_BITMAP \
+ ( EXCEPTION_BITMAP_PG | \
+ EXCEPTION_BITMAP_GP )
+#endif
+
+#define VMCALL_OPCODE ".byte 0x0f,0x01,0xc1\n"
+#define VMCLEAR_OPCODE ".byte 0x66,0x0f,0xc7\n" /* reg/opcode: /6 */
+#define VMLAUNCH_OPCODE ".byte 0x0f,0x01,0xc2\n"
+#define VMPTRLD_OPCODE ".byte 0x0f,0xc7\n" /* reg/opcode: /6 */
+#define VMPTRST_OPCODE ".byte 0x0f,0xc7\n" /* reg/opcode: /7 */
+#define VMREAD_OPCODE ".byte 0x0f,0x78\n"
+#define VMRESUME_OPCODE ".byte 0x0f,0x01,0xc3\n"
+#define VMWRITE_OPCODE ".byte 0x0f,0x79\n"
+#define VMXOFF_OPCODE ".byte 0x0f,0x01,0xc4\n"
+#define VMXON_OPCODE ".byte 0xf3,0x0f,0xc7\n"
+
+#define MODRM_EAX_06 ".byte 0x30\n" /* [EAX], with reg/opcode: /6 */
+#define MODRM_EAX_07 ".byte 0x38\n" /* [EAX], with reg/opcode: /7 */
+#define MODRM_EAX_ECX ".byte 0xc1\n" /* [EAX], [ECX] */
+
+static inline int __vmptrld (u64 addr)
+{
+ unsigned long eflags;
+ __asm__ __volatile__ ( VMPTRLD_OPCODE
+ MODRM_EAX_06
+ :
+ : "a" (&addr)
+ : "memory");
+
+ __save_flags(eflags);
+ if (eflags & X86_EFLAGS_ZF || eflags & X86_EFLAGS_CF)
+ return -1;
+ return 0;
+}
+
+static inline void __vmptrst (u64 addr)
+{
+ __asm__ __volatile__ ( VMPTRST_OPCODE
+ MODRM_EAX_07
+ :
+ : "a" (&addr)
+ : "memory");
+}
+
+static inline int __vmpclear (u64 addr)
+{
+ unsigned long eflags;
+
+ __asm__ __volatile__ ( VMCLEAR_OPCODE
+ MODRM_EAX_06
+ :
+ : "a" (&addr)
+ : "memory");
+ __save_flags(eflags);
+ if (eflags & X86_EFLAGS_ZF || eflags & X86_EFLAGS_CF)
+ return -1;
+ return 0;
+}
+
+static inline int __vmread (unsigned int field, void *value)
+{
+ unsigned long eflags;
+ unsigned long ecx = 0;
+
+ __asm__ __volatile__ ( VMREAD_OPCODE
+ MODRM_EAX_ECX
+ : "=c" (ecx)
+ : "a" (field)
+ : "memory");
+
+ *((long *) value) = ecx;
+
+ __save_flags(eflags);
+ if (eflags & X86_EFLAGS_ZF || eflags & X86_EFLAGS_CF)
+ return -1;
+ return 0;
+}
+
+static inline int __vmwrite (unsigned int field, unsigned int value)
+{
+ unsigned long eflags;
+
+ __asm__ __volatile__ ( VMWRITE_OPCODE
+ MODRM_EAX_ECX
+ :
+ : "a" (field) , "c" (value)
+ : "memory");
+ __save_flags(eflags);
+ if (eflags & X86_EFLAGS_ZF || eflags & X86_EFLAGS_CF)
+ return -1;
+ return 0;
+}
+
+static inline void __vmxoff (void)
+{
+ __asm__ __volatile__ ( VMXOFF_OPCODE
+ ::: "memory");
+}
+
+static inline int __vmxon (u64 addr)
+{
+ unsigned long eflags;
+
+ __asm__ __volatile__ ( VMXON_OPCODE
+ MODRM_EAX_06
+ :
+ : "a" (&addr)
+ : "memory");
+ __save_flags(eflags);
+ if (eflags & X86_EFLAGS_ZF || eflags & X86_EFLAGS_CF)
+ return -1;
+ return 0;
+}
+#endif /* __ASM_X86_VMX_H__ */
diff --git a/xen/include/asm-x86/vmx_cpu.h b/xen/include/asm-x86/vmx_cpu.h
new file mode 100644
index 0000000000..2cccc151dd
--- /dev/null
+++ b/xen/include/asm-x86/vmx_cpu.h
@@ -0,0 +1,35 @@
+/*
+ * vmx_cpu.h: Virtual CPU state
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, 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 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.
+ *
+ */
+#ifndef __ASM_X86_VMX_VMCS_H__
+#define __ASM_X86_VMX_VMCS_H__
+
+/*
+ * Virtual CPU
+ */
+struct arch_state_struct {
+ unsigned long mode_flags; /* vm86, 32-bit, 64-bit, etc. */
+ /* debug registers */
+ /* MSRs */
+};
+
+#define VMX_MF_VM86 0
+#define VMX_MF_32 1
+#define VMX_MF_64 2
+
+#endif
diff --git a/xen/include/asm-x86/vmx_platform.h b/xen/include/asm-x86/vmx_platform.h
new file mode 100644
index 0000000000..4557e5d083
--- /dev/null
+++ b/xen/include/asm-x86/vmx_platform.h
@@ -0,0 +1,96 @@
+/*
+ * vmx_platform.h: VMX platform support
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, 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 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.
+ *
+ */
+#ifndef __ASM_X86_VMX_PLATFORM_H__
+#define __ASM_X86_VMX_PLATFORM_H__
+
+#include <public/xen.h>
+#include <asm/e820.h>
+
+#define MAX_OPERAND_NUM 3
+#define I_NAME_LEN 16
+
+#define mk_operand(size, index, seg, flag) \
+ (((size) << 24) | ((index) << 16) | ((seg) << 8) | (flag))
+
+#define operand_size(operand) \
+ ((operand >> 24) & 0xFF)
+
+#define operand_index(operand) \
+ ((operand >> 16) & 0xFF)
+ //For instruction.operand[].size
+#define BYTE 1
+#define WORD 2
+#define LONG 4
+#define QUAD 8
+
+ //For instruction.operand[].flag
+#define REGISTER 0x1
+#define MEMORY 0x2
+#define IMMEDIATE 0x4
+#define WZEROEXTEND 0x8
+
+ //For instruction.flags
+#define REPZ 0x1
+#define REPNZ 0x2
+
+struct instruction {
+ __s8 i_name[I_NAME_LEN]; //Instruction's name
+ __s16 op_size; //The operand's bit size, e.g. 16-bit or 32-bit.
+
+ __u64 offset; //The effective address
+ //offset = Base + (Index * Scale) + Displacement
+
+ __u64 immediate;
+
+ __u16 seg_sel; //Segmentation selector
+
+ __u32 operand[MAX_OPERAND_NUM]; //The order of operand is from AT&T Assembly
+ __s16 op_num; //The operand numbers
+
+ __u32 flags; //
+};
+
+#define VGA_SPACE_START 0xA0000
+#define VGA_SPACE_END 0xC0000
+#define MAX_INST_LEN 32
+
+struct mi_per_cpu_info
+{
+ unsigned long mmio_target;
+ struct xen_regs *inst_decoder_regs;
+};
+
+struct virutal_platform_def {
+ unsigned long *real_mode_data; /* E820, etc. */
+ unsigned long shared_page_va;
+ struct mi_per_cpu_info mpci; /* MMIO */
+};
+
+extern void handle_mmio(unsigned long, unsigned long, unsigned long);
+extern int vmx_setup_platform(struct exec_domain *, execution_context_t *);
+
+static inline int mmio_space(unsigned long gpa)
+{
+ if (gpa >= VGA_SPACE_START && gpa < VGA_SPACE_END) {
+ return 1;
+ }
+ return 0;
+}
+
+#endif
diff --git a/xen/include/asm-x86/vmx_vmcs.h b/xen/include/asm-x86/vmx_vmcs.h
new file mode 100644
index 0000000000..6ee5137e74
--- /dev/null
+++ b/xen/include/asm-x86/vmx_vmcs.h
@@ -0,0 +1,214 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+/*
+ * vmx_vmcs.h: VMCS related definitions
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, 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 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.
+ *
+ */
+#ifndef __ASM_X86_VMX_VMCS_H__
+#define __ASM_X86_VMX_VMCS_H__
+
+#include <asm/config.h>
+#include <asm/vmx_cpu.h>
+#include <asm/vmx_platform.h>
+
+extern int start_vmx(void);
+extern void stop_vmx(void);
+
+void vmx_enter_scheduler(void);
+
+union vmcs_arbytes {
+ struct arbyte_fields {
+ unsigned int
+ seg_type: 4, s: 1, dpl: 2, p: 1,
+ reserved0: 4, avl: 1, reserved1: 1,
+ default_ops_size: 1, g: 1, null_bit: 1,
+ reserved2: 15;
+ } __attribute__((packed)) fields;
+ unsigned int bytes;
+};
+
+#define VMX_CPU_STATE_PG_ENABLED 0
+#define VMCS_SIZE 0x1000
+
+struct vmcs_struct {
+ u32 vmcs_revision_id;
+ unsigned char data [0x1000 - sizeof (u32)];
+};
+
+struct arch_vmx_struct {
+ struct vmcs_struct *vmcs; /* VMCS pointer in virtual */
+ unsigned long flags; /* VMCS flags */
+ unsigned long cpu_cr2; /* save CR2 */
+ unsigned long cpu_cr3;
+ unsigned long cpu_state;
+ struct virutal_platform_def vmx_platform;
+};
+
+#define vmx_schedule_tail(next) \
+ (next)->thread.arch_vmx.arch_vmx_schedule_tail((next))
+
+#define VMX_DOMAIN(d) d->arch.arch_vmx.flags
+
+#define ARCH_VMX_VMCS_LOADED 0 /* VMCS has been loaded and active */
+#define ARCH_VMX_VMCS_LAUNCH 1 /* Needs VMCS launch */
+#define ARCH_VMX_VMCS_RESUME 2 /* Needs VMCS resume */
+#define ARCH_VMX_IO_WAIT 3 /* Waiting for I/O completion */
+
+void vmx_do_launch(struct exec_domain *);
+void vmx_do_resume(struct exec_domain *);
+
+struct vmcs_struct *alloc_vmcs(void);
+void free_vmcs(struct vmcs_struct *);
+int load_vmcs(struct arch_vmx_struct *, u64);
+int store_vmcs(struct arch_vmx_struct *, u64);
+void dump_vmcs(void);
+int construct_vmcs(struct arch_vmx_struct *, execution_context_t *,
+ full_execution_context_t *, int);
+
+#define VMCS_USE_HOST_ENV 1
+#define VMCS_USE_SEPARATE_ENV 0
+
+#define VMCS_EFLAGS_RESERVED_0 0xffc08028 /* bitmap for 0 */
+#define VMCS_EFLAGS_RESERVED_1 0x00000002 /* bitmap for 1 */
+
+extern int vmcs_version;
+
+/* VMCS Encordings */
+enum vmcs_field {
+ GUEST_ES_SELECTOR = 0x00000800,
+ GUEST_CS_SELECTOR = 0x00000802,
+ GUEST_SS_SELECTOR = 0x00000804,
+ GUEST_DS_SELECTOR = 0x00000806,
+ GUEST_FS_SELECTOR = 0x00000808,
+ GUEST_GS_SELECTOR = 0x0000080a,
+ GUEST_LDTR_SELECTOR = 0x0000080c,
+ GUEST_TR_SELECTOR = 0x0000080e,
+ HOST_ES_SELECTOR = 0x00000c00,
+ HOST_CS_SELECTOR = 0x00000c02,
+ HOST_SS_SELECTOR = 0x00000c04,
+ HOST_DS_SELECTOR = 0x00000c06,
+ HOST_FS_SELECTOR = 0x00000c08,
+ HOST_GS_SELECTOR = 0x00000c0a,
+ HOST_TR_SELECTOR = 0x00000c0c,
+ IO_BITMAP_A = 0x00002000,
+ IO_BITMAP_B = 0x00002002,
+ VM_EXIT_MSR_STORE_ADDR = 0x00002006,
+ VM_EXIT_MSR_LOAD_ADDR = 0x00002008,
+ VM_ENTRY_MSR_LOAD_ADDR = 0x0000200a,
+ TSC_OFFSET = 0x00002010,
+ GUEST_VMCS0 = 0x00002800,
+ GUEST_VMCS1 = 0x00002801,
+ GUEST_IA32_DEBUGCTL = 0x00002802,
+ PIN_BASED_VM_EXEC_CONTROL = 0x00004000,
+ CPU_BASED_VM_EXEC_CONTROL = 0x00004002,
+ EXCEPTION_BITMAP = 0x00004004,
+ PAGE_FAULT_ERROR_CODE_MASK = 0x00004006,
+ PAGE_FAULT_ERROR_CODE_MATCH = 0x00004008,
+ CR3_TARGET_COUNT = 0x0000400a,
+ VM_EXIT_CONTROLS = 0x0000400c,
+ VM_EXIT_MSR_STORE_COUNT = 0x0000400e,
+ VM_EXIT_MSR_LOAD_COUNT = 0x00004010,
+ VM_ENTRY_CONTROLS = 0x00004012,
+ VM_ENTRY_MSR_LOAD_COUNT = 0x00004014,
+ VM_ENTRY_INTR_INFO_FIELD = 0x00004016,
+ VM_ENTRY_EXCEPTION_ERROR_CODE = 0x00004018,
+ VM_EXIT_REASON = 0x00004402,
+ VM_EXIT_INTR_INFO = 0x00004404,
+ VM_EXIT_INTR_ERROR_CODE = 0x00004406,
+ IDT_VECTORING_INFO_FIELD = 0x00004408,
+ IDT_VECTORING_ERROR_CODE = 0x0000440a,
+ INSTRUCTION_LEN = 0x0000440c,
+ GUEST_ES_LIMIT = 0x00004800,
+ GUEST_CS_LIMIT = 0x00004802,
+ GUEST_SS_LIMIT = 0x00004804,
+ GUEST_DS_LIMIT = 0x00004806,
+ GUEST_FS_LIMIT = 0x00004808,
+ GUEST_GS_LIMIT = 0x0000480a,
+ GUEST_LDTR_LIMIT = 0x0000480c,
+ GUEST_TR_LIMIT = 0x0000480e,
+ GUEST_GDTR_LIMIT = 0x00004810,
+ GUEST_IDTR_LIMIT = 0x00004812,
+ GUEST_ES_AR_BYTES = 0x00004814,
+ GUEST_CS_AR_BYTES = 0x00004816,
+ GUEST_SS_AR_BYTES = 0x00004818,
+ GUEST_DS_AR_BYTES = 0x0000481a,
+ GUEST_FS_AR_BYTES = 0x0000481c,
+ GUEST_GS_AR_BYTES = 0x0000481e,
+ GUEST_LDTR_AR_BYTES = 0x00004820,
+ GUEST_TR_AR_BYTES = 0x00004822,
+ GUEST_INTERRUPTIBILITY_INFO = 0x00004824,
+ CR0_GUEST_HOST_MASK = 0x00006000,
+ CR4_GUEST_HOST_MASK = 0x00006002,
+ CR0_READ_SHADOW = 0x00006004,
+ CR4_READ_SHADOW = 0x00006006,
+ CR3_TARGET_VALUES = 0x00006008,
+ CR3_GUEST_HOST_MASK = 0x00006208,
+ EXIT_QUALIFICATION = 0x00006400,
+ GUEST_CR0 = 0x00006800,
+ GUEST_CR3 = 0x00006802,
+ GUEST_CR4 = 0x00006804,
+ GUEST_ES_BASE = 0x00006806,
+ GUEST_CS_BASE = 0x00006808,
+ GUEST_SS_BASE = 0x0000680a,
+ GUEST_DS_BASE = 0x0000680c,
+ GUEST_FS_BASE = 0x0000680e,
+ GUEST_GS_BASE = 0x00006810,
+ GUEST_LDTR_BASE = 0x00006812,
+ GUEST_TR_BASE = 0x00006814,
+ GUEST_GDTR_BASE = 0x00006816,
+ GUEST_IDTR_BASE = 0x00006818,
+ GUEST_DR7 = 0x0000681a,
+ GUEST_ESP = 0x0000681c,
+ GUEST_EIP = 0x0000681e,
+ GUEST_EFLAGS = 0x00006820,
+ GUEST_PENDING_DBG_EXCEPTIONS = 0x00006822,
+ HOST_CR0 = 0x00006c00,
+ HOST_CR3 = 0x00006c02,
+ HOST_CR4 = 0x00006c04,
+ HOST_FS_BASE = 0x00006c06,
+ HOST_GS_BASE = 0x00006c08,
+ HOST_TR_BASE = 0x00006c0a,
+ HOST_GDTR_BASE = 0x00006c0c,
+ HOST_IDTR_BASE = 0x00006c0e,
+ HOST_ESP = 0x00006c14,
+ HOST_EIP = 0x00006c16,
+};
+
+#define VMX_DEBUG 1
+#if VMX_DEBUG
+#define DBG_LEVEL_0 (1 << 0)
+#define DBG_LEVEL_1 (1 << 1)
+#define DBG_LEVEL_2 (1 << 2)
+#define DBG_LEVEL_3 (1 << 3)
+#define DBG_LEVEL_IO (1 << 4)
+#define DBG_LEVEL_VMMU (1 << 5)
+
+extern unsigned int opt_vmx_debug_level;
+#define VMX_DBG_LOG(level, _f, _a...) \
+ if ((level) & opt_vmx_debug_level) \
+ printk("[VMX]" _f "\n", ## _a )
+#else
+#define VMX_DBG_LOG(level, _f, _a...)
+#endif
+
+#define __vmx_bug(regs) \
+ do { \
+ printk("__vmx_bug at %s:%d\n", __FILE__, __LINE__); \
+ show_registers(regs); \
+ domain_crash(); \
+ } while (0)
+
+#endif /* ASM_X86_VMX_VMCS_H__ */
diff --git a/xen/include/asm-x86/x86_32/asm_defns.h b/xen/include/asm-x86/x86_32/asm_defns.h
index e11ea34964..08932f2610 100644
--- a/xen/include/asm-x86/x86_32/asm_defns.h
+++ b/xen/include/asm-x86/x86_32/asm_defns.h
@@ -78,4 +78,51 @@
#endif
+#define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v)
+#define XBUILD_SMP_INTERRUPT(x,v)\
+asmlinkage void x(void); \
+__asm__( \
+ "\n"__ALIGN_STR"\n" \
+ SYMBOL_NAME_STR(x) ":\n\t" \
+ "pushl $"#v"<<16\n\t" \
+ SAVE_ALL(a) \
+ "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
+ "jmp ret_from_intr\n");
+
+#define BUILD_SMP_TIMER_INTERRUPT(x,v) XBUILD_SMP_TIMER_INTERRUPT(x,v)
+#define XBUILD_SMP_TIMER_INTERRUPT(x,v) \
+asmlinkage void x(struct xen_regs * regs); \
+__asm__( \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(x) ":\n\t" \
+ "pushl $"#v"<<16\n\t" \
+ SAVE_ALL(a) \
+ "movl %esp,%eax\n\t" \
+ "pushl %eax\n\t" \
+ "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
+ "addl $4,%esp\n\t" \
+ "jmp ret_from_intr\n");
+
+#define BUILD_COMMON_IRQ() \
+__asm__( \
+ "\n" __ALIGN_STR"\n" \
+ "common_interrupt:\n\t" \
+ SAVE_ALL(a) \
+ "movl %esp,%eax\n\t" \
+ "pushl %eax\n\t" \
+ "call " SYMBOL_NAME_STR(do_IRQ) "\n\t" \
+ "addl $4,%esp\n\t" \
+ "jmp ret_from_intr\n");
+
+#define IRQ_NAME2(nr) nr##_interrupt(void)
+#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
+
+#define BUILD_IRQ(nr) \
+asmlinkage void IRQ_NAME(nr); \
+__asm__( \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
+ "pushl $"#nr"<<16\n\t" \
+ "jmp common_interrupt");
+
#endif /* __X86_32_ASM_DEFNS_H__ */
diff --git a/xen/include/asm-x86/x86_32/current.h b/xen/include/asm-x86/x86_32/current.h
index 2c76a133aa..3c254191ba 100644
--- a/xen/include/asm-x86/x86_32/current.h
+++ b/xen/include/asm-x86/x86_32/current.h
@@ -1,3 +1,5 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+
#ifndef _X86_CURRENT_H
#define _X86_CURRENT_H
@@ -6,20 +8,20 @@ struct domain;
#define STACK_RESERVED \
(sizeof(execution_context_t) + sizeof(struct domain *))
-static inline struct domain * get_current(void)
+static inline struct exec_domain *get_current(void)
{
- struct domain *current;
+ struct exec_domain *ed;
__asm__ ( "orl %%esp,%0; andl $~3,%0; movl (%0),%0"
- : "=r" (current) : "0" (STACK_SIZE-4) );
- return current;
+ : "=r" (ed) : "0" (STACK_SIZE-4) );
+ return ed;
}
#define current get_current()
-static inline void set_current(struct domain *p)
+static inline void set_current(struct exec_domain *ed)
{
__asm__ ( "orl %%esp,%0; andl $~3,%0; movl %1,(%0)"
- : : "r" (STACK_SIZE-4), "r" (p) );
+ : : "r" (STACK_SIZE-4), "r" (ed) );
}
static inline execution_context_t *get_execution_context(void)
@@ -50,6 +52,6 @@ static inline unsigned long get_stack_top(void)
"movl %0,%%esp; jmp "STR(__fn) \
: : "r" (get_execution_context()) )
-#define schedule_tail(_d) ((_d)->thread.schedule_tail)(_d)
+#define schedule_tail(_ed) ((_ed)->arch.schedule_tail)(_ed)
#endif /* _X86_CURRENT_H */
diff --git a/xen/include/asm-x86/x86_32/domain_page.h b/xen/include/asm-x86/x86_32/domain_page.h
new file mode 100644
index 0000000000..d8cdf0b74e
--- /dev/null
+++ b/xen/include/asm-x86/x86_32/domain_page.h
@@ -0,0 +1,29 @@
+/******************************************************************************
+ * domain_page.h
+ *
+ * Allow temporary mapping of domain page frames into Xen space.
+ */
+
+#ifndef __ASM_DOMAIN_PAGE_H__
+#define __ASM_DOMAIN_PAGE_H__
+
+#include <xen/config.h>
+#include <xen/sched.h>
+
+extern unsigned long *mapcache;
+#define MAPCACHE_ENTRIES 1024
+
+/*
+ * Maps a given physical address, returning corresponding virtual address.
+ * The entire page containing that VA is now accessible until a
+ * corresponding call to unmap_domain_mem().
+ */
+extern void *map_domain_mem(unsigned long pa);
+
+/*
+ * Pass a VA within a page previously mapped with map_domain_mem().
+ * That page will then be removed from the mapping lists.
+ */
+extern void unmap_domain_mem(void *va);
+
+#endif /* __ASM_DOMAIN_PAGE_H__ */
diff --git a/xen/include/asm-x86/x86_32/regs.h b/xen/include/asm-x86/x86_32/regs.h
index 57d21e3cb6..e28f17fba6 100644
--- a/xen/include/asm-x86/x86_32/regs.h
+++ b/xen/include/asm-x86/x86_32/regs.h
@@ -3,6 +3,9 @@
#include <asm/types.h>
+/* So that we can use 'l' modifier in printf-style format strings. */
+#define u32 unsigned long
+
struct xen_regs
{
/* All saved activations contain the following fields. */
@@ -28,28 +31,7 @@ struct xen_regs
u32 gs;
} __attribute__ ((packed));
-enum EFLAGS {
- EF_CF = 0x00000001,
- EF_PF = 0x00000004,
- EF_AF = 0x00000010,
- EF_ZF = 0x00000040,
- EF_SF = 0x00000080,
- EF_TF = 0x00000100,
- EF_IE = 0x00000200,
- EF_DF = 0x00000400,
- EF_OF = 0x00000800,
- EF_IOPL = 0x00003000,
- EF_IOPL_RING0 = 0x00000000,
- EF_IOPL_RING1 = 0x00001000,
- EF_IOPL_RING2 = 0x00002000,
- EF_NT = 0x00004000, /* nested task */
- EF_RF = 0x00010000, /* resume */
- EF_VM = 0x00020000, /* virtual mode */
- EF_AC = 0x00040000, /* alignment */
- EF_VIF = 0x00080000, /* virtual interrupt */
- EF_VIP = 0x00100000, /* virtual interrupt pending */
- EF_ID = 0x00200000, /* id */
-};
+#undef u32
#define VM86_MODE(_r) ((_r)->eflags & EF_VM)
#define RING_0(_r) (((_r)->cs & 3) == 0)
diff --git a/xen/include/asm-x86/x86_32/uaccess.h b/xen/include/asm-x86/x86_32/uaccess.h
index b202a1a12b..c2420e74e5 100644
--- a/xen/include/asm-x86/x86_32/uaccess.h
+++ b/xen/include/asm-x86/x86_32/uaccess.h
@@ -10,9 +10,7 @@
#include <xen/string.h>
#include <xen/sched.h>
-/* No user-pointer checking. */
#define __user
-#define __chk_user_ptr(_p) ((void)0)
#define VERIFY_READ 0
#define VERIFY_WRITE 1
@@ -22,7 +20,7 @@
*/
#ifdef CONFIG_X86_INTEL_USERCOPY
extern struct movsl_mask {
- int mask;
+ int mask;
} __cacheline_aligned movsl_mask;
#endif
@@ -34,41 +32,22 @@ extern struct movsl_mask {
*
* This is equivalent to the following test:
* (u33)addr + (u33)size >= (u33)HYPERVISOR_VIRT_START
- *
- * This needs 33-bit arithmetic. We have a carry...
*/
-#define __range_ok(addr,size) ({ \
+#define __range_not_ok(addr,size) ({ \
unsigned long flag,sum; \
- __chk_user_ptr(addr); \
asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" \
:"=&r" (flag), "=r" (sum) \
:"1" (addr),"g" ((int)(size)),"r" (HYPERVISOR_VIRT_START)); \
flag; })
-/**
- * access_ok: - Checks if a user space pointer is valid
- * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that
- * %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
- * to write to a block, it is always safe to read from it.
- * @addr: User space pointer to start of block to check
- * @size: Size of block to check
- *
- * Context: User context only. This function may sleep.
- *
- * Checks if a pointer to a block of memory in user space is valid.
- *
- * Returns true (nonzero) if the memory block may be valid, false (zero)
- * if it is definitely invalid.
- *
- * Note that, depending on architecture, this function probably just
- * checks that the pointer is in the user space range - after calling
- * this function, memory access functions may still return -EFAULT.
- */
-#define access_ok(type,addr,size) (likely(__range_ok(addr,size) == 0))
+#define access_ok(type,addr,size) (likely(__range_not_ok(addr,size) == 0))
#define array_access_ok(type,addr,count,size) \
(likely(count < (~0UL/size)) && access_ok(type,addr,count*size))
+extern long __get_user_bad(void);
+extern void __put_user_bad(void);
+
/**
* get_user: - Get a simple variable from user space.
* @x: Variable to store result.
@@ -89,8 +68,6 @@ extern struct movsl_mask {
#define get_user(x,ptr) \
__get_user_check((x),(ptr),sizeof(*(ptr)))
-extern void __put_user_bad(void);
-
/**
* put_user: - Write a simple value into user space.
* @x: Value to copy to user space.
@@ -195,7 +172,6 @@ extern void __put_user_bad(void);
#define __put_user_size(x,ptr,size,retval,errret) \
do { \
retval = 0; \
- __chk_user_ptr(ptr); \
switch (size) { \
case 1: __put_user_asm(x,ptr,retval,"b","b","iq",errret);break; \
case 2: __put_user_asm(x,ptr,retval,"w","w","ir",errret);break; \
@@ -259,12 +235,9 @@ struct __large_struct { unsigned long buf[100]; };
__gu_err; \
})
-extern long __get_user_bad(void);
-
#define __get_user_size(x,ptr,size,retval,errret) \
do { \
retval = 0; \
- __chk_user_ptr(ptr); \
switch (size) { \
case 1: __get_user_asm(x,ptr,retval,"b","b","=q",errret);break; \
case 2: __get_user_asm(x,ptr,retval,"w","w","=r",errret);break; \
@@ -317,22 +290,22 @@ unsigned long __copy_from_user_ll(void *to, const void __user *from, unsigned lo
static always_inline unsigned long
__copy_to_user(void __user *to, const void *from, unsigned long n)
{
- if (__builtin_constant_p(n)) {
- unsigned long ret;
-
- switch (n) {
- case 1:
- __put_user_size(*(u8 *)from, (u8 __user *)to, 1, ret, 1);
- return ret;
- case 2:
- __put_user_size(*(u16 *)from, (u16 __user *)to, 2, ret, 2);
- return ret;
- case 4:
- __put_user_size(*(u32 *)from, (u32 __user *)to, 4, ret, 4);
- return ret;
- }
- }
- return __copy_to_user_ll(to, from, n);
+ if (__builtin_constant_p(n)) {
+ unsigned long ret;
+
+ switch (n) {
+ case 1:
+ __put_user_size(*(u8 *)from, (u8 __user *)to, 1, ret, 1);
+ return ret;
+ case 2:
+ __put_user_size(*(u16 *)from, (u16 __user *)to, 2, ret, 2);
+ return ret;
+ case 4:
+ __put_user_size(*(u32 *)from, (u32 __user *)to, 4, ret, 4);
+ return ret;
+ }
+ }
+ return __copy_to_user_ll(to, from, n);
}
/**
@@ -355,47 +328,28 @@ __copy_to_user(void __user *to, const void *from, unsigned long n)
static always_inline unsigned long
__copy_from_user(void *to, const void __user *from, unsigned long n)
{
- if (__builtin_constant_p(n)) {
- unsigned long ret;
-
- switch (n) {
- case 1:
- __get_user_size(*(u8 *)to, from, 1, ret, 1);
- return ret;
- case 2:
- __get_user_size(*(u16 *)to, from, 2, ret, 2);
- return ret;
- case 4:
- __get_user_size(*(u32 *)to, from, 4, ret, 4);
- return ret;
- }
- }
- return __copy_from_user_ll(to, from, n);
+ if (__builtin_constant_p(n)) {
+ unsigned long ret;
+
+ switch (n) {
+ case 1:
+ __get_user_size(*(u8 *)to, from, 1, ret, 1);
+ return ret;
+ case 2:
+ __get_user_size(*(u16 *)to, from, 2, ret, 2);
+ return ret;
+ case 4:
+ __get_user_size(*(u32 *)to, from, 4, ret, 4);
+ return ret;
+ }
+ }
+ return __copy_from_user_ll(to, from, n);
}
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n);
unsigned long copy_from_user(void *to,
- const void __user *from, unsigned long n);
-long strncpy_from_user(char *dst, const char __user *src, long count);
-long __strncpy_from_user(char *dst, const char __user *src, long count);
-
-/**
- * strlen_user: - Get the size of a string in user space.
- * @str: The string to measure.
- *
- * Context: User context only. This function may sleep.
- *
- * Get the size of a NUL-terminated string in user space.
- *
- * Returns the size of the string INCLUDING the terminating NUL.
- * On exception, returns 0.
- *
- * If there is a limit on the length of a valid string, you may wish to
- * consider using strnlen_user() instead.
- */
-#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
+ const void __user *from, unsigned long n);
-long strnlen_user(const char __user *str, long n);
unsigned long clear_user(void __user *mem, unsigned long len);
unsigned long __clear_user(void __user *mem, unsigned long len);
diff --git a/xen/include/asm-x86/x86_64/asm_defns.h b/xen/include/asm-x86/x86_64/asm_defns.h
index fa0b978304..f9478f9190 100644
--- a/xen/include/asm-x86/x86_64/asm_defns.h
+++ b/xen/include/asm-x86/x86_64/asm_defns.h
@@ -1,6 +1,127 @@
#ifndef __X86_64_ASM_DEFNS_H__
#define __X86_64_ASM_DEFNS_H__
-#define SAVE_ALL(_r) ""
+/* Maybe auto-generate the following two cases (quoted vs. unquoted). */
+#ifndef __ASSEMBLY__
+
+#define SAVE_ALL \
+ "cld;" \
+ "pushq %rdi;" \
+ "pushq %rsi;" \
+ "pushq %rdx;" \
+ "pushq %rcx;" \
+ "pushq %rax;" \
+ "pushq %r8;" \
+ "pushq %r9;" \
+ "pushq %r10;" \
+ "pushq %r11;" \
+ "pushq %rbx;" \
+ "pushq %rbp;" \
+ "pushq %r12;" \
+ "pushq %r13;" \
+ "pushq %r14;" \
+ "pushq %r15;"
+
+#define RESTORE_ALL \
+ "popq %r15;" \
+ "popq %r14;" \
+ "popq %r13;" \
+ "popq %r12;" \
+ "popq %rbp;" \
+ "popq %rbx;" \
+ "popq %r11;" \
+ "popq %r10;" \
+ "popq %r9;" \
+ "popq %r8;" \
+ "popq %rax;" \
+ "popq %rcx;" \
+ "popq %rdx;" \
+ "popq %rsi;" \
+ "popq %rdi;"
+
+#else
+
+#define SAVE_ALL \
+ cld; \
+ pushq %rdi; \
+ pushq %rsi; \
+ pushq %rdx; \
+ pushq %rcx; \
+ pushq %rax; \
+ pushq %r8; \
+ pushq %r9; \
+ pushq %r10; \
+ pushq %r11; \
+ pushq %rbx; \
+ pushq %rbp; \
+ pushq %r12; \
+ pushq %r13; \
+ pushq %r14; \
+ pushq %r15;
+
+#define RESTORE_ALL \
+ popq %r15; \
+ popq %r14; \
+ popq %r13; \
+ popq %r12; \
+ popq %rbp; \
+ popq %rbx; \
+ popq %r11; \
+ popq %r10; \
+ popq %r9; \
+ popq %r8; \
+ popq %rax; \
+ popq %rcx; \
+ popq %rdx; \
+ popq %rsi; \
+ popq %rdi;
+
+#endif
+
+#define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v)
+#define XBUILD_SMP_INTERRUPT(x,v)\
+asmlinkage void x(void); \
+__asm__( \
+ "\n"__ALIGN_STR"\n" \
+ SYMBOL_NAME_STR(x) ":\n\t" \
+ "pushq $0\n\t" \
+ "movl $"#v",4(%rsp)\n\t" \
+ SAVE_ALL \
+ "callq "SYMBOL_NAME_STR(smp_##x)"\n\t" \
+ "jmp ret_from_intr\n");
+
+#define BUILD_SMP_TIMER_INTERRUPT(x,v) XBUILD_SMP_TIMER_INTERRUPT(x,v)
+#define XBUILD_SMP_TIMER_INTERRUPT(x,v) \
+asmlinkage void x(struct xen_regs * regs); \
+__asm__( \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(x) ":\n\t" \
+ "pushq $0\n\t" \
+ "movl $"#v",4(%rsp)\n\t" \
+ SAVE_ALL \
+ "movq %rsp,%rdi\n\t" \
+ "callq "SYMBOL_NAME_STR(smp_##x)"\n\t" \
+ "jmp ret_from_intr\n");
+
+#define BUILD_COMMON_IRQ() \
+__asm__( \
+ "\n" __ALIGN_STR"\n" \
+ "common_interrupt:\n\t" \
+ SAVE_ALL \
+ "movq %rsp,%rdi\n\t" \
+ "callq " SYMBOL_NAME_STR(do_IRQ) "\n\t" \
+ "jmp ret_from_intr\n");
+
+#define IRQ_NAME2(nr) nr##_interrupt(void)
+#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
+
+#define BUILD_IRQ(nr) \
+asmlinkage void IRQ_NAME(nr); \
+__asm__( \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
+ "pushq $0\n\t" \
+ "movl $"#nr",4(%rsp)\n\t" \
+ "jmp common_interrupt");
#endif /* __X86_64_ASM_DEFNS_H__ */
diff --git a/xen/include/asm-x86/x86_64/current.h b/xen/include/asm-x86/x86_64/current.h
index 2ee550643b..0442f2db0f 100644
--- a/xen/include/asm-x86/x86_64/current.h
+++ b/xen/include/asm-x86/x86_64/current.h
@@ -1,26 +1,27 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+
#ifndef _X86_64_CURRENT_H
#define _X86_64_CURRENT_H
-#if !defined(__ASSEMBLY__)
struct domain;
-#include <asm/pda.h>
-
#define STACK_RESERVED \
- (sizeof(execution_context_t))
+ (sizeof(execution_context_t) + sizeof(struct domain *))
-static inline struct domain * get_current(void)
+static inline struct exec_domain *get_current(void)
{
- struct domain *current;
- current = read_pda(pcurrent);
- return current;
+ struct exec_domain *ed;
+ __asm__ ( "orq %%rsp,%0; andq $~7,%0; movq (%0),%0"
+ : "=r" (ed) : "0" (STACK_SIZE-8) );
+ return ed;
}
#define current get_current()
-static inline void set_current(struct domain *p)
+static inline void set_current(struct exec_domain *ed)
{
- write_pda(pcurrent,p);
+ __asm__ ( "orq %%rsp,%0; andq $~7,%0; movq %1,(%0)"
+ : : "r" (STACK_SIZE-8), "r" (ed) );
}
static inline execution_context_t *get_execution_context(void)
@@ -45,16 +46,6 @@ static inline unsigned long get_stack_top(void)
"movq %0,%%rsp; jmp "STR(__fn) \
: : "r" (get_execution_context()) )
-#define schedule_tail(_d) ((_d)->thread.schedule_tail)(_d)
-
-#else
-
-#ifndef ASM_OFFSET_H
-#include <asm/offset.h>
-#endif
-
-#define GET_CURRENT(reg) movq %gs:(pda_pcurrent),reg
-
-#endif
+#define schedule_tail(_ed) ((_ed)->arch.schedule_tail)(_ed)
#endif /* !(_X86_64_CURRENT_H) */
diff --git a/xen/include/asm-x86/x86_64/desc.h b/xen/include/asm-x86/x86_64/desc.h
deleted file mode 100644
index d1171de39d..0000000000
--- a/xen/include/asm-x86/x86_64/desc.h
+++ /dev/null
@@ -1,118 +0,0 @@
-#ifndef __ARCH_DESC_H
-#define __ARCH_DESC_H
-
-#define LDT_ENTRY_SIZE 16
-
-#define __DOUBLEFAULT_TSS_ENTRY FIRST_RESERVED_GDT_ENTRY
-
-#define __FIRST_PER_CPU_ENTRY (FIRST_RESERVED_GDT_ENTRY + 8)
-
-#define __CPU_DESC_INDEX(x,field) \
- ((x) * sizeof(struct per_cpu_gdt) + offsetof(struct per_cpu_gdt, field) + (__FIRST_PER_CPU_ENTRY*8))
-#define __LDT(n) (((n)<<1) + __FIRST_LDT_ENTRY)
-
-#define load_TR(cpu) asm volatile("ltr %w0"::"r" (__CPU_DESC_INDEX(cpu, tss)));
-#define __load_LDT(cpu) asm volatile("lldt %w0"::"r" (__CPU_DESC_INDEX(cpu, ldt)));
-#define clear_LDT(n) asm volatile("lldt %w0"::"r" (0))
-
-/*
- * Guest OS must provide its own code selectors, or use the one we provide. The
- * RPL must be 1, as we only create bounce frames to ring 1. Any LDT selector
- * value is okay. Note that checking only the RPL is insufficient: if the
- * selector is poked into an interrupt, trap or call gate then the RPL is
- * ignored when the gate is accessed.
- */
-#define VALID_SEL(_s) \
- (((((_s)>>3) < FIRST_RESERVED_GDT_ENTRY) || \
- (((_s)>>3) > LAST_RESERVED_GDT_ENTRY) || \
- ((_s)&4)) && \
- (((_s)&3) == 0))
-#define VALID_CODESEL(_s) ((_s) == FLAT_RING3_CS || VALID_SEL(_s))
-
-/* These are bitmasks for the first 32 bits of a descriptor table entry. */
-#define _SEGMENT_TYPE (15<< 8)
-#define _SEGMENT_S ( 1<<12) /* System descriptor (yes iff S==0) */
-#define _SEGMENT_DPL ( 3<<13) /* Descriptor Privilege Level */
-#define _SEGMENT_P ( 1<<15) /* Segment Present */
-#define _SEGMENT_G ( 1<<23) /* Granularity */
-
-#ifndef __ASSEMBLY__
-
-enum {
- GATE_INTERRUPT = 0xE,
- GATE_TRAP = 0xF,
- GATE_CALL = 0xC,
-};
-
-// 16byte gate
-struct gate_struct {
- u16 offset_low;
- u16 segment;
- unsigned ist : 3, zero0 : 5, type : 5, dpl : 2, p : 1;
- u16 offset_middle;
- u32 offset_high;
- u32 zero1;
-} __attribute__((packed));
-
-// 8 byte segment descriptor
-struct desc_struct {
- u16 limit0;
- u16 base0;
- unsigned base1 : 8, type : 4, s : 1, dpl : 2, p : 1;
- unsigned limit : 4, avl : 1, l : 1, d : 1, g : 1, base2 : 8;
-} __attribute__((packed));
-
-// LDT or TSS descriptor in the GDT. 16 bytes.
-struct ldttss_desc {
- u16 limit0;
- u16 base0;
- unsigned base1 : 8, type : 5, dpl : 2, p : 1;
- unsigned limit1 : 4, zero0 : 3, g : 1, base2 : 8;
- u32 base3;
- u32 zero1;
-} __attribute__((packed));
-
-// Union of above structures
-union desc_union {
- struct desc_struct seg;
- struct ldttss_desc ldttss;
- struct gate_struct gate;
-};
-
-struct per_cpu_gdt {
- struct ldttss_desc tss;
- struct ldttss_desc ldt;
-} __cacheline_aligned;
-
-
-struct Xgt_desc_struct {
- unsigned short size;
- unsigned long address;
-} __attribute__((packed));
-
-extern __u8 gdt_table[];
-extern __u8 gdt_end[];
-extern union desc_union *gdt;
-
-extern struct per_cpu_gdt gdt_cpu_table[];
-
-#define PTR_LOW(x) ((unsigned long)(x) & 0xFFFF)
-#define PTR_MIDDLE(x) (((unsigned long)(x) >> 16) & 0xFFFF)
-#define PTR_HIGH(x) ((unsigned long)(x) >> 32)
-
-enum {
- DESC_TSS = 0x9,
- DESC_LDT = 0x2,
-};
-
-extern struct gate_struct *idt;
-
-#define idt_descr (*(struct Xgt_desc_struct *)((char *)&idt - 2))
-#define gdt_descr (*(struct Xgt_desc_struct *)((char *)&gdt - 2))
-
-extern void set_intr_gate(unsigned int irq, void * addr);
-extern void set_tss_desc(unsigned int n, void *addr);
-
-#endif /* !__ASSEMBLY__ */
-
-#endif
diff --git a/xen/include/asm-x86/x86_64/domain_page.h b/xen/include/asm-x86/x86_64/domain_page.h
new file mode 100644
index 0000000000..8a6081cde4
--- /dev/null
+++ b/xen/include/asm-x86/x86_64/domain_page.h
@@ -0,0 +1,13 @@
+/******************************************************************************
+ * domain_page.h
+ *
+ * This is a trivial no-op on x86/64, where we can 1:1 map all RAM.
+ */
+
+#ifndef __ASM_DOMAIN_PAGE_H__
+#define __ASM_DOMAIN_PAGE_H__
+
+#define map_domain_mem(_pa) phys_to_virt(_pa)
+#define unmap_domain_mem(_va) ((void)(_va))
+
+#endif /* __ASM_DOMAIN_PAGE_H__ */
diff --git a/xen/include/asm-x86/x86_64/regs.h b/xen/include/asm-x86/x86_64/regs.h
index 7daea0f0ed..0169109fe3 100644
--- a/xen/include/asm-x86/x86_64/regs.h
+++ b/xen/include/asm-x86/x86_64/regs.h
@@ -1,114 +1,39 @@
#ifndef _X86_64_REGS_H
#define _X86_64_REGS_H
-#if defined(__ASSEMBLY__) || defined(__FRAME_OFFSETS)
-#define R15 0
-#define R14 8
-#define R13 16
-#define R12 24
-#define RBP 36
-#define RBX 40
-/* arguments: interrupts/hypercalls only save upto here*/
-#define R11 48
-#define R10 56
-#define R9 64
-#define R8 72
-#define RAX 80
-#define RCX 88
-#define RDX 96
-#define RSI 104
-#define RDI 112
-#define ORIG_RAX 120 /* = ERROR */
-/* end of arguments */
-/* cpu exception frame or undefined in case of fast hypercall. */
-#define RIP 128
-#define CS 136
-#define EFLAGS 144
-#define RSP 152
-#define SS 160
-#define ARGOFFSET R11
-#endif /* __ASSEMBLY__ */
-
-/* top of stack page */
-#define FRAME_SIZE 168
-
-#define PTRACE_SETOPTIONS 21
-
-/* options set using PTRACE_SETOPTIONS */
-#define PTRACE_O_TRACESYSGOOD 0x00000001
-
-/* Dummy values for ptrace */
-#define FS 1000
-#define GS 1008
-
-#ifndef __ASSEMBLY__
-
-struct xen_regs {
- unsigned long r15;
- unsigned long r14;
- unsigned long r13;
- unsigned long r12;
- unsigned long rbp;
- unsigned long rbx;
-/* arguments: non interrupts/hypercalls only save upto here*/
- unsigned long r11;
- unsigned long r10;
- unsigned long r9;
- unsigned long r8;
- unsigned long rax;
- unsigned long rcx;
- unsigned long rdx;
- unsigned long rsi;
- unsigned long rdi;
- unsigned long orig_rax;
-/* end of arguments */
-/* cpu exception frame or undefined */
- unsigned long rip;
- unsigned long cs;
- unsigned long eflags;
- unsigned long rsp;
- unsigned long ss;
-/* top of stack page */
-};
-
-#endif
-
-/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
-#define PTRACE_GETREGS 12
-#define PTRACE_SETREGS 13
-#define PTRACE_GETFPREGS 14
-#define PTRACE_SETFPREGS 15
-#define PTRACE_GETFPXREGS 18
-#define PTRACE_SETFPXREGS 19
-
-#if !defined(__ASSEMBLY__)
-
-#define instruction_pointer(regs) ((regs)->rip)
-extern void show_regs(struct xen_regs *);
-
-enum {
- EF_CF = 0x00000001,
- EF_PF = 0x00000004,
- EF_AF = 0x00000010,
- EF_ZF = 0x00000040,
- EF_SF = 0x00000080,
- EF_TF = 0x00000100,
- EF_IE = 0x00000200,
- EF_DF = 0x00000400,
- EF_OF = 0x00000800,
- EF_IOPL = 0x00003000,
- EF_IOPL_RING0 = 0x00000000,
- EF_IOPL_RING1 = 0x00001000,
- EF_IOPL_RING2 = 0x00002000,
- EF_NT = 0x00004000, /* nested task */
- EF_RF = 0x00010000, /* resume */
- EF_VM = 0x00020000, /* virtual mode */
- EF_AC = 0x00040000, /* alignment */
- EF_VIF = 0x00080000, /* virtual interrupt */
- EF_VIP = 0x00100000, /* virtual interrupt pending */
- EF_ID = 0x00200000, /* id */
-};
-
-#endif
+#include <asm/types.h>
+
+struct xen_regs
+{
+ u64 r15;
+ u64 r14;
+ u64 r13;
+ u64 r12;
+ union { u64 rbp; u32 ebp; } __attribute__ ((packed));
+ union { u64 rbx; u32 ebx; } __attribute__ ((packed));
+ /* NB. Above here is C callee-saves. */
+ u64 r11;
+ u64 r10;
+ u64 r9;
+ u64 r8;
+ union { u64 rax; u32 eax; } __attribute__ ((packed));
+ union { u64 rcx; u32 ecx; } __attribute__ ((packed));
+ union { u64 rdx; u32 edx; } __attribute__ ((packed));
+ union { u64 rsi; u32 esi; } __attribute__ ((packed));
+ union { u64 rdi; u32 edi; } __attribute__ ((packed));
+ u32 error_code;
+ u32 entry_vector;
+ union { u64 rip; u64 eip; } __attribute__ ((packed));
+ u64 cs;
+ union { u64 rflags; u64 eflags; } __attribute__ ((packed));
+ union { u64 rsp; u64 esp; } __attribute__ ((packed));
+ u64 ss;
+} __attribute__ ((packed));
+
+#define VM86_MODE(_r) ((_r)->eflags & EF_VM)
+#define RING_0(_r) (((_r)->cs & 3) == 0)
+#define RING_1(_r) (((_r)->cs & 3) == 1)
+#define RING_2(_r) (((_r)->cs & 3) == 2)
+#define RING_3(_r) (((_r)->cs & 3) == 3)
#endif
diff --git a/xen/include/asm-x86/x86_64/uaccess.h b/xen/include/asm-x86/x86_64/uaccess.h
index f965c87d32..52789d401e 100644
--- a/xen/include/asm-x86/x86_64/uaccess.h
+++ b/xen/include/asm-x86/x86_64/uaccess.h
@@ -11,10 +11,7 @@
#include <xen/prefetch.h>
#include <asm/page.h>
-/* No user-pointer checking. */
#define __user
-#define __force
-#define __chk_user_ptr(_p) ((void)0)
#define VERIFY_READ 0
#define VERIFY_WRITE 1
@@ -22,122 +19,149 @@
#define __addr_ok(addr) ((unsigned long)(addr) < HYPERVISOR_VIRT_START)
/*
- * Uhhuh, this needs 65-bit arithmetic. We have a carry..
+ * Test whether a block of memory is a valid user space address.
+ * Returns 0 if the range is valid, nonzero otherwise.
+ *
+ * This is equivalent to the following test:
+ * ((u65)addr >= (u65)HYPERVISOR_VIRT_END) ?
+ * (((u65)addr + (u65)size) >= ((u65)1 << 64)) :
+ * (((u65)addr + (u65)size) >= ((u65)HYPERVISOR_VIRT_START))
*/
#define __range_not_ok(addr,size) ({ \
- unsigned long flag,sum; \
- __chk_user_ptr(addr); \
- asm("# range_ok\n\r" \
- "addq %3,%1 ; sbbq %0,%0 ; cmpq %1,%4 ; sbbq $0,%0" \
- :"=&r" (flag), "=r" (sum) \
- :"1" (addr),"g" ((long)(size)),"r" (HYPERVISOR_VIRT_START)); \
- flag; })
+ unsigned long flag,sum; \
+ if ((unsigned long)addr >= HYPERVISOR_VIRT_END) \
+ asm("addq %3,%1 ; sbbq %0,%0" \
+ :"=&r" (flag), "=r" (sum) \
+ :"1" (addr),"g" ((long)(size))); \
+ else \
+ asm("addq %3,%1 ; sbbq %0,%0 ; cmpq %1,%4 ; sbbq $0,%0" \
+ :"=&r" (flag), "=r" (sum) \
+ :"1" (addr),"g" ((long)(size)),"r" (HYPERVISOR_VIRT_START)); \
+ flag; })
#define access_ok(type, addr, size) (__range_not_ok(addr,size) == 0)
#define array_access_ok(type,addr,count,size) \
(likely(sizeof(count) <= 4) /* disallow 64-bit counts */ && \
- access_ok(type,addr,count*size))
+ access_ok(type,addr,(unsigned long)count*(unsigned long)size))
-extern inline int verify_area(int type, const void __user * addr, unsigned long size)
-{
- return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
+extern long __get_user_bad(void);
+extern void __put_user_bad(void);
-/*
- * These are the main single-value transfer routines. They automatically
- * use the right size if we just have the right pointer type.
+/**
+ * get_user: - Get a simple variable from user space.
+ * @x: Variable to store result.
+ * @ptr: Source address, in user space.
*
- * This gets kind of ugly. We want to return _two_ values in "get_user()"
- * and yet we don't want to do any pointers, because that is too much
- * of a performance impact. Thus we have a few rather ugly macros here,
- * and hide all the ugliness from the user.
+ * Context: User context only. This function may sleep.
*
- * The "__xxx" versions of the user access functions are versions that
- * do not verify the address space, that must have been done previously
- * with a separate "access_ok()" call (this is used when we do multiple
- * accesses to the same area of user memory).
+ * This macro copies a single simple variable from user space to kernel
+ * space. It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
*/
+#define get_user(x,ptr) \
+ __get_user_check((x),(ptr),sizeof(*(ptr)))
-extern void __get_user_1(void);
-extern void __get_user_2(void);
-extern void __get_user_4(void);
-extern void __get_user_8(void);
-
-#define __get_user_x(size,ret,x,ptr) \
- __asm__ __volatile__("call __get_user_" #size \
- :"=a" (ret),"=d" (x) \
- :"0" (ptr) \
- :"rbx")
-
-/* Careful: we have to cast the result to the type of the pointer for sign reasons */
-#define get_user(x,ptr) \
-({ long __val_gu; \
- int __ret_gu; \
- __chk_user_ptr(ptr); \
- switch(sizeof (*(ptr))) { \
- case 1: __get_user_x(1,__ret_gu,__val_gu,ptr); break; \
- case 2: __get_user_x(2,__ret_gu,__val_gu,ptr); break; \
- case 4: __get_user_x(4,__ret_gu,__val_gu,ptr); break; \
- case 8: __get_user_x(8,__ret_gu,__val_gu,ptr); break; \
- default: __get_user_bad(); break; \
- } \
- (x) = (__typeof__(*(ptr)))__val_gu; \
- __ret_gu; \
-})
-
-extern void __put_user_1(void);
-extern void __put_user_2(void);
-extern void __put_user_4(void);
-extern void __put_user_8(void);
-
-extern void __put_user_bad(void);
-
-#define __put_user_x(size,ret,x,ptr) \
- __asm__ __volatile__("call __put_user_" #size \
- :"=a" (ret) \
- :"0" (ptr),"d" (x) \
- :"rbx")
-
+/**
+ * put_user: - Write a simple value into user space.
+ * @x: Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space. It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
#define put_user(x,ptr) \
__put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+/**
+ * __get_user: - Get a simple variable from user space, with less checking.
+ * @x: Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space. It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
#define __get_user(x,ptr) \
__get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+
+
+/**
+ * __put_user: - Write a simple value into user space, with less checking.
+ * @x: Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space. It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
#define __put_user(x,ptr) \
__put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
-#define __put_user_nocheck(x,ptr,size) \
-({ \
- int __pu_err; \
- __put_user_size((x),(ptr),(size),__pu_err); \
- __pu_err; \
+#define __put_user_nocheck(x,ptr,size) \
+({ \
+ long __pu_err; \
+ __put_user_size((x),(ptr),(size),__pu_err,-EFAULT); \
+ __pu_err; \
})
+#define __put_user_check(x,ptr,size) \
+({ \
+ long __pu_err = -EFAULT; \
+ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
+ if (__addr_ok(__pu_addr)) \
+ __put_user_size((x),__pu_addr,(size),__pu_err,-EFAULT); \
+ __pu_err; \
+})
-#define __put_user_check(x,ptr,size) \
-({ \
- int __pu_err = -EFAULT; \
- __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
- if (likely(access_ok(VERIFY_WRITE,__pu_addr,size))) \
- __put_user_size((x),__pu_addr,(size),__pu_err); \
- __pu_err; \
-})
-
-#define __put_user_size(x,ptr,size,retval) \
+#define __put_user_size(x,ptr,size,retval,errret) \
do { \
retval = 0; \
- __chk_user_ptr(ptr); \
switch (size) { \
- case 1: __put_user_asm(x,ptr,retval,"b","b","iq",-EFAULT); break;\
- case 2: __put_user_asm(x,ptr,retval,"w","w","ir",-EFAULT); break;\
- case 4: __put_user_asm(x,ptr,retval,"l","k","ir",-EFAULT); break;\
- case 8: __put_user_asm(x,ptr,retval,"q","","ir",-EFAULT); break;\
- default: __put_user_bad(); \
+ case 1: __put_user_asm(x,ptr,retval,"b","b","iq",errret);break; \
+ case 2: __put_user_asm(x,ptr,retval,"w","w","ir",errret);break; \
+ case 4: __put_user_asm(x,ptr,retval,"l","k","ir",errret);break; \
+ case 8: __put_user_asm(x,ptr,retval,"q","","ir",errret);break; \
+ default: __put_user_bad(); \
} \
} while (0)
-/* FIXME: this hack is definitely wrong -AK */
struct __large_struct { unsigned long buf[100]; };
#define __m(x) (*(struct __large_struct *)(x))
@@ -146,178 +170,139 @@ struct __large_struct { unsigned long buf[100]; };
* we do not write to any memory gcc knows about, so there are no
* aliasing issues.
*/
-#define __put_user_asm(x, addr, err, itype, rtype, ltype, errno) \
- __asm__ __volatile__( \
- "1: mov"itype" %"rtype"1,%2\n" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- "3: mov %3,%0\n" \
- " jmp 2b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 8\n" \
- " .quad 1b,3b\n" \
- ".previous" \
- : "=r"(err) \
- : ltype (x), "m"(__m(addr)), "i"(errno), "0"(err))
-
+#define __put_user_asm(x, addr, err, itype, rtype, ltype, errret) \
+ __asm__ __volatile__( \
+ "1: mov"itype" %"rtype"1,%2\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: mov %3,%0\n" \
+ " jmp 2b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 8\n" \
+ " .quad 1b,3b\n" \
+ ".previous" \
+ : "=r"(err) \
+ : ltype (x), "m"(__m(addr)), "i"(errret), "0"(err))
#define __get_user_nocheck(x,ptr,size) \
({ \
- int __gu_err; \
- long __gu_val; \
- __get_user_size(__gu_val,(ptr),(size),__gu_err); \
+ long __gu_err, __gu_val; \
+ __get_user_size(__gu_val,(ptr),(size),__gu_err,-EFAULT);\
(x) = (__typeof__(*(ptr)))__gu_val; \
__gu_err; \
})
-extern int __get_user_bad(void);
-
-#define __get_user_size(x,ptr,size,retval) \
+#define __get_user_check(x,ptr,size) \
+({ \
+ long __gu_err, __gu_val; \
+ __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
+ __get_user_size(__gu_val,__gu_addr,(size),__gu_err,-EFAULT); \
+ (x) = (__typeof__(*(ptr)))__gu_val; \
+ if (!__addr_ok(__gu_addr)) __gu_err = -EFAULT; \
+ __gu_err; \
+})
+
+#define __get_user_size(x,ptr,size,retval,errret) \
do { \
retval = 0; \
- __chk_user_ptr(ptr); \
switch (size) { \
- case 1: __get_user_asm(x,ptr,retval,"b","b","=q",-EFAULT); break;\
- case 2: __get_user_asm(x,ptr,retval,"w","w","=r",-EFAULT); break;\
- case 4: __get_user_asm(x,ptr,retval,"l","k","=r",-EFAULT); break;\
- case 8: __get_user_asm(x,ptr,retval,"q","","=r",-EFAULT); break;\
- default: (x) = __get_user_bad(); \
+ case 1: __get_user_asm(x,ptr,retval,"b","b","=q",errret);break; \
+ case 2: __get_user_asm(x,ptr,retval,"w","w","=r",errret);break; \
+ case 4: __get_user_asm(x,ptr,retval,"l","k","=r",errret);break; \
+ case 8: __get_user_asm(x,ptr,retval,"q","","=r",errret); break; \
+ default: (x) = __get_user_bad(); \
} \
} while (0)
-#define __get_user_asm(x, addr, err, itype, rtype, ltype, errno) \
- __asm__ __volatile__( \
- "1: mov"itype" %2,%"rtype"1\n" \
- "2:\n" \
- ".section .fixup,\"ax\"\n" \
- "3: mov %3,%0\n" \
- " xor"itype" %"rtype"1,%"rtype"1\n" \
- " jmp 2b\n" \
- ".previous\n" \
- ".section __ex_table,\"a\"\n" \
- " .align 8\n" \
- " .quad 1b,3b\n" \
- ".previous" \
- : "=r"(err), ltype (x) \
- : "m"(__m(addr)), "i"(errno), "0"(err))
+#define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \
+ __asm__ __volatile__( \
+ "1: mov"itype" %2,%"rtype"1\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: mov %3,%0\n" \
+ " xor"itype" %"rtype"1,%"rtype"1\n" \
+ " jmp 2b\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 8\n" \
+ " .quad 1b,3b\n" \
+ ".previous" \
+ : "=r"(err), ltype (x) \
+ : "m"(__m(addr)), "i"(errret), "0"(err))
+
/*
* Copy To/From Userspace
*/
/* Handles exceptions in both to and from, but doesn't do access_ok */
-extern unsigned long copy_user_generic(void *to, const void *from, unsigned len);
+unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned n);
+unsigned long __copy_from_user_ll(void *to, const void __user *from, unsigned n);
-extern unsigned long copy_to_user(void __user *to, const void *from, unsigned len);
-extern unsigned long copy_from_user(void *to, const void __user *from, unsigned len);
-extern unsigned long copy_in_user(void __user *to, const void __user *from, unsigned len);
+unsigned long copy_to_user(void __user *to, const void *from, unsigned len);
+unsigned long copy_from_user(void *to, const void __user *from, unsigned len);
static always_inline int __copy_from_user(void *dst, const void __user *src, unsigned size)
{
- int ret = 0;
- if (!__builtin_constant_p(size))
- return copy_user_generic(dst,(__force void *)src,size);
- switch (size) {
- case 1:__get_user_asm(*(u8*)dst,(u8 __user *)src,ret,"b","b","=q",1);
- return ret;
- case 2:__get_user_asm(*(u16*)dst,(u16 __user *)src,ret,"w","w","=r",2);
- return ret;
- case 4:__get_user_asm(*(u32*)dst,(u32 __user *)src,ret,"l","k","=r",4);
- return ret;
- case 8:__get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",8);
- return ret;
- case 10:
- __get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",16);
- if (unlikely(ret)) return ret;
- __get_user_asm(*(u16*)(8+(char*)dst),(u16 __user *)(8+(char __user *)src),ret,"w","w","=r",2);
- return ret;
- case 16:
- __get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",16);
- if (unlikely(ret)) return ret;
- __get_user_asm(*(u64*)(8+(char*)dst),(u64 __user *)(8+(char __user *)src),ret,"q","","=r",8);
- return ret;
- default:
- return copy_user_generic(dst,(__force void *)src,size);
- }
+ int ret = 0;
+ if (!__builtin_constant_p(size))
+ return __copy_from_user_ll(dst,(void *)src,size);
+ switch (size) {
+ case 1:__get_user_asm(*(u8*)dst,(u8 __user *)src,ret,"b","b","=q",1);
+ return ret;
+ case 2:__get_user_asm(*(u16*)dst,(u16 __user *)src,ret,"w","w","=r",2);
+ return ret;
+ case 4:__get_user_asm(*(u32*)dst,(u32 __user *)src,ret,"l","k","=r",4);
+ return ret;
+ case 8:__get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",8);
+ return ret;
+ case 10:
+ __get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",16);
+ if (unlikely(ret)) return ret;
+ __get_user_asm(*(u16*)(8+(char*)dst),(u16 __user *)(8+(char __user *)src),ret,"w","w","=r",2);
+ return ret;
+ case 16:
+ __get_user_asm(*(u64*)dst,(u64 __user *)src,ret,"q","","=r",16);
+ if (unlikely(ret)) return ret;
+ __get_user_asm(*(u64*)(8+(char*)dst),(u64 __user *)(8+(char __user *)src),ret,"q","","=r",8);
+ return ret;
+ default:
+ return __copy_from_user_ll(dst,(void *)src,size);
+ }
}
static always_inline int __copy_to_user(void __user *dst, const void *src, unsigned size)
{
- int ret = 0;
- if (!__builtin_constant_p(size))
- return copy_user_generic((__force void *)dst,src,size);
- switch (size) {
- case 1:__put_user_asm(*(u8*)src,(u8 __user *)dst,ret,"b","b","iq",1);
- return ret;
- case 2:__put_user_asm(*(u16*)src,(u16 __user *)dst,ret,"w","w","ir",2);
- return ret;
- case 4:__put_user_asm(*(u32*)src,(u32 __user *)dst,ret,"l","k","ir",4);
- return ret;
- case 8:__put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",8);
- return ret;
- case 10:
- __put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",10);
- if (unlikely(ret)) return ret;
- asm("":::"memory");
- __put_user_asm(4[(u16*)src],4+(u16 __user *)dst,ret,"w","w","ir",2);
- return ret;
- case 16:
- __put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",16);
- if (unlikely(ret)) return ret;
- asm("":::"memory");
- __put_user_asm(1[(u64*)src],1+(u64 __user *)dst,ret,"q","","ir",8);
- return ret;
- default:
- return copy_user_generic((__force void *)dst,src,size);
- }
-}
-
-
-static always_inline int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
-{
- int ret = 0;
- if (!__builtin_constant_p(size))
- return copy_user_generic((__force void *)dst,(__force void *)src,size);
- switch (size) {
- case 1: {
- u8 tmp;
- __get_user_asm(tmp,(u8 __user *)src,ret,"b","b","=q",1);
- if (likely(!ret))
- __put_user_asm(tmp,(u8 __user *)dst,ret,"b","b","iq",1);
- return ret;
- }
- case 2: {
- u16 tmp;
- __get_user_asm(tmp,(u16 __user *)src,ret,"w","w","=r",2);
- if (likely(!ret))
- __put_user_asm(tmp,(u16 __user *)dst,ret,"w","w","ir",2);
- return ret;
- }
-
- case 4: {
- u32 tmp;
- __get_user_asm(tmp,(u32 __user *)src,ret,"l","k","=r",4);
- if (likely(!ret))
- __put_user_asm(tmp,(u32 __user *)dst,ret,"l","k","ir",4);
- return ret;
- }
- case 8: {
- u64 tmp;
- __get_user_asm(tmp,(u64 __user *)src,ret,"q","","=r",8);
- if (likely(!ret))
- __put_user_asm(tmp,(u64 __user *)dst,ret,"q","","ir",8);
- return ret;
- }
- default:
- return copy_user_generic((__force void *)dst,(__force void *)src,size);
- }
+ int ret = 0;
+ if (!__builtin_constant_p(size))
+ return __copy_to_user_ll((void *)dst,src,size);
+ switch (size) {
+ case 1:__put_user_asm(*(u8*)src,(u8 __user *)dst,ret,"b","b","iq",1);
+ return ret;
+ case 2:__put_user_asm(*(u16*)src,(u16 __user *)dst,ret,"w","w","ir",2);
+ return ret;
+ case 4:__put_user_asm(*(u32*)src,(u32 __user *)dst,ret,"l","k","ir",4);
+ return ret;
+ case 8:__put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",8);
+ return ret;
+ case 10:
+ __put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",10);
+ if (unlikely(ret)) return ret;
+ asm("":::"memory");
+ __put_user_asm(4[(u16*)src],4+(u16 __user *)dst,ret,"w","w","ir",2);
+ return ret;
+ case 16:
+ __put_user_asm(*(u64*)src,(u64 __user *)dst,ret,"q","","ir",16);
+ if (unlikely(ret)) return ret;
+ asm("":::"memory");
+ __put_user_asm(1[(u64*)src],1+(u64 __user *)dst,ret,"q","","ir",8);
+ return ret;
+ default:
+ return __copy_to_user_ll((void *)dst,src,size);
+ }
}
-long strncpy_from_user(char *dst, const char __user *src, long count);
-long __strncpy_from_user(char *dst, const char __user *src, long count);
-long strnlen_user(const char __user *str, long n);
-long strlen_user(const char __user *str);
unsigned long clear_user(void __user *mem, unsigned long len);
unsigned long __clear_user(void __user *mem, unsigned long len);
diff --git a/xen/include/public/arch-x86_32.h b/xen/include/public/arch-x86_32.h
index f3d402d2b3..cb2af27582 100644
--- a/xen/include/public/arch-x86_32.h
+++ b/xen/include/public/arch-x86_32.h
@@ -49,13 +49,17 @@
*/
#define FLAT_RING1_CS 0x0819 /* GDT index 259 */
#define FLAT_RING1_DS 0x0821 /* GDT index 260 */
+#define FLAT_RING1_SS 0x0821 /* GDT index 260 */
#define FLAT_RING3_CS 0x082b /* GDT index 261 */
#define FLAT_RING3_DS 0x0833 /* GDT index 262 */
+#define FLAT_RING3_SS 0x0833 /* GDT index 262 */
#define FLAT_GUESTOS_CS FLAT_RING1_CS
#define FLAT_GUESTOS_DS FLAT_RING1_DS
+#define FLAT_GUESTOS_SS FLAT_RING1_SS
#define FLAT_USER_CS FLAT_RING3_CS
#define FLAT_USER_DS FLAT_RING3_DS
+#define FLAT_USER_SS FLAT_RING3_SS
/* And the trap vector is... */
#define TRAP_INSTR "int $0x82"
@@ -119,6 +123,7 @@ typedef u64 tsc_timestamp_t; /* RDTSC timestamp */
*/
typedef struct {
#define ECF_I387_VALID (1<<0)
+#define ECF_VMX_GUEST (2<<0)
unsigned long flags;
execution_context_t cpu_ctxt; /* User-level CPU registers */
char fpu_ctxt[256]; /* User-level FPU registers */
@@ -136,11 +141,13 @@ typedef struct {
} PACKED full_execution_context_t;
typedef struct {
- u64 mfn_to_pfn_start; /* MFN of start of m2p table */
- u64 pfn_to_mfn_frame_list; /* MFN of a table of MFNs that
- make up p2m table */
+ /* MFN of a table of MFNs that make up p2m table */
+ u64 pfn_to_mfn_frame_list;
} PACKED arch_shared_info_t;
+typedef struct {
+} PACKED arch_vcpu_info_t;
+
#define ARCH_HAS_FAST_TRAP
#endif
diff --git a/xen/include/public/arch-x86_64.h b/xen/include/public/arch-x86_64.h
index abba7bdf12..4ab9bcca79 100644
--- a/xen/include/public/arch-x86_64.h
+++ b/xen/include/public/arch-x86_64.h
@@ -30,7 +30,7 @@
* NB. The reserved range is inclusive (that is, both FIRST_RESERVED_GDT_ENTRY
* and LAST_RESERVED_GDT_ENTRY are reserved).
*/
-#define NR_RESERVED_GDT_ENTRIES 40
+#define NR_RESERVED_GDT_ENTRIES 72
#define FIRST_RESERVED_GDT_ENTRY 256
#define LAST_RESERVED_GDT_ENTRY \
(FIRST_RESERVED_GDT_ENTRY + NR_RESERVED_GDT_ENTRIES - 1)
@@ -44,22 +44,42 @@
#define FLAT_RING3_CS32 0x0823 /* GDT index 260 */
#define FLAT_RING3_CS64 0x082b /* GDT index 261 */
-#define FLAT_RING3_DS 0x0833 /* GDT index 262 */
-
-#define FLAT_GUESTOS_DS FLAT_RING3_DS
-#define FLAT_GUESTOS_CS FLAT_RING3_CS64
+#define FLAT_RING3_DS32 0x0833 /* GDT index 262 */
+#define FLAT_RING3_DS64 0x0000 /* NULL selector */
+#define FLAT_RING3_SS32 0x0833 /* GDT index 262 */
+#define FLAT_RING3_SS64 0x0833 /* GDT index 262 */
+
+#define FLAT_GUESTOS_DS64 FLAT_RING3_DS64
+#define FLAT_GUESTOS_DS32 FLAT_RING3_DS32
+#define FLAT_GUESTOS_DS FLAT_GUESTOS_DS64
+#define FLAT_GUESTOS_CS64 FLAT_RING3_CS64
#define FLAT_GUESTOS_CS32 FLAT_RING3_CS32
-
-#define FLAT_USER_DS FLAT_RING3_DS
-#define FLAT_USER_CS FLAT_RING3_CS64
-#define FLAT_USER_CS32 FLAT_RING3_CS32
+#define FLAT_GUESTOS_CS FLAT_GUESTOS_CS64
+#define FLAT_GUESTOS_SS64 FLAT_RING3_SS64
+#define FLAT_GUESTOS_SS32 FLAT_RING3_SS32
+#define FLAT_GUESTOS_SS FLAT_GUESTOS_SS64
+
+#define FLAT_USER_DS64 FLAT_RING3_DS64
+#define FLAT_USER_DS32 FLAT_RING3_DS32
+#define FLAT_USER_DS FLAT_USER_DS64
+#define FLAT_USER_CS64 FLAT_RING3_CS64
+#define FLAT_USER_CS32 FLAT_RING3_CS32
+#define FLAT_USER_CS FLAT_USER_CS64
+#define FLAT_USER_SS64 FLAT_RING3_SS64
+#define FLAT_USER_SS32 FLAT_RING3_SS32
+#define FLAT_USER_SS FLAT_USER_SS64
/* And the trap vector is... */
#define TRAP_INSTR "syscall"
+#ifndef HYPERVISOR_VIRT_START
+#define HYPERVISOR_VIRT_START (0xFFFF800000000000UL)
+#define HYPERVISOR_VIRT_END (0xFFFF880000000000UL)
+#endif
+
/* The machine->physical mapping table starts at this address, read-only. */
#ifndef machine_to_phys_mapping
-#define machine_to_phys_mapping ((unsigned long *)0xffff810000000000ULL)
+#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
#endif
#ifndef __ASSEMBLY__
@@ -89,22 +109,27 @@ typedef struct
unsigned long r14;
unsigned long r13;
unsigned long r12;
- unsigned long rbp;
- unsigned long rbx;
+ union { unsigned long rbp, ebp; } PACKED;
+ union { unsigned long rbx, ebx; } PACKED;
unsigned long r11;
unsigned long r10;
unsigned long r9;
unsigned long r8;
- unsigned long rax;
- unsigned long rcx;
- unsigned long rdx;
- unsigned long rsi;
- unsigned long rdi;
- unsigned long rip;
+ union { unsigned long rax, eax; } PACKED;
+ union { unsigned long rcx, ecx; } PACKED;
+ union { unsigned long rdx, edx; } PACKED;
+ union { unsigned long rsi, esi; } PACKED;
+ union { unsigned long rdi, edi; } PACKED;
+ unsigned long _unused;
+ union { unsigned long rip, eip; } PACKED;
unsigned long cs;
- unsigned long eflags;
- unsigned long rsp;
+ union { unsigned long rflags, eflags; } PACKED;
+ union { unsigned long rsp, esp; } PACKED;
unsigned long ss;
+ unsigned long es;
+ unsigned long ds;
+ unsigned long fs;
+ unsigned long gs;
} PACKED execution_context_t;
typedef u64 tsc_timestamp_t; /* RDTSC timestamp */
@@ -115,6 +140,7 @@ typedef u64 tsc_timestamp_t; /* RDTSC timestamp */
*/
typedef struct {
#define ECF_I387_VALID (1<<0)
+#define ECF_VMX_GUEST (2<<0)
unsigned long flags;
execution_context_t cpu_ctxt; /* User-level CPU registers */
char fpu_ctxt[512]; /* User-level FPU registers */
@@ -131,11 +157,13 @@ typedef struct {
} PACKED full_execution_context_t;
typedef struct {
- u64 mfn_to_pfn_start; /* MFN of start of m2p table */
- u64 pfn_to_mfn_frame_list; /* MFN of a table of MFNs that
- make up p2m table */
+ /* MFN of a table of MFNs that make up p2m table */
+ u64 pfn_to_mfn_frame_list;
} PACKED arch_shared_info_t;
+typedef struct {
+} PACKED arch_vcpu_info_t;
+
#endif /* !__ASSEMBLY__ */
#endif
diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h
index eb4766192d..58b49a7564 100644
--- a/xen/include/public/dom0_ops.h
+++ b/xen/include/public/dom0_ops.h
@@ -19,7 +19,7 @@
* This makes sure that old versions of dom0 tools will stop working in a
* well-defined way (rather than crashing the machine, for instance).
*/
-#define DOM0_INTERFACE_VERSION 0xAAAA001A
+#define DOM0_INTERFACE_VERSION 0xAAAA1001
/************************************************************************/
@@ -85,7 +85,7 @@ typedef struct {
typedef struct {
/* IN variables. */
domid_t domain; /* 0 */ /* NB. IN/OUT variable. */
- u16 __pad;
+ u16 exec_domain;
/* OUT variables. */
#define DOMFLAGS_DYING (1<<0) /* Domain is scheduled to die. */
#define DOMFLAGS_CRASHED (1<<1) /* Crashed domain; frozen for postmortem. */
@@ -208,7 +208,7 @@ typedef struct {
typedef struct {
/* IN variables. */
domid_t domain; /* 0 */
- u16 __pad;
+ u16 exec_domain;
s32 cpu; /* 4: -1 implies unpin */
} PACKED dom0_pincpudomain_t; /* 8 bytes */
diff --git a/xen/include/public/event_channel.h b/xen/include/public/event_channel.h
index 284326d9b6..8d1025ff29 100644
--- a/xen/include/public/event_channel.h
+++ b/xen/include/public/event_channel.h
@@ -128,6 +128,7 @@ typedef struct {
#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */
#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */
#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */
+#define EVTCHNSTAT_ipi 5 /* Channel is bound to a virtual IPI line */
u32 status; /* 8 */
union { /* 12 */
struct {
@@ -140,9 +141,22 @@ typedef struct {
} PACKED interdomain; /* EVTCHNSTAT_interdomain */
u32 pirq; /* EVTCHNSTAT_pirq */ /* 12 */
u32 virq; /* EVTCHNSTAT_virq */ /* 12 */
+ u32 ipi_edom; /* EVTCHNSTAT_ipi */ /* 12 */
} PACKED u;
} PACKED evtchn_status_t; /* 20 bytes */
+/*
+ * EVTCHNOP_bind_ipi: Bind a local event channel to receive events.
+ */
+#define EVTCHNOP_bind_ipi 7
+typedef struct {
+ /* IN parameters. */
+ u32 ipi_edom; /* 0 */
+ /* OUT parameters. */
+ u32 port; /* 4 */
+} PACKED evtchn_bind_ipi_t; /* 8 bytes */
+
+
typedef struct {
u32 cmd; /* EVTCHNOP_* */ /* 0 */
u32 __reserved; /* 4 */
@@ -154,6 +168,7 @@ typedef struct {
evtchn_close_t close;
evtchn_send_t send;
evtchn_status_t status;
+ evtchn_bind_ipi_t bind_ipi;
u8 __dummy[24];
} PACKED u;
} PACKED evtchn_op_t; /* 32 bytes */
diff --git a/xen/include/public/io/blkif.h b/xen/include/public/io/blkif.h
index 8cd3696eb6..4108f4e545 100644
--- a/xen/include/public/io/blkif.h
+++ b/xen/include/public/io/blkif.h
@@ -9,6 +9,8 @@
#ifndef __XEN_PUBLIC_IO_BLKIF_H__
#define __XEN_PUBLIC_IO_BLKIF_H__
+#include <asm-xen/xen-public/io/ring.h>
+
#define blkif_vdev_t u16
#define blkif_sector_t u64
@@ -52,27 +54,11 @@ typedef struct {
#define BLKIF_RSP_OKAY 0 /* non-specific 'okay' */
/*
- * We use a special capitalised type name because it is _essential_ that all
- * arithmetic on indexes is done on an integer type of the correct size.
- */
-typedef u32 BLKIF_RING_IDX;
-
-/*
- * Ring indexes are 'free running'. That is, they are not stored modulo the
- * size of the ring buffer. The following macro converts a free-running counter
- * into a value that can directly index a ring-buffer array.
+ * Generate blkif ring structures and types.
*/
-#define MASK_BLKIF_IDX(_i) ((_i)&(BLKIF_RING_SIZE-1))
-
-typedef struct {
- BLKIF_RING_IDX req_prod; /* 0: Request producer. Updated by front-end. */
- BLKIF_RING_IDX resp_prod; /* 4: Response producer. Updated by back-end. */
- union { /* 8 */
- blkif_request_t req;
- blkif_response_t resp;
- } PACKED ring[BLKIF_RING_SIZE];
-} PACKED blkif_ring_t;
+#define BLKIF_RING RING_PARAMS(blkif_request_t, blkif_response_t, PAGE_SIZE)
+DEFINE_RING_TYPES(blkif, BLKIF_RING);
/*
* BLKIF_OP_PROBE:
diff --git a/xen/include/public/io/domain_controller.h b/xen/include/public/io/domain_controller.h
index c248f21419..c2abbc16be 100644
--- a/xen/include/public/io/domain_controller.h
+++ b/xen/include/public/io/domain_controller.h
@@ -10,6 +10,7 @@
#ifndef __XEN_PUBLIC_IO_DOMAIN_CONTROLLER_H__
#define __XEN_PUBLIC_IO_DOMAIN_CONTROLLER_H__
+#include "ring.h"
/*
* Reason codes for SCHEDOP_shutdown. These are opaque to Xen but may be
@@ -33,15 +34,24 @@ typedef struct {
u8 msg[60]; /* 4: type-specific message data */
} PACKED control_msg_t; /* 64 bytes */
+/* These are used by the control message deferred ring. */
#define CONTROL_RING_SIZE 8
typedef u32 CONTROL_RING_IDX;
#define MASK_CONTROL_IDX(_i) ((_i)&(CONTROL_RING_SIZE-1))
+/*
+ * Generate control ring structures and types.
+ *
+ * CONTROL_RING_MEM is currently an 8-slot ring of ctrl_msg_t structs and
+ * two 32-bit counters: (64 * 8) + (2 * 4) = 520
+ */
+#define CONTROL_RING_MEM 520
+#define CTRL_RING RING_PARAMS(control_msg_t, control_msg_t, CONTROL_RING_MEM)
+DEFINE_RING_TYPES(ctrl, CTRL_RING);
+
typedef struct {
- control_msg_t tx_ring[CONTROL_RING_SIZE]; /* 0: guest -> controller */
- control_msg_t rx_ring[CONTROL_RING_SIZE]; /* 512: controller -> guest */
- CONTROL_RING_IDX tx_req_prod, tx_resp_prod; /* 1024, 1028 */
- CONTROL_RING_IDX rx_req_prod, rx_resp_prod; /* 1032, 1036 */
+ ctrl_sring_t tx_ring; /* 0: guest -> controller */
+ ctrl_sring_t rx_ring; /* 520: controller -> guest */
} PACKED control_if_t; /* 1040 bytes */
/*
@@ -54,7 +64,8 @@ typedef struct {
#define CMSG_NETIF_FE 4 /* Network-device frontend */
#define CMSG_SHUTDOWN 6 /* Shutdown messages */
#define CMSG_MEM_REQUEST 7 /* Memory reservation reqs */
-
+#define CMSG_USBIF_BE 8 /* USB controller backend */
+#define CMSG_USBIF_FE 9 /* USB controller frontend */
/******************************************************************************
* CONSOLE DEFINITIONS
@@ -478,9 +489,11 @@ typedef struct {
u32 netif_handle; /* 4: Domain-specific interface handle. */
u8 mac[6]; /* 8 */
u16 __pad1; /* 14 */
+ u8 be_mac[6]; /* 16 */
+ u16 __pad2; /* 22 */
/* OUT */
- u32 status; /* 16 */
-} PACKED netif_be_create_t; /* 20 bytes */
+ u32 status; /* 24 */
+} PACKED netif_be_create_t; /* 28 bytes */
/*
* CMSG_NETIF_BE_DESTROY:
@@ -544,6 +557,208 @@ typedef struct {
} PACKED netif_be_driver_status_t; /* 4 bytes */
+
+/******************************************************************************
+ * USB-INTERFACE FRONTEND DEFINITIONS
+ */
+
+/* Messages from domain controller to guest. */
+#define CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED 0
+
+/* Messages from guest to domain controller. */
+#define CMSG_USBIF_FE_DRIVER_STATUS_CHANGED 32
+#define CMSG_USBIF_FE_INTERFACE_CONNECT 33
+#define CMSG_USBIF_FE_INTERFACE_DISCONNECT 34
+/*
+ * CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED:
+ * Notify a guest about a status change on one of its block interfaces.
+ * If the interface is DESTROYED or DOWN then the interface is disconnected:
+ * 1. The shared-memory frame is available for reuse.
+ * 2. Any unacknowledged messages pending on the interface were dropped.
+ */
+#define USBIF_INTERFACE_STATUS_DESTROYED 0 /* Interface doesn't exist. */
+#define USBIF_INTERFACE_STATUS_DISCONNECTED 1 /* Exists but is disconnected. */
+#define USBIF_INTERFACE_STATUS_CONNECTED 2 /* Exists and is connected. */
+typedef struct {
+ u32 status; /* 0 */
+ u16 evtchn; /* 4: (only if status == BLKIF_INTERFACE_STATUS_CONNECTED). */
+ domid_t domid; /* 6: status != BLKIF_INTERFACE_STATUS_DESTROYED */
+ u32 bandwidth; /* 8 */
+ u32 num_ports; /* 12 */
+} PACKED usbif_fe_interface_status_changed_t; /* 12 bytes */
+
+/*
+ * CMSG_USBIF_FE_DRIVER_STATUS_CHANGED:
+ * Notify the domain controller that the front-end driver is DOWN or UP.
+ * When the driver goes DOWN then the controller will send no more
+ * status-change notifications.
+ * If the driver goes DOWN while interfaces are still UP, the domain
+ * will automatically take the interfaces DOWN.
+ *
+ * NB. The controller should not send an INTERFACE_STATUS_CHANGED message
+ * for interfaces that are active when it receives an UP notification. We
+ * expect that the frontend driver will query those interfaces itself.
+ */
+#define USBIF_DRIVER_STATUS_DOWN 0
+#define USBIF_DRIVER_STATUS_UP 1
+typedef struct {
+ /* IN */
+ u32 status; /* 0: USBIF_DRIVER_STATUS_??? */
+} PACKED usbif_fe_driver_status_changed_t; /* 4 bytes */
+
+/*
+ * CMSG_USBIF_FE_INTERFACE_CONNECT:
+ * If successful, the domain controller will acknowledge with a
+ * STATUS_CONNECTED message.
+ */
+typedef struct {
+ u32 __pad;
+ memory_t shmem_frame; /* 8 */
+ MEMORY_PADDING;
+} PACKED usbif_fe_interface_connect_t; /* 16 bytes */
+
+/*
+ * CMSG_BLKIF_FE_INTERFACE_DISCONNECT:
+ * If successful, the domain controller will acknowledge with a
+ * STATUS_DISCONNECTED message.
+ */
+typedef struct {} PACKED usbif_fe_interface_disconnect_t; /* 4 bytes */
+
+
+/******************************************************************************
+ * USB-INTERFACE BACKEND DEFINITIONS
+ */
+
+/* Messages from domain controller. */
+#define CMSG_USBIF_BE_CREATE 0 /* Create a new block-device interface. */
+#define CMSG_USBIF_BE_DESTROY 1 /* Destroy a block-device interface. */
+#define CMSG_USBIF_BE_CONNECT 2 /* Connect i/f to remote driver. */
+#define CMSG_USBIF_BE_DISCONNECT 3 /* Disconnect i/f from remote driver. */
+#define CMSG_USBIF_BE_CLAIM_PORT 4 /* Claim host port for a domain. */
+#define CMSG_USBIF_BE_RELEASE_PORT 5 /* Release host port. */
+/* Messages to domain controller. */
+#define CMSG_USBIF_BE_DRIVER_STATUS_CHANGED 32
+
+/* Non-specific 'okay' return. */
+#define USBIF_BE_STATUS_OKAY 0
+/* Non-specific 'error' return. */
+#define USBIF_BE_STATUS_ERROR 1
+/* The following are specific error returns. */
+#define USBIF_BE_STATUS_INTERFACE_EXISTS 2
+#define USBIF_BE_STATUS_INTERFACE_NOT_FOUND 3
+#define USBIF_BE_STATUS_INTERFACE_CONNECTED 4
+#define USBIF_BE_STATUS_OUT_OF_MEMORY 7
+#define USBIF_BE_STATUS_MAPPING_ERROR 9
+
+/* This macro can be used to create an array of descriptive error strings. */
+#define USBIF_BE_STATUS_ERRORS { \
+ "Okay", \
+ "Non-specific error", \
+ "Interface already exists", \
+ "Interface not found", \
+ "Interface is still connected", \
+ "Out of memory", \
+ "Could not map domain memory" }
+
+/*
+ * CMSG_USBIF_BE_CREATE:
+ * When the driver sends a successful response then the interface is fully
+ * created. The controller will send a DOWN notification to the front-end
+ * driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Domain attached to new interface. */
+ u16 __pad;
+ /* OUT */
+ u32 status; /* 8 */
+} PACKED usbif_be_create_t; /* 12 bytes */
+
+/*
+ * CMSG_USBIF_BE_DESTROY:
+ * When the driver sends a successful response then the interface is fully
+ * torn down. The controller will send a DESTROYED notification to the
+ * front-end driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Identify interface to be destroyed. */
+ u16 __pad;
+ /* OUT */
+ u32 status; /* 8 */
+} PACKED usbif_be_destroy_t; /* 12 bytes */
+
+/*
+ * CMSG_USBIF_BE_CONNECT:
+ * When the driver sends a successful response then the interface is fully
+ * connected. The controller will send a CONNECTED notification to the
+ * front-end driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Domain attached to new interface. */
+ u16 __pad;
+ memory_t shmem_frame; /* 8: Page cont. shared comms window. */
+ MEMORY_PADDING;
+ u32 evtchn; /* 16: Event channel for notifications. */
+ u32 bandwidth; /* 20: Bandwidth allocated for isoch / int - us
+ * per 1ms frame (ie between 0 and 900 or 800
+ * depending on USB version). */
+ /* OUT */
+ u32 status; /* 24 */
+} PACKED usbif_be_connect_t; /* 28 bytes */
+
+/*
+ * CMSG_USBIF_BE_DISCONNECT:
+ * When the driver sends a successful response then the interface is fully
+ * disconnected. The controller will send a DOWN notification to the front-end
+ * driver.
+ */
+typedef struct {
+ /* IN */
+ domid_t domid; /* 0: Domain attached to new interface. */
+ u16 __pad;
+ /* OUT */
+ u32 status; /* 8 */
+} PACKED usbif_be_disconnect_t; /* 12 bytes */
+
+/*
+ * CMSG_USBIF_BE_DRIVER_STATUS_CHANGED:
+ * Notify the domain controller that the back-end driver is DOWN or UP.
+ * If the driver goes DOWN while interfaces are still UP, the controller
+ * will automatically send DOWN notifications.
+ */
+typedef struct {
+ u32 status; /* 0: USBIF_DRIVER_STATUS_??? */
+} PACKED usbif_be_driver_status_changed_t; /* 4 bytes */
+
+#define USB_PATH_LEN 16
+
+/*
+ * CMSG_USBIF_BE_CLAIM_PORT:
+ * Instruct the backend driver to claim any device plugged into the specified
+ * host port and to allow the specified domain to control that port.
+ */
+typedef struct
+{
+ /* IN */
+ domid_t domid; /* 0: which domain */
+ u32 usbif_port; /* 6: port on the virtual root hub */
+ u32 status; /* 10: status of operation */
+ char path[USB_PATH_LEN]; /* Currently specified in the Linux style - may need to be
+ * converted to some OS-independent format at some stage. */
+} PACKED usbif_be_claim_port_t;
+
+/*
+ * CMSG_USBIF_BE_RELEASE_PORT:
+ * Instruct the backend driver to release any device plugged into the specified
+ * host port.
+ */
+typedef struct
+{
+ char path[USB_PATH_LEN];
+} PACKED usbif_be_release_port_t;
+
/******************************************************************************
* SHUTDOWN DEFINITIONS
*/
diff --git a/xen/include/public/io/ioreq.h b/xen/include/public/io/ioreq.h
new file mode 100644
index 0000000000..ac47cd9ec5
--- /dev/null
+++ b/xen/include/public/io/ioreq.h
@@ -0,0 +1,60 @@
+/*
+ * ioreq.h: I/O request definitions for device models
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, 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 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.
+ *
+ */
+
+#ifndef _IOREQ_H_
+#define _IOREQ_H_
+
+#define IOREQ_READ 1
+#define IOREQ_WRITE 0
+
+#define STATE_INVALID 0
+#define STATE_IOREQ_READY 1
+#define STATE_IOREQ_INPROCESS 2
+#define STATE_IORESP_READY 3
+
+#define IOPACKET_PORT 2
+
+/* VMExit dispatcher should cooperate with instruction decoder to
+ prepare this structure and notify service OS and DM by sending
+ virq */
+typedef struct {
+ u64 addr; /* physical address */
+ u64 size; /* size in bytes */
+ u64 count; /* for rep prefixes */
+ union {
+ u64 data; /* data */
+ void *pdata; /* pointer to data */
+ } u;
+ u8 state:4;
+ u8 pdata_valid:1; /* if 1, use pdata above */
+ u8 dir:1; /* 1=read, 0=write */
+ u8 port_mm:1; /* 0=portio, 1=mmio */
+ u8 df:1;
+} ioreq_t;
+
+#define MAX_VECTOR 256
+#define BITS_PER_BYTE 8
+#define INTR_LEN (MAX_VECTOR/(BITS_PER_BYTE * sizeof(unsigned long)))
+
+typedef struct {
+ ioreq_t vp_ioreq;
+ unsigned long vp_intr[INTR_LEN];
+} vcpu_iodata_t;
+
+#endif /* _IOREQ_H_ */
diff --git a/xen/include/public/io/ring.h b/xen/include/public/io/ring.h
new file mode 100644
index 0000000000..8efeac4e98
--- /dev/null
+++ b/xen/include/public/io/ring.h
@@ -0,0 +1,254 @@
+/*
+ * Shared producer-consumer ring macros.
+ * Tim Deegan and Andrew Warfield November 2004.
+ */
+
+#ifndef __XEN_PUBLIC_IO_RING_H__
+#define __XEN_PUBLIC_IO_RING_H__
+
+typedef unsigned int RING_IDX;
+
+/* This is horrible: it rounds a 32-bit unsigned constant down to the
+ * nearest power of two, by finding the highest set bit. */
+#define __RD2PO2(_x) (((_x) & 0x80000000) ? 0x80000000 : \
+ ((_x) & 0x40000000) ? 0x40000000 : \
+ ((_x) & 0x20000000) ? 0x20000000 : \
+ ((_x) & 0x10000000) ? 0x10000000 : \
+ ((_x) & 0x08000000) ? 0x08000000 : \
+ ((_x) & 0x04000000) ? 0x04000000 : \
+ ((_x) & 0x02000000) ? 0x02000000 : \
+ ((_x) & 0x01000000) ? 0x01000000 : \
+ ((_x) & 0x00800000) ? 0x00800000 : \
+ ((_x) & 0x00400000) ? 0x00400000 : \
+ ((_x) & 0x00200000) ? 0x00200000 : \
+ ((_x) & 0x00100000) ? 0x00100000 : \
+ ((_x) & 0x00080000) ? 0x00080000 : \
+ ((_x) & 0x00040000) ? 0x00040000 : \
+ ((_x) & 0x00020000) ? 0x00020000 : \
+ ((_x) & 0x00010000) ? 0x00010000 : \
+ ((_x) & 0x00008000) ? 0x00008000 : \
+ ((_x) & 0x00004000) ? 0x00004000 : \
+ ((_x) & 0x00002000) ? 0x00002000 : \
+ ((_x) & 0x00001000) ? 0x00001000 : \
+ ((_x) & 0x00000800) ? 0x00000800 : \
+ ((_x) & 0x00000400) ? 0x00000400 : \
+ ((_x) & 0x00000200) ? 0x00000200 : \
+ ((_x) & 0x00000100) ? 0x00000100 : \
+ ((_x) & 0x00000080) ? 0x00000080 : \
+ ((_x) & 0x00000040) ? 0x00000040 : \
+ ((_x) & 0x00000020) ? 0x00000020 : \
+ ((_x) & 0x00000010) ? 0x00000010 : \
+ ((_x) & 0x00000008) ? 0x00000008 : \
+ ((_x) & 0x00000004) ? 0x00000004 : \
+ ((_x) & 0x00000002) ? 0x00000002 : \
+ ((_x) & 0x00000001) ? 0x00000001 : 0x00000000)
+
+/* Given a shared ring, tell me how many entries there are in it. The
+ * rule is: a ring contains as many entries as will fit, rounded down to
+ * the nearest power of two (so we can mask with (size-1) to loop
+ * around) */
+#define __SRING_SIZE(__params, __esize) \
+ __RD2PO2((sizeof((__params)->size) - (2 * sizeof(RING_IDX))) / (__esize))
+#define SRING_SIZE(__params, __sringp) \
+ __SRING_SIZE(__params, sizeof (__sringp)->ring[0])
+
+/*
+ * Macros to make the correct C datatypes for a new kind of ring.
+ *
+ * To make a new ring datatype, you need to have two message structures,
+ * let's say request_t, and response_t already defined. You also need to
+ * know how big the shared memory region you want the ring to occupy is
+ * (PAGE_SIZE, of instance).
+ *
+ * In a header where you want the ring datatype declared, you then do:
+ *
+ * #define MY_RING RING_PARAMS(request_t, response_t, PAGE_SIZE)
+ * DEFINE_RING_TYPES(mytag, MY_RING);
+ *
+ * These expand out to give you a set of types, as you can see below.
+ * The most important of these are:
+ *
+ * mytag_sring_t - The shared ring.
+ * mytag_front_ring_t - The 'front' half of the ring.
+ * mytag_back_ring_t - The 'back' half of the ring.
+ *
+ * Use the RING_PARAMS define (MY_RING above) as a first parameter on all
+ * the ring functions. To initialize a ring in your code, on the front
+ * half, you do a:
+ *
+ * mytag_front_ring_t front_ring;
+ *
+ * SHARED_RING_INIT(MY_RING, (mytag_sring_t *)shared_page)
+ * FRONT_RING_INIT(MY_RING, &front_ring, (mytag_sring_t *)shared_page)
+ *
+ * Initializing the back follows similarly...
+ */
+
+/* NB: RING SIZING. (a note to ease future debugging...)
+ *
+ * Passing size information into the ring macros is made difficult by
+ * the lack of a reasonable constant declaration in C. To get around this,
+ * the RING_PARAMS define places the requested size of the ring as the
+ * static size of the 'size' array in the anonymous RING_PARAMS struct.
+ * While this struct is never actually instantiated, __SRING_SIZE is
+ * able to use sizeof() to get at the constant size.
+ */
+
+#define RING_PARAMS(__req_t, __rsp_t, __size) \
+((struct { \
+ char size[__size]; \
+ __req_t req; \
+ __rsp_t rsp; \
+ \
+} *) 0)
+
+
+#define DEFINE_RING_TYPES(__name, __params) \
+ \
+/* Shared ring entry */ \
+union __name##_sring_entry { \
+ typeof ((__params)->req) req; \
+ typeof ((__params)->rsp) rsp; \
+} PACKED; \
+ \
+/* Shared ring page */ \
+struct __name##_sring { \
+ RING_IDX req_prod; \
+ RING_IDX rsp_prod; \
+ union __name##_sring_entry \
+ ring[__SRING_SIZE(__params, sizeof (union __name##_sring_entry))]; \
+} PACKED; \
+ \
+/* "Front" end's private variables */ \
+struct __name##_front_ring { \
+ RING_IDX req_prod_pvt; \
+ RING_IDX rsp_cons; \
+ struct __name##_sring *sring; \
+}; \
+ \
+/* "Back" end's private variables */ \
+struct __name##_back_ring { \
+ RING_IDX rsp_prod_pvt; \
+ RING_IDX req_cons; \
+ struct __name##_sring *sring; \
+}; \
+ \
+/* Syntactic sugar */ \
+typedef struct __name##_sring __name##_sring_t; \
+typedef struct __name##_front_ring __name##_front_ring_t; \
+typedef struct __name##_back_ring __name##_back_ring_t;
+
+/*
+ * Macros for manipulating rings.
+ *
+ * FRONT_RING_whatever works on the "front end" of a ring: here
+ * requests are pushed on to the ring and responses taken off it.
+ *
+ * BACK_RING_whatever works on the "back end" of a ring: here
+ * requests are taken off the ring and responses put on.
+ *
+ * N.B. these macros do NO INTERLOCKS OR FLOW CONTROL.
+ * This is OK in 1-for-1 request-response situations where the
+ * requestor (front end) never has more than SRING_SIZE()-1
+ * outstanding requests.
+ */
+
+
+/* Initialising empty rings */
+#define SHARED_RING_INIT(_p, _s) do { \
+ (_s)->req_prod = 0; \
+ (_s)->rsp_prod = 0; \
+} while(0)
+
+#define FRONT_RING_INIT(_p, _r, _s) do { \
+ (_r)->req_prod_pvt = 0; \
+ (_r)->rsp_cons = 0; \
+ (_r)->sring = (_s); \
+} while (0)
+
+#define BACK_RING_INIT(_p, _r, _s) do { \
+ (_r)->rsp_prod_pvt = 0; \
+ (_r)->req_cons = 0; \
+ (_r)->sring = (_s); \
+} while (0)
+
+/* Initialize to existing shared indexes -- for recovery */
+#define FRONT_RING_ATTACH(_p, _r, _s) do { \
+ (_r)->sring = (_s); \
+ (_r)->req_prod_pvt = (_s)->req_prod; \
+ (_r)->rsp_cons = (_s)->rsp_prod; \
+} while (0)
+
+#define BACK_RING_ATTACH(_p, _r, _s) do { \
+ (_r)->sring = (_s); \
+ (_r)->rsp_prod_pvt = (_s)->rsp_prod; \
+ (_r)->req_cons = (_s)->req_prod; \
+} while (0)
+
+
+/* How to mask off a number for use as an offset into a ring
+ * N.B. This evalutes its second argument once but its first often */
+#define __SHARED_RING_MASK(_p, _s, _i) \
+ ((_i) & (SRING_SIZE((_p), (_s)) - 1))
+
+/* How big is this ring? */
+#define RING_SIZE(_p, _r) SRING_SIZE((_p), (_r)->sring)
+
+/* How many empty slots are on a ring? */
+#define RING_PENDING_REQUESTS(_p, _r) \
+ ( ((_r)->req_prod_pvt - (_r)->rsp_cons) )
+
+/* Test if there is an empty slot available on the front ring.
+ * (This is only meaningful from the front. )
+ */
+#define RING_FULL(_p, _r) \
+ (((_r)->req_prod_pvt - (_r)->rsp_cons) == SRING_SIZE((_p), (_r)->sring))
+
+/* Test if there are outstanding messages to be processed on a ring. */
+#define RING_HAS_UNCONSUMED_RESPONSES(_p, _r) \
+ ( (_r)->rsp_cons != (_r)->sring->rsp_prod )
+
+#define RING_HAS_UNCONSUMED_REQUESTS(_p, _r) \
+ ( ((_r)->req_cons != (_r)->sring->req_prod ) && \
+ (((_r)->req_cons - (_r)->rsp_prod_pvt) != \
+ SRING_SIZE((_p), (_r)->sring)) )
+
+/* Test if there are messages waiting to be pushed. */
+#define RING_HAS_UNPUSHED_REQUESTS(_p, _r) \
+ ( (_r)->req_prod_pvt != (_r)->sring->req_prod )
+
+#define RING_HAS_UNPUSHED_RESPONSES(_p, _r) \
+ ( (_r)->rsp_prod_pvt != (_r)->sring->rsp_prod )
+
+
+/* Copy the private producer pointer into the shared ring so the other end
+ * can see the updates we've made. */
+#define RING_PUSH_REQUESTS(_p, _r) do { \
+ wmb(); \
+ (_r)->sring->req_prod = (_r)->req_prod_pvt; \
+} while (0)
+
+#define RING_PUSH_RESPONSES(_p, _r) do { \
+ wmb(); \
+ (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt; \
+} while (0)
+
+/* Direct access to individual ring elements, by index.
+ */
+#define RING_GET_REQUEST(_p, _r, _idx) \
+ (&((_r)->sring->ring[ \
+ __SHARED_RING_MASK((_p), (_r)->sring, (_idx)) \
+ ].req))
+
+#define RING_GET_RESPONSE(_p, _r, _idx) \
+ (&((_r)->sring->ring[ \
+ __SHARED_RING_MASK((_p), (_r)->sring, (_idx)) \
+ ].rsp))
+
+/* Loop termination condition: Would the specified index overflow the
+ * ring?
+ */
+#define RING_REQUEST_CONS_OVERFLOW(_p, _r, _cons) \
+ (((_cons) - (_r)->rsp_prod_pvt) >= SRING_SIZE((_p), (_r)->sring))
+
+#endif /* __XEN_PUBLIC_IO_RING_H__ */
diff --git a/xen/include/public/io/usbif.h b/xen/include/public/io/usbif.h
new file mode 100644
index 0000000000..6056d54f40
--- /dev/null
+++ b/xen/include/public/io/usbif.h
@@ -0,0 +1,67 @@
+/******************************************************************************
+ * usbif.h
+ *
+ * Unified block-device I/O interface for Xen guest OSes.
+ *
+ * Copyright (c) 2003-2004, Keir Fraser
+ */
+
+#ifndef __SHARED_USBIF_H__
+#define __SHARED_USBIF_H__
+
+#define usbif_vdev_t u16
+#define usbif_sector_t u64
+
+#define USBIF_OP_IO 0 /* Request IO to a device */
+#define USBIF_OP_PROBE 1 /* Is there a device on this port? */
+#define USBIF_OP_RESET 2 /* Reset a virtual USB port. */
+
+typedef struct {
+ unsigned long id; /* 0: private guest value, echoed in resp */
+ u8 operation; /* 4: USBIF_OP_??? */
+ u8 __pad1;
+ usbif_vdev_t port; /* 6 : guest virtual USB port */
+ unsigned long devnum :7; /* 8 : Device address, as seen by the guest.*/
+ unsigned long endpoint :4; /* Device endpoint. */
+ unsigned long direction :1; /* Pipe direction. */
+ unsigned long speed :1; /* Pipe speed. */
+ unsigned long pipe_type :2; /* Pipe type (iso, bulk, int, ctrl) */
+ unsigned long __pad2 :18;
+ unsigned long transfer_buffer; /* 12: Machine address */
+ unsigned long length; /* 16: Buffer length */
+ unsigned long transfer_flags; /* 20: For now just pass Linux transfer
+ * flags - this may change. */
+ unsigned char setup[8]; /* 22 Embed setup packets directly. */
+ unsigned long iso_schedule; /* 30 Machine address of transfer sched (iso
+ * only) */
+ unsigned long num_iso; /* 34 : length of iso schedule */
+ unsigned long timeout; /* 38: timeout in ms */
+} PACKED usbif_request_t; /* 42 */
+
+/* Data we need to pass:
+ * - Transparently handle short packets or complain at us?
+ */
+
+typedef struct {
+ unsigned long id; /* 0: copied from request */
+ u8 operation; /* 4: copied from request */
+ u8 data; /* 5: Small chunk of in-band data */
+ s16 status; /* 6: USBIF_RSP_??? */
+ unsigned long transfer_mutex; /* Used for cancelling requests atomically. */
+ unsigned long length; /* 8: How much data we really got */
+} PACKED usbif_response_t;
+
+#define USBIF_RSP_ERROR -1 /* non-specific 'error' */
+#define USBIF_RSP_OKAY 0 /* non-specific 'okay' */
+
+#define USBIF_RING RING_PARAMS(usbif_request_t, usbif_response_t, PAGE_SIZE)
+DEFINE_RING_TYPES(usbif, USBIF_RING);
+
+typedef struct {
+ unsigned long length; /* IN = expected, OUT = actual */
+ unsigned long buffer_offset; /* IN offset in buffer specified in main
+ packet */
+ unsigned long status; /* OUT Status for this packet. */
+} usbif_iso_t;
+
+#endif /* __SHARED_USBIF_H__ */
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index ff13c0fb20..ac643140c4 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -48,6 +48,7 @@
#define __HYPERVISOR_vm_assist 21
#define __HYPERVISOR_update_va_mapping_otherdomain 22
#define __HYPERVISOR_switch_vm86 23
+#define __HYPERVISOR_boot_vcpu 24
/*
* MULTICALLS
@@ -64,13 +65,12 @@
*
* Virtual interrupts that a guest OS may receive from Xen.
*/
-#define VIRQ_MISDIRECT 0 /* Catch-all interrupt for unbound VIRQs. */
-#define VIRQ_TIMER 1 /* Timebase update, and/or requested timeout. */
-#define VIRQ_DEBUG 2 /* Request guest to dump debug info. */
-#define VIRQ_CONSOLE 3 /* (DOM0) bytes received on emergency console. */
-#define VIRQ_DOM_EXC 4 /* (DOM0) Exceptional event for some domain. */
-#define VIRQ_PARITY_ERR 5 /* (DOM0) NMI parity error. */
-#define VIRQ_IO_ERR 6 /* (DOM0) NMI I/O error. */
+#define VIRQ_TIMER 0 /* Timebase update, and/or requested timeout. */
+#define VIRQ_DEBUG 1 /* Request guest to dump debug info. */
+#define VIRQ_CONSOLE 2 /* (DOM0) bytes received on emergency console. */
+#define VIRQ_DOM_EXC 3 /* (DOM0) Exceptional event for some domain. */
+#define VIRQ_PARITY_ERR 4 /* (DOM0) NMI parity error. */
+#define VIRQ_IO_ERR 5 /* (DOM0) NMI I/O error. */
#define NR_VIRQS 7
/*
@@ -250,8 +250,46 @@ typedef struct
/* Event channel endpoints per domain. */
#define NR_EVENT_CHANNELS 1024
-/* No support for multi-processor guests. */
-#define MAX_VIRT_CPUS 1
+/* Support for multi-processor guests. */
+#define MAX_VIRT_CPUS 32
+
+/*
+ * Per-VCPU information goes here. This will be cleaned up more when Xen
+ * actually supports multi-VCPU guests.
+ */
+typedef struct
+{
+ /*
+ * 'evtchn_upcall_pending' is written non-zero by Xen to indicate
+ * a pending notification for a particular VCPU. It is then cleared
+ * by the guest OS /before/ checking for pending work, thus avoiding
+ * a set-and-check race. Note that the mask is only accessed by Xen
+ * on the CPU that is currently hosting the VCPU. This means that the
+ * pending and mask flags can be updated by the guest without special
+ * synchronisation (i.e., no need for the x86 LOCK prefix).
+ * This may seem suboptimal because if the pending flag is set by
+ * a different CPU then an IPI may be scheduled even when the mask
+ * is set. However, note:
+ * 1. The task of 'interrupt holdoff' is covered by the per-event-
+ * channel mask bits. A 'noisy' event that is continually being
+ * triggered can be masked at source at this very precise
+ * granularity.
+ * 2. The main purpose of the per-VCPU mask is therefore to restrict
+ * reentrant execution: whether for concurrency control, or to
+ * prevent unbounded stack usage. Whatever the purpose, we expect
+ * that the mask will be asserted only for short periods at a time,
+ * and so the likelihood of a 'spurious' IPI is suitably small.
+ * The mask is read before making an event upcall to the guest: a
+ * non-zero mask therefore guarantees that the VCPU will not receive
+ * an upcall activation. The mask is cleared when the VCPU requests
+ * to block: this avoids wakeup-waiting races.
+ */
+ u8 evtchn_upcall_pending; /* 0 */
+ u8 evtchn_upcall_mask; /* 1 */
+ u8 pad0, pad1;
+ u32 evtchn_pending_sel; /* 4 */
+ arch_vcpu_info_t arch; /* 8 */
+} PACKED vcpu_info_t; /* 8 + arch */
/*
* Xen/guestos shared data -- pointer provided in start_info.
@@ -259,40 +297,9 @@ typedef struct
*/
typedef struct shared_info_st
{
- /*
- * Per-VCPU information goes here. This will be cleaned up more when Xen
- * actually supports multi-VCPU guests.
- */
- struct {
- /*
- * 'evtchn_upcall_pending' is written non-zero by Xen to indicate
- * a pending notification for a particular VCPU. It is then cleared
- * by the guest OS /before/ checking for pending work, thus avoiding
- * a set-and-check race. Note that the mask is only accessed by Xen
- * on the CPU that is currently hosting the VCPU. This means that the
- * pending and mask flags can be updated by the guest without special
- * synchronisation (i.e., no need for the x86 LOCK prefix).
- * This may seem suboptimal because if the pending flag is set by
- * a different CPU then an IPI may be scheduled even when the mask
- * is set. However, note:
- * 1. The task of 'interrupt holdoff' is covered by the per-event-
- * channel mask bits. A 'noisy' event that is continually being
- * triggered can be masked at source at this very precise
- * granularity.
- * 2. The main purpose of the per-VCPU mask is therefore to restrict
- * reentrant execution: whether for concurrency control, or to
- * prevent unbounded stack usage. Whatever the purpose, we expect
- * that the mask will be asserted only for short periods at a time,
- * and so the likelihood of a 'spurious' IPI is suitably small.
- * The mask is read before making an event upcall to the guest: a
- * non-zero mask therefore guarantees that the VCPU will not receive
- * an upcall activation. The mask is cleared when the VCPU requests
- * to block: this avoids wakeup-waiting races.
- */
- u8 evtchn_upcall_pending;
- u8 evtchn_upcall_mask;
- u8 pad0, pad1;
- } PACKED vcpu_data[MAX_VIRT_CPUS]; /* 0 */
+ vcpu_info_t vcpu_data[MAX_VIRT_CPUS]; /* 0 */
+
+ u32 n_vcpu;
/*
* A domain can have up to 1024 "event channels" on which it can send
@@ -326,7 +333,6 @@ typedef struct shared_info_st
* word in the PENDING bitfield array.
*/
u32 evtchn_pending[32]; /* 4 */
- u32 evtchn_pending_sel; /* 132 */
u32 evtchn_mask[32]; /* 136 */
/*
@@ -416,7 +422,7 @@ typedef struct {
#define SIF_INITDOMAIN (1<<1) /* Is this the initial control domain? */
#define SIF_BLK_BE_DOMAIN (1<<4) /* Is this a block backend domain? */
#define SIF_NET_BE_DOMAIN (1<<5) /* Is this a net backend domain? */
-
+#define SIF_USB_BE_DOMAIN (1<<6) /* Is this a usb backend domain? */
/* For use in guest OSes. */
extern shared_info_t *HYPERVISOR_shared_info;
diff --git a/xen/include/xen/domain.h b/xen/include/xen/domain.h
index 94d1e01635..0e28badba0 100644
--- a/xen/include/xen/domain.h
+++ b/xen/include/xen/domain.h
@@ -6,16 +6,20 @@
* Arch-specifics.
*/
-extern void domain_startofday(void);
-
extern struct domain *arch_alloc_domain_struct(void);
extern void arch_free_domain_struct(struct domain *d);
-extern void arch_do_createdomain(struct domain *d);
+struct exec_domain *arch_alloc_exec_domain_struct(void);
+
+extern void arch_free_exec_domain_struct(struct exec_domain *ed);
+
+extern void arch_do_createdomain(struct exec_domain *ed);
+
+extern void arch_do_boot_vcpu(struct exec_domain *ed);
extern int arch_final_setup_guestos(
- struct domain *d, full_execution_context_t *c);
+ struct exec_domain *d, full_execution_context_t *c);
extern void free_perdomain_pt(struct domain *d);
diff --git a/xen/include/xen/elf.h b/xen/include/xen/elf.h
index f63daa6fc6..34ca50e2be 100644
--- a/xen/include/xen/elf.h
+++ b/xen/include/xen/elf.h
@@ -528,4 +528,8 @@ struct domain_setup_info;
extern int loadelfimage(char *);
extern int parseelfimage(char *, unsigned long, struct domain_setup_info *);
+#ifdef Elf_Ehdr
+extern int elf_sanity_check(Elf_Ehdr *ehdr);
+#endif
+
#endif /* __XEN_ELF_H__ */
diff --git a/xen/include/xen/event.h b/xen/include/xen/event.h
index 1fcef0f03e..f0f3d61fd6 100644
--- a/xen/include/xen/event.h
+++ b/xen/include/xen/event.h
@@ -20,18 +20,19 @@
* may require explicit memory barriers.
*/
-static inline void evtchn_set_pending(struct domain *d, int port)
+static inline void evtchn_set_pending(struct exec_domain *ed, int port)
{
+ struct domain *d = ed->domain;
shared_info_t *s = d->shared_info;
int running;
/* These three operations must happen in strict order. */
if ( !test_and_set_bit(port, &s->evtchn_pending[0]) &&
!test_bit (port, &s->evtchn_mask[0]) &&
- !test_and_set_bit(port>>5, &s->evtchn_pending_sel) )
+ !test_and_set_bit(port>>5, &ed->vcpu_info->evtchn_pending_sel) )
{
/* The VCPU pending flag must be set /after/ update to evtchn-pend. */
- set_bit(0, &s->vcpu_data[0].evtchn_upcall_pending);
+ set_bit(0, &ed->vcpu_info->evtchn_upcall_pending);
/*
* NB1. 'flags' and 'processor' must be checked /after/ update of
@@ -42,10 +43,10 @@ static inline void evtchn_set_pending(struct domain *d, int port)
* NB2. We save DF_RUNNING across the unblock to avoid a needless
* IPI for domains that we IPI'd to unblock.
*/
- running = test_bit(DF_RUNNING, &d->flags);
- domain_unblock(d);
+ running = test_bit(EDF_RUNNING, &ed->ed_flags);
+ exec_domain_unblock(ed);
if ( running )
- smp_send_event_check_cpu(d->processor);
+ smp_send_event_check_cpu(ed->processor);
}
}
@@ -54,9 +55,12 @@ static inline void evtchn_set_pending(struct domain *d, int port)
* @d: Domain to which virtual IRQ should be sent
* @virq: Virtual IRQ number (VIRQ_*)
*/
-static inline void send_guest_virq(struct domain *d, int virq)
+static inline void send_guest_virq(struct exec_domain *ed, int virq)
{
- evtchn_set_pending(d, d->virq_to_evtchn[virq]);
+ int port = ed->virq_to_evtchn[virq];
+
+ if ( likely(port != 0) )
+ evtchn_set_pending(ed, port);
}
/*
@@ -64,13 +68,13 @@ static inline void send_guest_virq(struct domain *d, int virq)
* @d: Domain to which physical IRQ should be sent
* @pirq: Physical IRQ number
*/
-static inline void send_guest_pirq(struct domain *d, int pirq)
+static inline void send_guest_pirq(struct exec_domain *ed, int pirq)
{
- evtchn_set_pending(d, d->pirq_to_evtchn[pirq]);
+ evtchn_set_pending(ed, ed->domain->pirq_to_evtchn[pirq]);
}
#define event_pending(_d) \
- ((_d)->shared_info->vcpu_data[0].evtchn_upcall_pending && \
- !(_d)->shared_info->vcpu_data[0].evtchn_upcall_mask)
+ ((_d)->vcpu_info->evtchn_upcall_pending && \
+ !(_d)->vcpu_info->evtchn_upcall_mask)
#endif /* __XEN_EVENT_H__ */
diff --git a/xen/include/xen/init.h b/xen/include/xen/init.h
index 9e1e62e48f..6df189f980 100644
--- a/xen/include/xen/init.h
+++ b/xen/include/xen/init.h
@@ -2,6 +2,7 @@
#define _LINUX_INIT_H
#include <xen/config.h>
+#include <asm/init.h>
/* These macros are used to mark some functions or
* initialized data (doesn't apply to uninitialized data)
@@ -83,30 +84,6 @@ extern struct kernel_param __setup_start, __setup_end;
#endif /* __ASSEMBLY__ */
-/*
- * Mark functions and data as being only used at initialization
- * or exit time.
- */
-#define __init \
- __attribute__ ((__section__ (".text.init")))
-#define __exit \
- __attribute_used__ __attribute__ ((__section__(".text.exit")))
-#define __initdata \
- __attribute__ ((__section__ (".data.init")))
-#define __exitdata \
- __attribute_used__ __attribute__ ((__section__ (".data.exit")))
-#define __initsetup \
- __attribute_used__ __attribute__ ((__section__ (".setup.init")))
-#define __init_call \
- __attribute_used__ __attribute__ ((__section__ (".initcall.init")))
-#define __exit_call \
- __attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
-
-/* For assembly routines */
-#define __INIT .section ".text.init","ax"
-#define __FINIT .previous
-#define __INITDATA .section ".data.init","aw"
-
#ifdef CONFIG_HOTPLUG
#define __devinit
#define __devinitdata
diff --git a/xen/include/xen/irq.h b/xen/include/xen/irq.h
index 42e6d266a4..fd00e5e5eb 100644
--- a/xen/include/xen/irq.h
+++ b/xen/include/xen/irq.h
@@ -66,8 +66,9 @@ extern hw_irq_controller no_irq_type;
extern void no_action(int cpl, void *dev_id, struct xen_regs *regs);
struct domain;
+struct exec_domain;
extern int pirq_guest_unmask(struct domain *p);
-extern int pirq_guest_bind(struct domain *p, int irq, int will_share);
+extern int pirq_guest_bind(struct exec_domain *p, int irq, int will_share);
extern int pirq_guest_unbind(struct domain *p, int irq);
extern int pirq_guest_bindable(int irq, int will_share);
diff --git a/xen/include/xen/keyhandler.h b/xen/include/xen/keyhandler.h
index 3c7c36ef66..e3d49c9086 100644
--- a/xen/include/xen/keyhandler.h
+++ b/xen/include/xen/keyhandler.h
@@ -10,7 +10,7 @@
#ifndef __XEN_KEYHANDLER_H__
#define __XEN_KEYHANDLER_H__
-struct xen_regs;
+#include <asm/regs.h>
/*
* Register a callback function for key @key. The callback occurs in
diff --git a/xen/include/xen/list.h b/xen/include/xen/list.h
index 7b19bb4650..93d9f987e7 100644
--- a/xen/include/xen/list.h
+++ b/xen/include/xen/list.h
@@ -174,5 +174,17 @@ static __inline__ void list_splice(struct list_head *list, struct list_head *hea
pos = list_entry(pos->member.next, typeof(*pos), member), \
prefetch(pos->member.next))
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
#endif /* _LINUX_LIST_H */
diff --git a/xen/include/xen/sched-if.h b/xen/include/xen/sched-if.h
index 15f992614a..f73eace25b 100644
--- a/xen/include/xen/sched-if.h
+++ b/xen/include/xen/sched-if.h
@@ -13,8 +13,8 @@ typedef struct schedule_data_st
{
spinlock_t schedule_lock; /* spinlock protecting curr pointer
TODO check this */
- struct domain *curr; /* current task */
- struct domain *idle; /* idle task for this cpu */
+ struct exec_domain *curr; /* current task */
+ struct exec_domain *idle; /* idle task for this cpu */
void * sched_priv;
struct ac_timer s_timer; /* scheduling timer */
#ifdef BUCKETS
@@ -25,7 +25,7 @@ typedef struct schedule_data_st
typedef struct task_slice_st
{
- struct domain *task;
+ struct exec_domain *task;
s_time_t time;
} task_slice_t;
@@ -36,14 +36,14 @@ struct scheduler
unsigned int sched_id; /* ID for this scheduler */
int (*init_scheduler) ();
- int (*init_idle_task) (struct domain *);
- int (*alloc_task) (struct domain *);
- void (*add_task) (struct domain *);
+ int (*init_idle_task) (struct exec_domain *);
+ int (*alloc_task) (struct exec_domain *);
+ void (*add_task) (struct exec_domain *);
void (*free_task) (struct domain *);
- void (*rem_task) (struct domain *);
- void (*sleep) (struct domain *);
- void (*wake) (struct domain *);
- void (*do_block) (struct domain *);
+ void (*rem_task) (struct exec_domain *);
+ void (*sleep) (struct exec_domain *);
+ void (*wake) (struct exec_domain *);
+ void (*do_block) (struct exec_domain *);
task_slice_t (*do_schedule) (s_time_t);
int (*control) (struct sched_ctl_cmd *);
int (*adjdom) (struct domain *,
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index d7e6f0be26..4381799d89 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -1,8 +1,8 @@
+/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */
+
#ifndef __SCHED_H__
#define __SCHED_H__
-#define STACK_SIZE (2*PAGE_SIZE)
-
#include <xen/config.h>
#include <xen/types.h>
#include <xen/spinlock.h>
@@ -21,48 +21,97 @@
#include <asm/current.h>
#include <xen/spinlock.h>
#include <xen/grant_table.h>
-#include <xen/irq_cpustat.h>
+#include <asm/hardirq.h>
+#include <asm/domain.h>
extern unsigned long volatile jiffies;
extern rwlock_t domlist_lock;
-struct domain;
-
/* A global pointer to the initial domain (DOM0). */
extern struct domain *dom0;
typedef struct event_channel_st
{
#define ECS_FREE 0 /* Channel is available for use. */
-#define ECS_UNBOUND 1 /* Channel is waiting to bind to a remote domain. */
-#define ECS_INTERDOMAIN 2 /* Channel is bound to another domain. */
-#define ECS_PIRQ 3 /* Channel is bound to a physical IRQ line. */
-#define ECS_VIRQ 4 /* Channel is bound to a virtual IRQ line. */
+#define ECS_RESERVED 1 /* Channel is reserved. */
+#define ECS_UNBOUND 2 /* Channel is waiting to bind to a remote domain. */
+#define ECS_INTERDOMAIN 3 /* Channel is bound to another domain. */
+#define ECS_PIRQ 4 /* Channel is bound to a physical IRQ line. */
+#define ECS_VIRQ 5 /* Channel is bound to a virtual IRQ line. */
+#define ECS_IPI 6 /* Channel is bound to a virtual IPI line. */
u16 state;
union {
struct {
domid_t remote_domid;
} __attribute__ ((packed)) unbound; /* state == ECS_UNBOUND */
struct {
- u16 remote_port;
- struct domain *remote_dom;
+ u16 remote_port;
+ struct exec_domain *remote_dom;
} __attribute__ ((packed)) interdomain; /* state == ECS_INTERDOMAIN */
u16 pirq; /* state == ECS_PIRQ */
u16 virq; /* state == ECS_VIRQ */
+ u32 ipi_edom; /* state == ECS_IPI */
} u;
} event_channel_t;
int init_event_channels(struct domain *d);
void destroy_event_channels(struct domain *d);
+int init_exec_domain_event_channels(struct exec_domain *ed);
-struct domain
+struct exec_domain
{
u32 processor;
- shared_info_t *shared_info;
+ vcpu_info_t *vcpu_info;
+
+ struct domain *domain;
+ struct exec_domain *ed_next_list;
+ int eid;
+
+#ifdef ARCH_HAS_EXEC_DOMAIN_MM_PTR
+ struct mm_struct *mm;
+#endif
+
+ struct ac_timer timer; /* one-shot timer for timeout values */
+
+ s_time_t lastschd; /* time this domain was last scheduled */
+ s_time_t lastdeschd; /* time this domain was last descheduled */
+ s_time_t cpu_time; /* total CPU time received till now */
+ s_time_t wokenup; /* time domain got woken up */
+ void *ed_sched_priv; /* scheduler-specific data */
+
+ unsigned long ed_flags;
- domid_t id;
- s_time_t create_time;
+ u16 virq_to_evtchn[NR_VIRQS];
+
+ atomic_t pausecnt;
+
+ struct arch_exec_domain arch;
+};
+
+/*
+** SMH: do_mmu_update() grabs big_lock and subsequently can fault
+** on map_ldt_shadow_page(), enter do_page_fault() and then deadlock
+** trying to reacquire big_lock. A temporary fix is to make big_lock
+** recursive; overall probably needs more thought.
+*/
+#if 0
+#define LOCK_BIGLOCK(_d) spin_lock(&(_d)->big_lock)
+#define UNLOCK_BIGLOCK(_d) spin_unlock(&(_d)->big_lock)
+#else
+#define LOCK_BIGLOCK(_d) spin_lock_recursive(&(_d)->big_lock)
+#define UNLOCK_BIGLOCK(_d) spin_unlock_recursive(&(_d)->big_lock)
+#endif
+
+struct domain
+{
+ domid_t id;
+ s_time_t create_time;
+
+ shared_info_t *shared_info; /* shared data area */
+ spinlock_t time_lock;
+
+ spinlock_t big_lock;
spinlock_t page_alloc_lock; /* protects all the following fields */
struct list_head page_list; /* linked list, of size tot_pages */
@@ -73,16 +122,8 @@ struct domain
/* Scheduling. */
int shutdown_code; /* code value from OS (if DF_SHUTDOWN). */
- s_time_t lastschd; /* time this domain was last scheduled */
- s_time_t lastdeschd; /* time this domain was last descheduled */
- s_time_t cpu_time; /* total CPU time received till now */
- s_time_t wokenup; /* time domain got woken up */
- struct ac_timer timer; /* one-shot timer for timeout values */
void *sched_priv; /* scheduler-specific data */
- struct mm_struct mm;
-
- struct thread_struct thread;
struct domain *next_list, *next_hash;
/* Event channel information. */
@@ -99,18 +140,20 @@ struct domain
*/
#define NR_PIRQS 128 /* Put this somewhere sane! */
u16 pirq_to_evtchn[NR_PIRQS];
- u16 virq_to_evtchn[NR_VIRQS];
u32 pirq_mask[NR_PIRQS/32];
/* Physical I/O */
spinlock_t pcidev_lock;
struct list_head pcidev_list;
- unsigned long flags;
+ unsigned long d_flags;
unsigned long vm_assist;
atomic_t refcnt;
- atomic_t pausecnt;
+
+ struct exec_domain *exec_domain[MAX_VIRT_CPUS];
+
+ struct arch_domain arch;
};
struct domain_setup_info
@@ -125,11 +168,15 @@ struct domain_setup_info
#include <asm/uaccess.h> /* for KERNEL_DS */
-extern struct domain idle0_task;
+extern struct domain idle0_domain;
+extern struct exec_domain idle0_exec_domain;
-extern struct domain *idle_task[NR_CPUS];
+extern struct exec_domain *idle_task[NR_CPUS];
#define IDLE_DOMAIN_ID (0x7FFFU)
-#define is_idle_task(_p) (test_bit(DF_IDLETASK, &(_p)->flags))
+#define is_idle_task(_p) (test_bit(DF_IDLETASK, &(_p)->d_flags))
+
+struct exec_domain *alloc_exec_domain_struct(struct domain *d,
+ unsigned long vcpu);
void free_domain_struct(struct domain *d);
struct domain *alloc_domain_struct();
@@ -172,8 +219,8 @@ extern struct domain *do_createdomain(
extern int construct_dom0(struct domain *d,
unsigned long alloc_start,
unsigned long alloc_end,
- char *image_start, unsigned long image_len,
- char *initrd_start, unsigned long initrd_len,
+ unsigned long image_start, unsigned long image_len,
+ unsigned long initrd_start, unsigned long initrd_len,
char *cmdline);
extern int final_setup_guestos(struct domain *d, dom0_builddomain_t *);
@@ -184,7 +231,7 @@ extern void domain_kill(struct domain *d);
extern void domain_crash(void);
extern void domain_shutdown(u8 reason);
-void new_thread(struct domain *d,
+void new_thread(struct exec_domain *d,
unsigned long start_pc,
unsigned long start_stack,
unsigned long start_info);
@@ -195,19 +242,19 @@ extern unsigned long wait_init_idle;
#define set_current_state(_s) do { current->state = (_s); } while (0)
void scheduler_init(void);
void schedulers_start(void);
-void sched_add_domain(struct domain *d);
-void sched_rem_domain(struct domain *d);
+void sched_add_domain(struct exec_domain *);
+void sched_rem_domain(struct exec_domain *);
long sched_ctl(struct sched_ctl_cmd *);
long sched_adjdom(struct sched_adjdom_cmd *);
int sched_id();
void init_idle_task(void);
-void domain_wake(struct domain *d);
-void domain_sleep(struct domain *d);
+void domain_wake(struct exec_domain *d);
+void domain_sleep(struct exec_domain *d);
void __enter_scheduler(void);
-extern void switch_to(struct domain *prev,
- struct domain *next);
+extern void switch_to(struct exec_domain *prev,
+ struct exec_domain *next);
void domain_init(void);
@@ -229,69 +276,105 @@ extern struct domain *domain_list;
#define for_each_domain(_p) \
for ( (_p) = domain_list; (_p) != NULL; (_p) = (_p)->next_list )
-#define DF_DONEFPUINIT 0 /* Has the FPU been initialised for this task? */
-#define DF_USEDFPU 1 /* Has this task used the FPU since last save? */
-#define DF_GUEST_STTS 2 /* Has the guest OS requested 'stts'? */
-#define DF_CONSTRUCTED 3 /* Has the guest OS been fully built yet? */
-#define DF_IDLETASK 4 /* Is this one of the per-CPU idle domains? */
-#define DF_PRIVILEGED 5 /* Is this domain privileged? */
-#define DF_PHYSDEV 6 /* May this domain do IO to physical devices? */
-#define DF_BLOCKED 7 /* Domain is blocked waiting for an event. */
-#define DF_CTRLPAUSE 8 /* Domain is paused by controller software. */
-#define DF_SHUTDOWN 9 /* Guest shut itself down for some reason. */
-#define DF_CRASHED 10 /* Domain crashed inside Xen, cannot continue. */
-#define DF_DYING 11 /* Death rattle. */
-#define DF_RUNNING 12 /* Currently running on a CPU. */
-#define DF_CPUPINNED 13 /* Disables auto-migration. */
-#define DF_MIGRATED 14 /* Domain migrated between CPUs. */
-
-static inline int domain_runnable(struct domain *d)
+#define for_each_exec_domain(_d,_ed) \
+ for ( (_ed) = _d->exec_domain[0]; (_ed) != NULL; (_ed) = (_ed)->ed_next_list )
+
+#define EDF_DONEFPUINIT 0 /* Has the FPU been initialised for this task? */
+#define EDF_USEDFPU 1 /* Has this task used the FPU since last save? */
+#define EDF_GUEST_STTS 2 /* Has the guest OS requested 'stts'? */
+#define DF_CONSTRUCTED 3 /* Has the guest OS been fully built yet? */
+#define DF_IDLETASK 4 /* Is this one of the per-CPU idle domains? */
+#define DF_PRIVILEGED 5 /* Is this domain privileged? */
+#define DF_PHYSDEV 6 /* May this domain do IO to physical devices? */
+#define EDF_BLOCKED 7 /* Domain is blocked waiting for an event. */
+#define EDF_CTRLPAUSE 8 /* Domain is paused by controller software. */
+#define DF_SHUTDOWN 9 /* Guest shut itself down for some reason. */
+#define DF_CRASHED 10 /* Domain crashed inside Xen, cannot continue. */
+#define DF_DYING 11 /* Death rattle. */
+#define EDF_RUNNING 12 /* Currently running on a CPU. */
+#define EDF_CPUPINNED 13 /* Disables auto-migration. */
+#define EDF_MIGRATED 14 /* Domain migrated between CPUs. */
+
+static inline int domain_runnable(struct exec_domain *d)
{
return ( (atomic_read(&d->pausecnt) == 0) &&
- !(d->flags & ((1<<DF_BLOCKED)|(1<<DF_CTRLPAUSE)|
- (1<<DF_SHUTDOWN)|(1<<DF_CRASHED))) );
+ !(d->ed_flags & ((1<<EDF_BLOCKED)|(1<<EDF_CTRLPAUSE))) &&
+ !(d->domain->d_flags & ((1<<DF_SHUTDOWN)|(1<<DF_CRASHED))) );
+}
+
+static inline void exec_domain_pause(struct exec_domain *ed)
+{
+ ASSERT(ed != current);
+ atomic_inc(&ed->pausecnt);
+ domain_sleep(ed);
}
static inline void domain_pause(struct domain *d)
{
- ASSERT(d != current);
- atomic_inc(&d->pausecnt);
- domain_sleep(d);
+ struct exec_domain *ed;
+
+ for_each_exec_domain(d, ed)
+ exec_domain_pause(ed);
+}
+
+static inline void exec_domain_unpause(struct exec_domain *ed)
+{
+ ASSERT(ed != current);
+ if ( atomic_dec_and_test(&ed->pausecnt) )
+ domain_wake(ed);
}
static inline void domain_unpause(struct domain *d)
{
- ASSERT(d != current);
- if ( atomic_dec_and_test(&d->pausecnt) )
- domain_wake(d);
+ struct exec_domain *ed;
+
+ for_each_exec_domain(d, ed)
+ exec_domain_unpause(ed);
+}
+
+static inline void exec_domain_unblock(struct exec_domain *ed)
+{
+ if ( test_and_clear_bit(EDF_BLOCKED, &ed->ed_flags) )
+ domain_wake(ed);
}
static inline void domain_unblock(struct domain *d)
{
- if ( test_and_clear_bit(DF_BLOCKED, &d->flags) )
- domain_wake(d);
+ struct exec_domain *ed;
+
+ for_each_exec_domain(d, ed)
+ exec_domain_unblock(ed);
}
static inline void domain_pause_by_systemcontroller(struct domain *d)
{
- ASSERT(d != current);
- if ( !test_and_set_bit(DF_CTRLPAUSE, &d->flags) )
- domain_sleep(d);
+ struct exec_domain *ed;
+
+ for_each_exec_domain(d, ed) {
+ ASSERT(ed != current);
+ if ( !test_and_set_bit(EDF_CTRLPAUSE, &ed->ed_flags) )
+ domain_sleep(ed);
+ }
}
static inline void domain_unpause_by_systemcontroller(struct domain *d)
{
- if ( test_and_clear_bit(DF_CTRLPAUSE, &d->flags) )
- domain_wake(d);
+ struct exec_domain *ed;
+
+ for_each_exec_domain(d, ed) {
+ if ( test_and_clear_bit(EDF_CTRLPAUSE, &ed->ed_flags) )
+ domain_wake(ed);
+ }
}
-#define IS_PRIV(_d) (test_bit(DF_PRIVILEGED, &(_d)->flags))
-#define IS_CAPABLE_PHYSDEV(_d) (test_bit(DF_PHYSDEV, &(_d)->flags))
+#define IS_PRIV(_d) (test_bit(DF_PRIVILEGED, &(_d)->d_flags))
+#define IS_CAPABLE_PHYSDEV(_d) (test_bit(DF_PHYSDEV, &(_d)->d_flags))
#define VM_ASSIST(_d,_t) (test_bit((_t), &(_d)->vm_assist))
#include <xen/slab.h>
#include <xen/domain.h>
+
#endif /* __SCHED_H__ */
diff --git a/xen/include/xen/slab.h b/xen/include/xen/slab.h
index 692b3b63f3..8e510d4a3b 100644
--- a/xen/include/xen/slab.h
+++ b/xen/include/xen/slab.h
@@ -14,43 +14,31 @@
#else
-typedef struct xmem_cache_s xmem_cache_t;
-
#include <xen/mm.h>
#include <xen/cache.h>
+#include <xen/types.h>
-/* Flags to pass to xmem_cache_create(). */
-/* NB. The first 3 are only valid when built with SLAB_DEBUG_SUPPORT. */
-#define SLAB_DEBUG_INITIAL 0x00000200UL /* Call constructor */
-#define SLAB_RED_ZONE 0x00000400UL /* Red zone objs in a cache */
-#define SLAB_POISON 0x00000800UL /* Poison objects */
-#define SLAB_NO_REAP 0x00001000UL /* never reap from the cache */
-#define SLAB_HWCACHE_ALIGN 0x00002000UL /* align obj on a cache line */
-
-/* Flags passed to a constructor function. */
-#define SLAB_CTOR_CONSTRUCTOR 0x001UL /* if not set, then deconstructor */
-#define SLAB_CTOR_ATOMIC 0x002UL /* tell cons. it can't sleep */
-#define SLAB_CTOR_VERIFY 0x004UL /* tell cons. it's a verify call */
-
-extern void xmem_cache_init(void);
-extern void xmem_cache_sizes_init(unsigned long);
-
-extern xmem_cache_t *xmem_find_general_cachep(size_t);
-extern xmem_cache_t *xmem_cache_create(
- const char *, size_t, size_t, unsigned long,
- void (*)(void *, xmem_cache_t *, unsigned long),
- void (*)(void *, xmem_cache_t *, unsigned long));
-extern int xmem_cache_destroy(xmem_cache_t *);
-extern int xmem_cache_shrink(xmem_cache_t *);
-extern void *xmem_cache_alloc(xmem_cache_t *);
-extern void xmem_cache_free(xmem_cache_t *, void *);
-
-extern void *xmalloc(size_t);
-extern void xfree(const void *);
+/* Allocate space for typed object. */
+#define xmalloc(_type) ((_type *)_xmalloc(sizeof(_type), __alignof__(_type)))
+
+/* Allocate space for array of typed objects. */
+#define xmalloc_array(_type, _num) ((_type *)_xmalloc_array(sizeof(_type), __alignof__(_type), _num))
-extern int xmem_cache_reap(void);
+/* Allocate untyped storage. */
+#define xmalloc_bytes(_bytes) (_xmalloc(_bytes, SMP_CACHE_BYTES))
+
+/* Free any of the above. */
+extern void xfree(const void *);
-extern void dump_slabinfo();
+/* Underlying functions */
+extern void *_xmalloc(size_t size, size_t align);
+static inline void *_xmalloc_array(size_t size, size_t align, size_t num)
+{
+ /* Check for overflow. */
+ if (size && num > UINT_MAX / size)
+ return NULL;
+ return _xmalloc(size * num, align);
+}
#endif /* __ARCH_HAS_SLAB_ALLOCATOR */
diff --git a/xen/include/xen/time.h b/xen/include/xen/time.h
index dd476f9298..be8becffa1 100644
--- a/xen/include/xen/time.h
+++ b/xen/include/xen/time.h
@@ -29,11 +29,14 @@
#include <xen/types.h>
#include <public/xen.h>
+#include <asm/time.h>
extern int init_xen_time();
extern unsigned long cpu_khz;
+struct domain;
+
/*
* System Time
* 64 bit value containing the nanoseconds elapsed since boot time.
@@ -52,7 +55,7 @@ s_time_t get_s_time(void);
#define MILLISECS(_ms) (((s_time_t)(_ms)) * 1000000ULL )
#define MICROSECS(_us) (((s_time_t)(_us)) * 1000ULL )
-extern void update_dom_time(shared_info_t *si);
+extern void update_dom_time(struct domain *d);
extern void do_settime(unsigned long secs, unsigned long usecs,
u64 system_time_base);
diff --git a/xen/include/xen/types.h b/xen/include/xen/types.h
index 0299f74136..cd55353dfe 100644
--- a/xen/include/xen/types.h
+++ b/xen/include/xen/types.h
@@ -44,5 +44,7 @@ typedef __u32 uint32_t;
typedef __u64 uint64_t;
+struct domain;
+struct exec_domain;
#endif /* __TYPES_H__ */