@@ -188,6 +188,7 @@ obj-$(CONFIG_KVM) += kvm.o kvm-all.o
# MSI-X depends on kvm for interrupt injection,
# so moved it from Makefile.objs to Makefile.target for now
obj-y += msix.o
+obj-y += event-tap.o
obj-$(CONFIG_ISA_MMIO) += isa_mmio.o
LIBS+=-lz
new file mode 100644
@@ -0,0 +1,184 @@
+/*
+ * Event Tap functions for QEMU
+ *
+ * Copyright (c) 2010 Nippon Telegraph and Telephone Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "block.h"
+#include "ioport.h"
+#include "osdep.h"
+#include "hw/hw.h"
+#include "net/queue.h"
+#include "event-tap.h"
+
+static enum EVENT_TAP_STATE event_tap_state = EVENT_TAP_OFF;
+
+typedef struct EventTapIOport {
+ uint32_t address;
+ uint32_t data;
+ int index;
+} EventTapIOport;
+
+#define MMIO_BUF_SIZE 8
+
+typedef struct EventTapMMIO {
+ uint64_t address;
+ uint8_t buf[MMIO_BUF_SIZE];
+ int len;
+} EventTapMMIO;
+
+#define EVENT_TAP_IOPORT 1
+#define EVENT_TAP_MMIO 2
+
+typedef struct EventTapLog {
+ int mode;
+ union {
+ EventTapIOport ioport ;
+ EventTapMMIO mmio;
+ };
+} EventTapLog;
+
+static EventTapLog last_event_tap;
+
+int event_tap_register(int (*cb)(void))
+{
+ if (cb == NULL || event_tap_state != EVENT_TAP_OFF)
+ return -1;
+
+ bdrv_event_tap_register(cb);
+ qemu_net_event_tap_register(cb);
+ event_tap_state = EVENT_TAP_ON;
+
+ return 0;
+}
+
+int event_tap_unregister(void)
+{
+ if (event_tap_state == EVENT_TAP_OFF)
+ return -1;
+
+ bdrv_event_tap_unregister();
+ qemu_net_event_tap_unregister();
+ event_tap_state = EVENT_TAP_OFF;
+
+ return 0;
+}
+
+void event_tap_suspend(void)
+{
+ if (event_tap_state == EVENT_TAP_ON)
+ event_tap_state = EVENT_TAP_SUSPEND;
+}
+
+void event_tap_resume(void)
+{
+ if (event_tap_state == EVENT_TAP_SUSPEND)
+ event_tap_state = EVENT_TAP_ON;
+}
+
+int event_tap_get_state(void)
+{
+ return event_tap_state;
+}
+
+void event_tap_ioport(int index, uint32_t address, uint32_t data)
+{
+ if (event_tap_state != EVENT_TAP_ON) {
+ return;
+ }
+
+ last_event_tap.mode = EVENT_TAP_IOPORT;
+ last_event_tap.ioport.index = index;
+ last_event_tap.ioport.address = address;
+ last_event_tap.ioport.data = data;
+}
+
+void event_tap_mmio(uint64_t address, uint8_t *buf, int len)
+{
+ if (event_tap_state != EVENT_TAP_ON || len > MMIO_BUF_SIZE) {
+ return;
+ }
+
+ last_event_tap.mode = EVENT_TAP_MMIO;
+ last_event_tap.mmio.address = address;
+ last_event_tap.mmio.len = len;
+ memcpy(last_event_tap.mmio.buf, buf, len);
+}
+
+static void event_tap_reset(void)
+{
+ memset(&last_event_tap, 0, sizeof(last_event_tap));
+}
+
+void event_tap_replay(void)
+{
+ if (event_tap_state != EVENT_TAP_REPLAY) {
+ return;
+ }
+
+ switch (last_event_tap.mode) {
+ case EVENT_TAP_IOPORT:
+ switch (last_event_tap.ioport.index) {
+ case 0:
+ cpu_outb(last_event_tap.ioport.address, last_event_tap.ioport.data);
+ break;
+ case 1:
+ cpu_outw(last_event_tap.ioport.address, last_event_tap.ioport.data);
+ break;
+ case 2:
+ cpu_outl(last_event_tap.ioport.address, last_event_tap.ioport.data);
+ break;
+ }
+ event_tap_reset();
+ break;
+ case EVENT_TAP_MMIO:
+ cpu_physical_memory_rw(last_event_tap.mmio.address,
+ last_event_tap.mmio.buf,
+ last_event_tap.mmio.len, 1);
+ event_tap_reset();
+ break;
+ }
+}
+
+static void event_tap_save(QEMUFile *f, void *opaque)
+{
+ qemu_put_byte(f, last_event_tap.mode);
+
+ if (last_event_tap.mode == EVENT_TAP_IOPORT) {
+ qemu_put_be32(f, last_event_tap.ioport.index);
+ qemu_put_be32(f, last_event_tap.ioport.address);
+ qemu_put_byte(f, last_event_tap.ioport.data);
+ } else {
+ qemu_put_be64(f, last_event_tap.mmio.address);
+ qemu_put_byte(f, last_event_tap.mmio.len);
+ qemu_put_buffer(f, last_event_tap.mmio.buf, last_event_tap.mmio.len);
+ }
+}
+
+static int event_tap_load(QEMUFile *f, void *opaque, int version_id)
+{
+ last_event_tap.mode = qemu_get_byte(f);
+
+ if (last_event_tap.mode == EVENT_TAP_IOPORT) {
+ last_event_tap.ioport.index = qemu_get_be32(f);
+ last_event_tap.ioport.address = qemu_get_be32(f);
+ last_event_tap.ioport.data = qemu_get_byte(f);
+ } else {
+ last_event_tap.mmio.address = qemu_get_be64(f);
+ last_event_tap.mmio.len = qemu_get_byte(f);
+ qemu_get_buffer(f, last_event_tap.mmio.buf, last_event_tap.mmio.len);
+ }
+
+ event_tap_state = EVENT_TAP_REPLAY;
+
+ return 0;
+}
+
+void event_tap_init(void)
+{
+ register_savevm("event-tap", 0, 1,
+ event_tap_save, event_tap_load, &last_event_tap);
+}
new file mode 100644
@@ -0,0 +1,32 @@
+/*
+ * Event Tap functions for QEMU
+ *
+ * Copyright (c) 2010 Nippon Telegraph and Telephone Corporation.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef EVENT_TAP_H
+#define EVENT_TAP_H
+
+#include "qemu-common.h"
+
+enum EVENT_TAP_STATE {
+ EVENT_TAP_OFF,
+ EVENT_TAP_ON,
+ EVENT_TAP_SUSPEND,
+ EVENT_TAP_REPLAY,
+};
+
+int event_tap_register(int (*cb)(void));
+int event_tap_unregister(void);
+void event_tap_suspend(void);
+void event_tap_resume(void);
+int event_tap_get_state(void);
+void event_tap_ioport(int index, uint32_t address, uint32_t data);
+void event_tap_mmio(uint64_t address, uint8_t *buf, int len);
+void event_tap_replay(void);
+void event_tap_init(void);
+
+#endif