All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 00/18] uq/master: Introduce basic irqchip support
@ 2012-01-13 17:34 ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:34 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl,
	Lai Jiangshan

Changes in v6:
- back to the roots: model irqchip variants as separate qdev devices
  with a common base class
- i8259: Completely privatize PicState
- ioapic: Drop post-load irr initialization

I hope this meets all expectations now and can soon be merged.

Jan

CC: Lai Jiangshan <laijs@cn.fujitsu.com>

Jan Kiszka (18):
  msi: Generalize msix_supported to msi_supported
  kvm: Move kvmclock into hw/kvm folder
  apic: Stop timer on reset
  apic: Inject external NMI events via LINT1
  apic: Introduce apic_report_irq_delivered
  apic: Factor out base class for KVM reuse
  apic: Open-code timer save/restore
  i8259: Completely privatize PicState
  i8259: Factor out base class for KVM reuse
  ioapic: Drop post-load irr initialization
  ioapic: Factor out base class for KVM reuse
  memory: Introduce memory_region_init_reservation
  kvm: Introduce core services for in-kernel irqchip support
  kvm: x86: Establish IRQ0 override control
  kvm: x86: Add user space part for in-kernel APIC
  kvm: x86: Add user space part for in-kernel i8259
  kvm: x86: Add user space part for in-kernel IOAPIC
  kvm: Arm in-kernel irqchip support

 Makefile.objs                  |    2 +-
 Makefile.target                |    6 +-
 configure                      |    1 +
 cpus.c                         |    6 +-
 hw/apic.c                      |  368 ++++++++--------------------------------
 hw/apic.h                      |    1 +
 hw/apic_common.c               |  273 +++++++++++++++++++++++++++++
 hw/apic_internal.h             |  123 +++++++++++++
 hw/i8259.c                     |  165 ++++++------------
 hw/i8259_common.c              |   96 +++++++++++
 hw/i8259_internal.h            |   76 ++++++++
 hw/ioapic.c                    |  152 ++++-------------
 hw/ioapic_common.c             |   70 ++++++++
 hw/ioapic_internal.h           |   99 +++++++++++
 hw/kvm/apic.c                  |  165 ++++++++++++++++++
 hw/{kvmclock.c => kvm/clock.c} |    4 +-
 hw/{kvmclock.h => kvm/clock.h} |    0
 hw/kvm/i8259.c                 |  173 +++++++++++++++++++
 hw/kvm/ioapic.c                |  144 ++++++++++++++++
 hw/msi.c                       |    8 +
 hw/msi.h                       |    2 +
 hw/msix.c                      |    9 +-
 hw/msix.h                      |    2 -
 hw/pc.c                        |   20 ++-
 hw/pc.h                        |    8 +-
 hw/pc_piix.c                   |   67 +++++++-
 kvm-all.c                      |  154 +++++++++++++++++
 kvm-stub.c                     |    5 +
 kvm.h                          |   14 ++
 memory.c                       |   36 ++++
 memory.h                       |   16 ++
 qemu-config.c                  |    4 +
 qemu-options.hx                |    5 +-
 sysemu.h                       |    1 -
 target-i386/kvm.c              |   49 ++++++
 trace-events                   |    2 +-
 vl.c                           |    1 -
 37 files changed, 1769 insertions(+), 558 deletions(-)
 create mode 100644 hw/apic_common.c
 create mode 100644 hw/apic_internal.h
 create mode 100644 hw/i8259_common.c
 create mode 100644 hw/i8259_internal.h
 create mode 100644 hw/ioapic_common.c
 create mode 100644 hw/ioapic_internal.h
 create mode 100644 hw/kvm/apic.c
 rename hw/{kvmclock.c => kvm/clock.c} (98%)
 rename hw/{kvmclock.h => kvm/clock.h} (100%)
 create mode 100644 hw/kvm/i8259.c
 create mode 100644 hw/kvm/ioapic.c

-- 
1.7.3.4


^ permalink raw reply	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 00/18] uq/master: Introduce basic irqchip support
@ 2012-01-13 17:34 ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:34 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Anthony Liguori, Lai Jiangshan, kvm, Michael S. Tsirkin,
	qemu-devel, Blue Swirl

Changes in v6:
- back to the roots: model irqchip variants as separate qdev devices
  with a common base class
- i8259: Completely privatize PicState
- ioapic: Drop post-load irr initialization

I hope this meets all expectations now and can soon be merged.

Jan

CC: Lai Jiangshan <laijs@cn.fujitsu.com>

Jan Kiszka (18):
  msi: Generalize msix_supported to msi_supported
  kvm: Move kvmclock into hw/kvm folder
  apic: Stop timer on reset
  apic: Inject external NMI events via LINT1
  apic: Introduce apic_report_irq_delivered
  apic: Factor out base class for KVM reuse
  apic: Open-code timer save/restore
  i8259: Completely privatize PicState
  i8259: Factor out base class for KVM reuse
  ioapic: Drop post-load irr initialization
  ioapic: Factor out base class for KVM reuse
  memory: Introduce memory_region_init_reservation
  kvm: Introduce core services for in-kernel irqchip support
  kvm: x86: Establish IRQ0 override control
  kvm: x86: Add user space part for in-kernel APIC
  kvm: x86: Add user space part for in-kernel i8259
  kvm: x86: Add user space part for in-kernel IOAPIC
  kvm: Arm in-kernel irqchip support

 Makefile.objs                  |    2 +-
 Makefile.target                |    6 +-
 configure                      |    1 +
 cpus.c                         |    6 +-
 hw/apic.c                      |  368 ++++++++--------------------------------
 hw/apic.h                      |    1 +
 hw/apic_common.c               |  273 +++++++++++++++++++++++++++++
 hw/apic_internal.h             |  123 +++++++++++++
 hw/i8259.c                     |  165 ++++++------------
 hw/i8259_common.c              |   96 +++++++++++
 hw/i8259_internal.h            |   76 ++++++++
 hw/ioapic.c                    |  152 ++++-------------
 hw/ioapic_common.c             |   70 ++++++++
 hw/ioapic_internal.h           |   99 +++++++++++
 hw/kvm/apic.c                  |  165 ++++++++++++++++++
 hw/{kvmclock.c => kvm/clock.c} |    4 +-
 hw/{kvmclock.h => kvm/clock.h} |    0
 hw/kvm/i8259.c                 |  173 +++++++++++++++++++
 hw/kvm/ioapic.c                |  144 ++++++++++++++++
 hw/msi.c                       |    8 +
 hw/msi.h                       |    2 +
 hw/msix.c                      |    9 +-
 hw/msix.h                      |    2 -
 hw/pc.c                        |   20 ++-
 hw/pc.h                        |    8 +-
 hw/pc_piix.c                   |   67 +++++++-
 kvm-all.c                      |  154 +++++++++++++++++
 kvm-stub.c                     |    5 +
 kvm.h                          |   14 ++
 memory.c                       |   36 ++++
 memory.h                       |   16 ++
 qemu-config.c                  |    4 +
 qemu-options.hx                |    5 +-
 sysemu.h                       |    1 -
 target-i386/kvm.c              |   49 ++++++
 trace-events                   |    2 +-
 vl.c                           |    1 -
 37 files changed, 1769 insertions(+), 558 deletions(-)
 create mode 100644 hw/apic_common.c
 create mode 100644 hw/apic_internal.h
 create mode 100644 hw/i8259_common.c
 create mode 100644 hw/i8259_internal.h
 create mode 100644 hw/ioapic_common.c
 create mode 100644 hw/ioapic_internal.h
 create mode 100644 hw/kvm/apic.c
 rename hw/{kvmclock.c => kvm/clock.c} (98%)
 rename hw/{kvmclock.h => kvm/clock.h} (100%)
 create mode 100644 hw/kvm/i8259.c
 create mode 100644 hw/kvm/ioapic.c

-- 
1.7.3.4

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH v6 01/18] msi: Generalize msix_supported to msi_supported
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:34   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:34 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl

Rename msix_supported to msi_supported and control MSI and MSI-X
activation this way. That was likely to original intention for this
flag, but MSI support came after MSI-X.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/msi.c  |    8 ++++++++
 hw/msi.h  |    2 ++
 hw/msix.c |    9 ++++-----
 hw/msix.h |    2 --
 hw/pc.c   |    4 ++--
 5 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/hw/msi.c b/hw/msi.c
index f214fcf..5d6ceb6 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -36,6 +36,9 @@
 
 #define PCI_MSI_VECTORS_MAX     32
 
+/* Flag for interrupt controller to declare MSI/MSI-X support */
+bool msi_supported;
+
 /* If we get rid of cap allocator, we won't need this. */
 static inline uint8_t msi_cap_sizeof(uint16_t flags)
 {
@@ -116,6 +119,11 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
     uint16_t flags;
     uint8_t cap_size;
     int config_offset;
+
+    if (!msi_supported) {
+        return -ENOTSUP;
+    }
+
     MSI_DEV_PRINTF(dev,
                    "init offset: 0x%"PRIx8" vector: %"PRId8
                    " 64bit %d mask %d\n",
diff --git a/hw/msi.h b/hw/msi.h
index 5766018..3040bb0 100644
--- a/hw/msi.h
+++ b/hw/msi.h
@@ -24,6 +24,8 @@
 #include "qemu-common.h"
 #include "pci.h"
 
+extern bool msi_supported;
+
 bool msi_enabled(const PCIDevice *dev);
 int msi_init(struct PCIDevice *dev, uint8_t offset,
              unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask);
diff --git a/hw/msix.c b/hw/msix.c
index 149eed2..107d4e5 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -12,6 +12,7 @@
  */
 
 #include "hw.h"
+#include "msi.h"
 #include "msix.h"
 #include "pci.h"
 #include "range.h"
@@ -32,9 +33,6 @@
 #define MSIX_MAX_ENTRIES 32
 
 
-/* Flag for interrupt controller to declare MSI-X support */
-int msix_supported;
-
 /* Add MSI-X capability to the config space for the device. */
 /* Given a bar and its size, add MSI-X table on top of it
  * and fill MSI-X capability in the config space.
@@ -235,10 +233,11 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
               unsigned bar_nr, unsigned bar_size)
 {
     int ret;
+
     /* Nothing to do if MSI is not supported by interrupt controller */
-    if (!msix_supported)
+    if (!msi_supported) {
         return -ENOTSUP;
-
+    }
     if (nentries > MSIX_MAX_ENTRIES)
         return -EINVAL;
 
diff --git a/hw/msix.h b/hw/msix.h
index 7e04336..5aba22b 100644
--- a/hw/msix.h
+++ b/hw/msix.h
@@ -29,6 +29,4 @@ void msix_notify(PCIDevice *dev, unsigned vector);
 
 void msix_reset(PCIDevice *dev);
 
-extern int msix_supported;
-
 #endif
diff --git a/hw/pc.c b/hw/pc.c
index f51afa8..3f69e09 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -36,7 +36,7 @@
 #include "elf.h"
 #include "multiboot.h"
 #include "mc146818rtc.h"
-#include "msix.h"
+#include "msi.h"
 #include "sysbus.h"
 #include "sysemu.h"
 #include "blockdev.h"
@@ -896,7 +896,7 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
         apic_mapped = 1;
     }
 
-    msix_supported = 1;
+    msi_supported = true;
 
     return dev;
 }
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 01/18] msi: Generalize msix_supported to msi_supported
@ 2012-01-13 17:34   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:34 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

Rename msix_supported to msi_supported and control MSI and MSI-X
activation this way. That was likely to original intention for this
flag, but MSI support came after MSI-X.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/msi.c  |    8 ++++++++
 hw/msi.h  |    2 ++
 hw/msix.c |    9 ++++-----
 hw/msix.h |    2 --
 hw/pc.c   |    4 ++--
 5 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/hw/msi.c b/hw/msi.c
index f214fcf..5d6ceb6 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -36,6 +36,9 @@
 
 #define PCI_MSI_VECTORS_MAX     32
 
+/* Flag for interrupt controller to declare MSI/MSI-X support */
+bool msi_supported;
+
 /* If we get rid of cap allocator, we won't need this. */
 static inline uint8_t msi_cap_sizeof(uint16_t flags)
 {
@@ -116,6 +119,11 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
     uint16_t flags;
     uint8_t cap_size;
     int config_offset;
+
+    if (!msi_supported) {
+        return -ENOTSUP;
+    }
+
     MSI_DEV_PRINTF(dev,
                    "init offset: 0x%"PRIx8" vector: %"PRId8
                    " 64bit %d mask %d\n",
diff --git a/hw/msi.h b/hw/msi.h
index 5766018..3040bb0 100644
--- a/hw/msi.h
+++ b/hw/msi.h
@@ -24,6 +24,8 @@
 #include "qemu-common.h"
 #include "pci.h"
 
+extern bool msi_supported;
+
 bool msi_enabled(const PCIDevice *dev);
 int msi_init(struct PCIDevice *dev, uint8_t offset,
              unsigned int nr_vectors, bool msi64bit, bool msi_per_vector_mask);
diff --git a/hw/msix.c b/hw/msix.c
index 149eed2..107d4e5 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -12,6 +12,7 @@
  */
 
 #include "hw.h"
+#include "msi.h"
 #include "msix.h"
 #include "pci.h"
 #include "range.h"
@@ -32,9 +33,6 @@
 #define MSIX_MAX_ENTRIES 32
 
 
-/* Flag for interrupt controller to declare MSI-X support */
-int msix_supported;
-
 /* Add MSI-X capability to the config space for the device. */
 /* Given a bar and its size, add MSI-X table on top of it
  * and fill MSI-X capability in the config space.
@@ -235,10 +233,11 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
               unsigned bar_nr, unsigned bar_size)
 {
     int ret;
+
     /* Nothing to do if MSI is not supported by interrupt controller */
-    if (!msix_supported)
+    if (!msi_supported) {
         return -ENOTSUP;
-
+    }
     if (nentries > MSIX_MAX_ENTRIES)
         return -EINVAL;
 
diff --git a/hw/msix.h b/hw/msix.h
index 7e04336..5aba22b 100644
--- a/hw/msix.h
+++ b/hw/msix.h
@@ -29,6 +29,4 @@ void msix_notify(PCIDevice *dev, unsigned vector);
 
 void msix_reset(PCIDevice *dev);
 
-extern int msix_supported;
-
 #endif
diff --git a/hw/pc.c b/hw/pc.c
index f51afa8..3f69e09 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -36,7 +36,7 @@
 #include "elf.h"
 #include "multiboot.h"
 #include "mc146818rtc.h"
-#include "msix.h"
+#include "msi.h"
 #include "sysbus.h"
 #include "sysemu.h"
 #include "blockdev.h"
@@ -896,7 +896,7 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
         apic_mapped = 1;
     }
 
-    msix_supported = 1;
+    msi_supported = true;
 
     return dev;
 }
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 02/18] kvm: Move kvmclock into hw/kvm folder
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:34   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:34 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl

More KVM-specific devices will come, so let's start with moving the
kvmclock into a dedicated folder.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.target                |    4 ++--
 configure                      |    1 +
 hw/{kvmclock.c => kvm/clock.c} |    4 ++--
 hw/{kvmclock.h => kvm/clock.h} |    0
 hw/pc_piix.c                   |    2 +-
 5 files changed, 6 insertions(+), 5 deletions(-)
 rename hw/{kvmclock.c => kvm/clock.c} (98%)
 rename hw/{kvmclock.h => kvm/clock.h} (100%)

diff --git a/Makefile.target b/Makefile.target
index 3261383..974cd72 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -228,7 +228,7 @@ obj-i386-y += vmport.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvmclock.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
@@ -418,7 +418,7 @@ qmp-commands-old.h: $(SRC_PATH)/qmp-commands.hx
 
 clean:
 	rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
-	rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o
+	rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o kvm/*.o
 	rm -f hmp-commands.h qmp-commands-old.h gdbstub-xml.c
 ifdef CONFIG_TRACE_SYSTEMTAP
 	rm -f *.stp
diff --git a/configure b/configure
index 640e815..11edff6 100755
--- a/configure
+++ b/configure
@@ -3384,6 +3384,7 @@ mkdir -p $target_dir/fpu
 mkdir -p $target_dir/tcg
 mkdir -p $target_dir/ide
 mkdir -p $target_dir/9pfs
+mkdir -p $target_dir/kvm
 if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" -o "$target" = "arm-bsd-user" -o "$target" = "armeb-bsd-user" ; then
   mkdir -p $target_dir/nwfpe
 fi
diff --git a/hw/kvmclock.c b/hw/kvm/clock.c
similarity index 98%
rename from hw/kvmclock.c
rename to hw/kvm/clock.c
index 5388bc4..5983271 100644
--- a/hw/kvmclock.c
+++ b/hw/kvm/clock.c
@@ -13,9 +13,9 @@
 
 #include "qemu-common.h"
 #include "sysemu.h"
-#include "sysbus.h"
 #include "kvm.h"
-#include "kvmclock.h"
+#include "hw/sysbus.h"
+#include "hw/kvm/clock.h"
 
 #include <linux/kvm.h>
 #include <linux/kvm_para.h>
diff --git a/hw/kvmclock.h b/hw/kvm/clock.h
similarity index 100%
rename from hw/kvmclock.h
rename to hw/kvm/clock.h
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index b70431f..f44f00e 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -34,7 +34,7 @@
 #include "boards.h"
 #include "ide.h"
 #include "kvm.h"
-#include "kvmclock.h"
+#include "kvm/clock.h"
 #include "sysemu.h"
 #include "sysbus.h"
 #include "arch_init.h"
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 02/18] kvm: Move kvmclock into hw/kvm folder
@ 2012-01-13 17:34   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:34 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

More KVM-specific devices will come, so let's start with moving the
kvmclock into a dedicated folder.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.target                |    4 ++--
 configure                      |    1 +
 hw/{kvmclock.c => kvm/clock.c} |    4 ++--
 hw/{kvmclock.h => kvm/clock.h} |    0
 hw/pc_piix.c                   |    2 +-
 5 files changed, 6 insertions(+), 5 deletions(-)
 rename hw/{kvmclock.c => kvm/clock.c} (98%)
 rename hw/{kvmclock.h => kvm/clock.h} (100%)

diff --git a/Makefile.target b/Makefile.target
index 3261383..974cd72 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -228,7 +228,7 @@ obj-i386-y += vmport.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvmclock.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
@@ -418,7 +418,7 @@ qmp-commands-old.h: $(SRC_PATH)/qmp-commands.hx
 
 clean:
 	rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o
-	rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o
+	rm -f *.d */*.d tcg/*.o ide/*.o 9pfs/*.o kvm/*.o
 	rm -f hmp-commands.h qmp-commands-old.h gdbstub-xml.c
 ifdef CONFIG_TRACE_SYSTEMTAP
 	rm -f *.stp
diff --git a/configure b/configure
index 640e815..11edff6 100755
--- a/configure
+++ b/configure
@@ -3384,6 +3384,7 @@ mkdir -p $target_dir/fpu
 mkdir -p $target_dir/tcg
 mkdir -p $target_dir/ide
 mkdir -p $target_dir/9pfs
+mkdir -p $target_dir/kvm
 if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" -o "$target" = "arm-bsd-user" -o "$target" = "armeb-bsd-user" ; then
   mkdir -p $target_dir/nwfpe
 fi
diff --git a/hw/kvmclock.c b/hw/kvm/clock.c
similarity index 98%
rename from hw/kvmclock.c
rename to hw/kvm/clock.c
index 5388bc4..5983271 100644
--- a/hw/kvmclock.c
+++ b/hw/kvm/clock.c
@@ -13,9 +13,9 @@
 
 #include "qemu-common.h"
 #include "sysemu.h"
-#include "sysbus.h"
 #include "kvm.h"
-#include "kvmclock.h"
+#include "hw/sysbus.h"
+#include "hw/kvm/clock.h"
 
 #include <linux/kvm.h>
 #include <linux/kvm_para.h>
diff --git a/hw/kvmclock.h b/hw/kvm/clock.h
similarity index 100%
rename from hw/kvmclock.h
rename to hw/kvm/clock.h
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index b70431f..f44f00e 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -34,7 +34,7 @@
 #include "boards.h"
 #include "ide.h"
 #include "kvm.h"
-#include "kvmclock.h"
+#include "kvm/clock.h"
 #include "sysemu.h"
 #include "sysbus.h"
 #include "arch_init.h"
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 03/18] apic: Stop timer on reset
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:34   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:34 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl

All LVTs are masked on reset, so the timer becomes ineffective. Letting
it tick nevertheless is harmless, but will at least create a spurious
trace event.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/apic.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/hw/apic.c b/hw/apic.c
index 9d0f460..4b97b17 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -528,6 +528,8 @@ void apic_init_reset(DeviceState *d)
     s->initial_count_load_time = 0;
     s->next_time = 0;
     s->wait_for_sipi = 1;
+
+    qemu_del_timer(s->timer);
 }
 
 static void apic_startup(APICState *s, int vector_num)
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 03/18] apic: Stop timer on reset
@ 2012-01-13 17:34   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:34 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

All LVTs are masked on reset, so the timer becomes ineffective. Letting
it tick nevertheless is harmless, but will at least create a spurious
trace event.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/apic.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/hw/apic.c b/hw/apic.c
index 9d0f460..4b97b17 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -528,6 +528,8 @@ void apic_init_reset(DeviceState *d)
     s->initial_count_load_time = 0;
     s->next_time = 0;
     s->wait_for_sipi = 1;
+
+    qemu_del_timer(s->timer);
 }
 
 static void apic_startup(APICState *s, int vector_num)
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 04/18] apic: Inject external NMI events via LINT1
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:34   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:34 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl,
	Lai Jiangshan

On real hardware, NMI button events are injected via the LINT1 line of
the APICs. E.g. kdump expect this wiring and gets upset if the per-APIC
LINT1 mask is not respected, i.e. if NMIs are injected to VCPUs that
should not receive them. Change the APIC emulation code to reflect this.

Based on qemu-kvm patch by Lai Jiangshan.

CC: Lai Jiangshan <laijs@cn.fujitsu.com>
Reported-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 cpus.c    |    6 +++++-
 hw/apic.c |    7 +++++++
 hw/apic.h |    1 +
 3 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/cpus.c b/cpus.c
index b421a71..857f96f 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1225,7 +1225,11 @@ void qmp_inject_nmi(Error **errp)
     CPUState *env;
 
     for (env = first_cpu; env != NULL; env = env->next_cpu) {
-        cpu_interrupt(env, CPU_INTERRUPT_NMI);
+        if (!env->apic_state) {
+            cpu_interrupt(env, CPU_INTERRUPT_NMI);
+        } else {
+            apic_deliver_nmi(env->apic_state);
+        }
     }
 #else
     error_set(errp, QERR_UNSUPPORTED);
diff --git a/hw/apic.c b/hw/apic.c
index 4b97b17..b9d733c 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -205,6 +205,13 @@ void apic_deliver_pic_intr(DeviceState *d, int level)
     }
 }
 
+void apic_deliver_nmi(DeviceState *d)
+{
+    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+
+    apic_local_deliver(s, APIC_LVT_LINT1);
+}
+
 #define foreach_apic(apic, deliver_bitmask, code) \
 {\
     int __i, __j, __mask;\
diff --git a/hw/apic.h b/hw/apic.h
index a5c910f..a62d83b 100644
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -8,6 +8,7 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
                       uint8_t vector_num, uint8_t trigger_mode);
 int apic_accept_pic_intr(DeviceState *s);
 void apic_deliver_pic_intr(DeviceState *s, int level);
+void apic_deliver_nmi(DeviceState *d);
 int apic_get_interrupt(DeviceState *s);
 void apic_reset_irq_delivered(void);
 int apic_get_irq_delivered(void);
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 04/18] apic: Inject external NMI events via LINT1
@ 2012-01-13 17:34   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:34 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Anthony Liguori, Lai Jiangshan, kvm, Michael S. Tsirkin,
	qemu-devel, Blue Swirl

On real hardware, NMI button events are injected via the LINT1 line of
the APICs. E.g. kdump expect this wiring and gets upset if the per-APIC
LINT1 mask is not respected, i.e. if NMIs are injected to VCPUs that
should not receive them. Change the APIC emulation code to reflect this.

Based on qemu-kvm patch by Lai Jiangshan.

CC: Lai Jiangshan <laijs@cn.fujitsu.com>
Reported-by: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 cpus.c    |    6 +++++-
 hw/apic.c |    7 +++++++
 hw/apic.h |    1 +
 3 files changed, 13 insertions(+), 1 deletions(-)

diff --git a/cpus.c b/cpus.c
index b421a71..857f96f 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1225,7 +1225,11 @@ void qmp_inject_nmi(Error **errp)
     CPUState *env;
 
     for (env = first_cpu; env != NULL; env = env->next_cpu) {
-        cpu_interrupt(env, CPU_INTERRUPT_NMI);
+        if (!env->apic_state) {
+            cpu_interrupt(env, CPU_INTERRUPT_NMI);
+        } else {
+            apic_deliver_nmi(env->apic_state);
+        }
     }
 #else
     error_set(errp, QERR_UNSUPPORTED);
diff --git a/hw/apic.c b/hw/apic.c
index 4b97b17..b9d733c 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -205,6 +205,13 @@ void apic_deliver_pic_intr(DeviceState *d, int level)
     }
 }
 
+void apic_deliver_nmi(DeviceState *d)
+{
+    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+
+    apic_local_deliver(s, APIC_LVT_LINT1);
+}
+
 #define foreach_apic(apic, deliver_bitmask, code) \
 {\
     int __i, __j, __mask;\
diff --git a/hw/apic.h b/hw/apic.h
index a5c910f..a62d83b 100644
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -8,6 +8,7 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
                       uint8_t vector_num, uint8_t trigger_mode);
 int apic_accept_pic_intr(DeviceState *s);
 void apic_deliver_pic_intr(DeviceState *s, int level);
+void apic_deliver_nmi(DeviceState *d);
 int apic_get_interrupt(DeviceState *s);
 void apic_reset_irq_delivered(void);
 int apic_get_irq_delivered(void);
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 05/18] apic: Introduce apic_report_irq_delivered
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:35   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl

The in-kernel i8259 and IOAPIC backends for KVM will need this, so
encapsulate the shared bits.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/apic.c    |   11 ++++++++---
 hw/apic.h    |    1 +
 trace-events |    2 +-
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/hw/apic.c b/hw/apic.c
index b9d733c..bec493b 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -413,6 +413,13 @@ static void apic_update_irq(APICState *s)
     }
 }
 
+void apic_report_irq_delivered(int delivered)
+{
+    apic_irq_delivered += delivered;
+
+    trace_apic_report_irq_delivered(apic_irq_delivered);
+}
+
 void apic_reset_irq_delivered(void)
 {
     trace_apic_reset_irq_delivered(apic_irq_delivered);
@@ -429,9 +436,7 @@ int apic_get_irq_delivered(void)
 
 static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
 {
-    apic_irq_delivered += !get_bit(s->irr, vector_num);
-
-    trace_apic_set_irq(apic_irq_delivered);
+    apic_report_irq_delivered(!get_bit(s->irr, vector_num));
 
     set_bit(s->irr, vector_num);
     if (trigger_mode)
diff --git a/hw/apic.h b/hw/apic.h
index a62d83b..8173d8a 100644
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -10,6 +10,7 @@ int apic_accept_pic_intr(DeviceState *s);
 void apic_deliver_pic_intr(DeviceState *s, int level);
 void apic_deliver_nmi(DeviceState *d);
 int apic_get_interrupt(DeviceState *s);
+void apic_report_irq_delivered(int delivered);
 void apic_reset_irq_delivered(void);
 int apic_get_irq_delivered(void);
 void cpu_set_apic_base(DeviceState *s, uint64_t val);
diff --git a/trace-events b/trace-events
index 514849a..c101216 100644
--- a/trace-events
+++ b/trace-events
@@ -95,9 +95,9 @@ cpu_get_apic_base(uint64_t val) "%016"PRIx64
 apic_mem_readl(uint64_t addr, uint32_t val)  "%"PRIx64" = %08x"
 apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
 # coalescing
+apic_report_irq_delivered(int apic_irq_delivered) "coalescing %d"
 apic_reset_irq_delivered(int apic_irq_delivered) "old coalescing %d"
 apic_get_irq_delivered(int apic_irq_delivered) "returning coalescing %d"
-apic_set_irq(int apic_irq_delivered) "coalescing %d"
 
 # hw/cs4231.c
 cs4231_mem_readl_dreg(uint32_t reg, uint32_t ret) "read dreg %d: 0x%02x"
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 05/18] apic: Introduce apic_report_irq_delivered
@ 2012-01-13 17:35   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

The in-kernel i8259 and IOAPIC backends for KVM will need this, so
encapsulate the shared bits.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/apic.c    |   11 ++++++++---
 hw/apic.h    |    1 +
 trace-events |    2 +-
 3 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/hw/apic.c b/hw/apic.c
index b9d733c..bec493b 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -413,6 +413,13 @@ static void apic_update_irq(APICState *s)
     }
 }
 
+void apic_report_irq_delivered(int delivered)
+{
+    apic_irq_delivered += delivered;
+
+    trace_apic_report_irq_delivered(apic_irq_delivered);
+}
+
 void apic_reset_irq_delivered(void)
 {
     trace_apic_reset_irq_delivered(apic_irq_delivered);
@@ -429,9 +436,7 @@ int apic_get_irq_delivered(void)
 
 static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
 {
-    apic_irq_delivered += !get_bit(s->irr, vector_num);
-
-    trace_apic_set_irq(apic_irq_delivered);
+    apic_report_irq_delivered(!get_bit(s->irr, vector_num));
 
     set_bit(s->irr, vector_num);
     if (trigger_mode)
diff --git a/hw/apic.h b/hw/apic.h
index a62d83b..8173d8a 100644
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -10,6 +10,7 @@ int apic_accept_pic_intr(DeviceState *s);
 void apic_deliver_pic_intr(DeviceState *s, int level);
 void apic_deliver_nmi(DeviceState *d);
 int apic_get_interrupt(DeviceState *s);
+void apic_report_irq_delivered(int delivered);
 void apic_reset_irq_delivered(void);
 int apic_get_irq_delivered(void);
 void cpu_set_apic_base(DeviceState *s, uint64_t val);
diff --git a/trace-events b/trace-events
index 514849a..c101216 100644
--- a/trace-events
+++ b/trace-events
@@ -95,9 +95,9 @@ cpu_get_apic_base(uint64_t val) "%016"PRIx64
 apic_mem_readl(uint64_t addr, uint32_t val)  "%"PRIx64" = %08x"
 apic_mem_writel(uint64_t addr, uint32_t val) "%"PRIx64" = %08x"
 # coalescing
+apic_report_irq_delivered(int apic_irq_delivered) "coalescing %d"
 apic_reset_irq_delivered(int apic_irq_delivered) "old coalescing %d"
 apic_get_irq_delivered(int apic_irq_delivered) "returning coalescing %d"
-apic_set_irq(int apic_irq_delivered) "coalescing %d"
 
 # hw/cs4231.c
 cs4231_mem_readl_dreg(uint32_t reg, uint32_t ret) "read dreg %d: 0x%02x"
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 06/18] apic: Factor out base class for KVM reuse
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:35   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl

The KVM in-kernel APIC model will reuse parts of the user space model
while providing the same frontend view to guest and most management
interfaces.

Factor out an APIC base class to encapsulate those parts that will be
shared by user space and KVM model. This class offers callback hooks for
init, base/tpr setting, and the external NMI delivery that will be
set via APICCommonInfo super-structure and implemented specifically in
the subclasses.

Furthermore, a common vmstate and a common list of qdev properties is
provided with the base clase. Also the reset handler will be shared.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.target    |    2 +-
 hw/apic.c          |  353 +++++++++-------------------------------------------
 hw/apic.h          |    1 -
 hw/apic_common.c   |  236 +++++++++++++++++++++++++++++++++++
 hw/apic_internal.h |  121 ++++++++++++++++++
 5 files changed, 420 insertions(+), 293 deletions(-)
 create mode 100644 hw/apic_common.c
 create mode 100644 hw/apic_internal.h

diff --git a/Makefile.target b/Makefile.target
index 974cd72..a8acece 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -223,7 +223,7 @@ obj-$(CONFIG_IVSHMEM) += ivshmem.o
 # Hardware support
 obj-i386-y += vga.o
 obj-i386-y += mc146818rtc.o pc.o
-obj-i386-y += cirrus_vga.o sga.o apic.o ioapic.o piix_pci.o
+obj-i386-y += cirrus_vga.o sga.o apic_common.o apic.o ioapic.o piix_pci.o
 obj-i386-y += vmport.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
diff --git a/hw/apic.c b/hw/apic.c
index bec493b..8f1d5aa 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -16,53 +16,13 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, see <http://www.gnu.org/licenses/>
  */
-#include "hw.h"
+#include "apic_internal.h"
 #include "apic.h"
 #include "ioapic.h"
-#include "qemu-timer.h"
 #include "host-utils.h"
-#include "sysbus.h"
 #include "trace.h"
 #include "pc.h"
 
-/* APIC Local Vector Table */
-#define APIC_LVT_TIMER   0
-#define APIC_LVT_THERMAL 1
-#define APIC_LVT_PERFORM 2
-#define APIC_LVT_LINT0   3
-#define APIC_LVT_LINT1   4
-#define APIC_LVT_ERROR   5
-#define APIC_LVT_NB      6
-
-/* APIC delivery modes */
-#define APIC_DM_FIXED	0
-#define APIC_DM_LOWPRI	1
-#define APIC_DM_SMI	2
-#define APIC_DM_NMI	4
-#define APIC_DM_INIT	5
-#define APIC_DM_SIPI	6
-#define APIC_DM_EXTINT	7
-
-/* APIC destination mode */
-#define APIC_DESTMODE_FLAT	0xf
-#define APIC_DESTMODE_CLUSTER	1
-
-#define APIC_TRIGGER_EDGE  0
-#define APIC_TRIGGER_LEVEL 1
-
-#define	APIC_LVT_TIMER_PERIODIC		(1<<17)
-#define	APIC_LVT_MASKED			(1<<16)
-#define	APIC_LVT_LEVEL_TRIGGER		(1<<15)
-#define	APIC_LVT_REMOTE_IRR		(1<<14)
-#define	APIC_INPUT_POLARITY		(1<<13)
-#define	APIC_SEND_PENDING		(1<<12)
-
-#define ESR_ILLEGAL_ADDRESS (1 << 7)
-
-#define APIC_SV_DIRECTED_IO             (1<<12)
-#define APIC_SV_ENABLE                  (1<<8)
-
-#define MAX_APICS 255
 #define MAX_APIC_WORDS 8
 
 /* Intel APIC constants: from include/asm/msidef.h */
@@ -75,43 +35,16 @@
 #define MSI_ADDR_DEST_ID_SHIFT		12
 #define	MSI_ADDR_DEST_ID_MASK		0x00ffff0
 
-#define MSI_ADDR_SIZE                   0x100000
-
 typedef struct APICState APICState;
 
 struct APICState {
-    SysBusDevice busdev;
-    MemoryRegion io_memory;
-    void *cpu_env;
-    uint32_t apicbase;
-    uint8_t id;
-    uint8_t arb_id;
-    uint8_t tpr;
-    uint32_t spurious_vec;
-    uint8_t log_dest;
-    uint8_t dest_mode;
-    uint32_t isr[8];  /* in service register */
-    uint32_t tmr[8];  /* trigger mode register */
-    uint32_t irr[8]; /* interrupt request register */
-    uint32_t lvt[APIC_LVT_NB];
-    uint32_t esr; /* error register */
-    uint32_t icr[2];
-
-    uint32_t divide_conf;
-    int count_shift;
-    uint32_t initial_count;
-    int64_t initial_count_load_time, next_time;
-    uint32_t idx;
-    QEMUTimer *timer;
-    int sipi_vector;
-    int wait_for_sipi;
+    APICCommonState apic;
 };
 
-static APICState *local_apics[MAX_APICS + 1];
-static int apic_irq_delivered;
+static APICCommonState *local_apics[MAX_APICS + 1];
 
-static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
-static void apic_update_irq(APICState *s);
+static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode);
+static void apic_update_irq(APICCommonState *s);
 static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
                                       uint8_t dest, uint8_t dest_mode);
 
@@ -151,7 +84,7 @@ static inline int get_bit(uint32_t *tab, int index)
     return !!(tab[i] & mask);
 }
 
-static void apic_local_deliver(APICState *s, int vector)
+static void apic_local_deliver(APICCommonState *s, int vector)
 {
     uint32_t lvt = s->lvt[vector];
     int trigger_mode;
@@ -185,7 +118,7 @@ static void apic_local_deliver(APICState *s, int vector)
 
 void apic_deliver_pic_intr(DeviceState *d, int level)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
 
     if (level) {
         apic_local_deliver(s, APIC_LVT_LINT0);
@@ -205,10 +138,8 @@ void apic_deliver_pic_intr(DeviceState *d, int level)
     }
 }
 
-void apic_deliver_nmi(DeviceState *d)
+static void apic_external_nmi(APICCommonState *s)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
     apic_local_deliver(s, APIC_LVT_LINT1);
 }
 
@@ -234,7 +165,7 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask,
                              uint8_t delivery_mode, uint8_t vector_num,
                              uint8_t trigger_mode)
 {
-    APICState *apic_iter;
+    APICCommonState *apic_iter;
 
     switch (delivery_mode) {
         case APIC_DM_LOWPRI:
@@ -300,14 +231,8 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
     apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
 }
 
-void cpu_set_apic_base(DeviceState *d, uint64_t val)
+static void apic_set_base(APICCommonState *s, uint64_t val)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
-    trace_cpu_set_apic_base(val);
-
-    if (!s)
-        return;
     s->apicbase = (val & 0xfffff000) |
         (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
     /* if disabled, cannot be enabled again */
@@ -318,32 +243,12 @@ void cpu_set_apic_base(DeviceState *d, uint64_t val)
     }
 }
 
-uint64_t cpu_get_apic_base(DeviceState *d)
-{
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
-    trace_cpu_get_apic_base(s ? (uint64_t)s->apicbase: 0);
-
-    return s ? s->apicbase : 0;
-}
-
-void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
+static void apic_set_tpr(APICCommonState *s, uint8_t val)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
-    if (!s)
-        return;
     s->tpr = (val & 0x0f) << 4;
     apic_update_irq(s);
 }
 
-uint8_t cpu_get_apic_tpr(DeviceState *d)
-{
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
-    return s ? s->tpr >> 4 : 0;
-}
-
 /* return -1 if no bit is set */
 static int get_highest_priority_int(uint32_t *tab)
 {
@@ -356,7 +261,7 @@ static int get_highest_priority_int(uint32_t *tab)
     return -1;
 }
 
-static int apic_get_ppr(APICState *s)
+static int apic_get_ppr(APICCommonState *s)
 {
     int tpr, isrv, ppr;
 
@@ -372,7 +277,7 @@ static int apic_get_ppr(APICState *s)
     return ppr;
 }
 
-static int apic_get_arb_pri(APICState *s)
+static int apic_get_arb_pri(APICCommonState *s)
 {
     /* XXX: arbitration */
     return 0;
@@ -384,7 +289,7 @@ static int apic_get_arb_pri(APICState *s)
  * 0  - no interrupt,
  * >0 - interrupt number
  */
-static int apic_irq_pending(APICState *s)
+static int apic_irq_pending(APICCommonState *s)
 {
     int irrv, ppr;
     irrv = get_highest_priority_int(s->irr);
@@ -400,7 +305,7 @@ static int apic_irq_pending(APICState *s)
 }
 
 /* signal the CPU if an irq is pending */
-static void apic_update_irq(APICState *s)
+static void apic_update_irq(APICCommonState *s)
 {
     if (!(s->spurious_vec & APIC_SV_ENABLE)) {
         return;
@@ -413,28 +318,7 @@ static void apic_update_irq(APICState *s)
     }
 }
 
-void apic_report_irq_delivered(int delivered)
-{
-    apic_irq_delivered += delivered;
-
-    trace_apic_report_irq_delivered(apic_irq_delivered);
-}
-
-void apic_reset_irq_delivered(void)
-{
-    trace_apic_reset_irq_delivered(apic_irq_delivered);
-
-    apic_irq_delivered = 0;
-}
-
-int apic_get_irq_delivered(void)
-{
-    trace_apic_get_irq_delivered(apic_irq_delivered);
-
-    return apic_irq_delivered;
-}
-
-static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
+static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
 {
     apic_report_irq_delivered(!get_bit(s->irr, vector_num));
 
@@ -446,7 +330,7 @@ static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
     apic_update_irq(s);
 }
 
-static void apic_eoi(APICState *s)
+static void apic_eoi(APICCommonState *s)
 {
     int isrv;
     isrv = get_highest_priority_int(s->isr);
@@ -461,7 +345,7 @@ static void apic_eoi(APICState *s)
 
 static int apic_find_dest(uint8_t dest)
 {
-    APICState *apic = local_apics[dest];
+    APICCommonState *apic = local_apics[dest];
     int i;
 
     if (apic && apic->id == dest)
@@ -481,7 +365,7 @@ static int apic_find_dest(uint8_t dest)
 static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
                                       uint8_t dest, uint8_t dest_mode)
 {
-    APICState *apic_iter;
+    APICCommonState *apic_iter;
     int i;
 
     if (dest_mode == 0) {
@@ -515,36 +399,7 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
     }
 }
 
-void apic_init_reset(DeviceState *d)
-{
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-    int i;
-
-    if (!s)
-        return;
-
-    s->tpr = 0;
-    s->spurious_vec = 0xff;
-    s->log_dest = 0;
-    s->dest_mode = 0xf;
-    memset(s->isr, 0, sizeof(s->isr));
-    memset(s->tmr, 0, sizeof(s->tmr));
-    memset(s->irr, 0, sizeof(s->irr));
-    for(i = 0; i < APIC_LVT_NB; i++)
-        s->lvt[i] = 1 << 16; /* mask LVT */
-    s->esr = 0;
-    memset(s->icr, 0, sizeof(s->icr));
-    s->divide_conf = 0;
-    s->count_shift = 0;
-    s->initial_count = 0;
-    s->initial_count_load_time = 0;
-    s->next_time = 0;
-    s->wait_for_sipi = 1;
-
-    qemu_del_timer(s->timer);
-}
-
-static void apic_startup(APICState *s, int vector_num)
+static void apic_startup(APICCommonState *s, int vector_num)
 {
     s->sipi_vector = vector_num;
     cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
@@ -552,7 +407,7 @@ static void apic_startup(APICState *s, int vector_num)
 
 void apic_sipi(DeviceState *d)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
 
     cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
 
@@ -566,10 +421,10 @@ static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
                          uint8_t delivery_mode, uint8_t vector_num,
                          uint8_t trigger_mode)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
     uint32_t deliver_bitmask[MAX_APIC_WORDS];
     int dest_shorthand = (s->icr[0] >> 18) & 3;
-    APICState *apic_iter;
+    APICCommonState *apic_iter;
 
     switch (dest_shorthand) {
     case 0:
@@ -612,7 +467,7 @@ static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
 
 int apic_get_interrupt(DeviceState *d)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
     int intno;
 
     /* if the APIC is installed or enabled, we let the 8259 handle the
@@ -637,7 +492,7 @@ int apic_get_interrupt(DeviceState *d)
 
 int apic_accept_pic_intr(DeviceState *d)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
     uint32_t lvt0;
 
     if (!s)
@@ -652,7 +507,7 @@ int apic_accept_pic_intr(DeviceState *d)
     return 0;
 }
 
-static uint32_t apic_get_current_count(APICState *s)
+static uint32_t apic_get_current_count(APICCommonState *s)
 {
     int64_t d;
     uint32_t val;
@@ -670,7 +525,7 @@ static uint32_t apic_get_current_count(APICState *s)
     return val;
 }
 
-static void apic_timer_update(APICState *s, int64_t current_time)
+static void apic_timer_update(APICCommonState *s, int64_t current_time)
 {
     int64_t next_time, d;
 
@@ -697,7 +552,7 @@ static void apic_timer_update(APICState *s, int64_t current_time)
 
 static void apic_timer(void *opaque)
 {
-    APICState *s = opaque;
+    APICCommonState *s = opaque;
 
     apic_local_deliver(s, APIC_LVT_TIMER);
     apic_timer_update(s, s->next_time);
@@ -724,7 +579,7 @@ static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
 static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
 {
     DeviceState *d;
-    APICState *s;
+    APICCommonState *s;
     uint32_t val;
     int index;
 
@@ -732,7 +587,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
     if (!d) {
         return 0;
     }
-    s = DO_UPCAST(APICState, busdev.qdev, d);
+    s = DO_UPCAST(APICCommonState, busdev.qdev, d);
 
     index = (addr >> 4) & 0xff;
     switch(index) {
@@ -815,7 +670,7 @@ static void apic_send_msi(target_phys_addr_t addr, uint32_t data)
 static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     DeviceState *d;
-    APICState *s;
+    APICCommonState *s;
     int index = (addr >> 4) & 0xff;
     if (addr > 0xfff || !index) {
         /* MSI and MMIO APIC are at the same memory location,
@@ -831,7 +686,7 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     if (!d) {
         return;
     }
-    s = DO_UPCAST(APICState, busdev.qdev, d);
+    s = DO_UPCAST(APICCommonState, busdev.qdev, d);
 
     trace_apic_mem_writel(addr, val);
 
@@ -904,96 +759,6 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     }
 }
 
-/* This function is only used for old state version 1 and 2 */
-static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
-{
-    APICState *s = opaque;
-    int i;
-
-    if (version_id > 2)
-        return -EINVAL;
-
-    /* XXX: what if the base changes? (registered memory regions) */
-    qemu_get_be32s(f, &s->apicbase);
-    qemu_get_8s(f, &s->id);
-    qemu_get_8s(f, &s->arb_id);
-    qemu_get_8s(f, &s->tpr);
-    qemu_get_be32s(f, &s->spurious_vec);
-    qemu_get_8s(f, &s->log_dest);
-    qemu_get_8s(f, &s->dest_mode);
-    for (i = 0; i < 8; i++) {
-        qemu_get_be32s(f, &s->isr[i]);
-        qemu_get_be32s(f, &s->tmr[i]);
-        qemu_get_be32s(f, &s->irr[i]);
-    }
-    for (i = 0; i < APIC_LVT_NB; i++) {
-        qemu_get_be32s(f, &s->lvt[i]);
-    }
-    qemu_get_be32s(f, &s->esr);
-    qemu_get_be32s(f, &s->icr[0]);
-    qemu_get_be32s(f, &s->icr[1]);
-    qemu_get_be32s(f, &s->divide_conf);
-    s->count_shift=qemu_get_be32(f);
-    qemu_get_be32s(f, &s->initial_count);
-    s->initial_count_load_time=qemu_get_be64(f);
-    s->next_time=qemu_get_be64(f);
-
-    if (version_id >= 2)
-        qemu_get_timer(f, s->timer);
-    return 0;
-}
-
-static const VMStateDescription vmstate_apic = {
-    .name = "apic",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 1,
-    .load_state_old = apic_load_old,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32(apicbase, APICState),
-        VMSTATE_UINT8(id, APICState),
-        VMSTATE_UINT8(arb_id, APICState),
-        VMSTATE_UINT8(tpr, APICState),
-        VMSTATE_UINT32(spurious_vec, APICState),
-        VMSTATE_UINT8(log_dest, APICState),
-        VMSTATE_UINT8(dest_mode, APICState),
-        VMSTATE_UINT32_ARRAY(isr, APICState, 8),
-        VMSTATE_UINT32_ARRAY(tmr, APICState, 8),
-        VMSTATE_UINT32_ARRAY(irr, APICState, 8),
-        VMSTATE_UINT32_ARRAY(lvt, APICState, APIC_LVT_NB),
-        VMSTATE_UINT32(esr, APICState),
-        VMSTATE_UINT32_ARRAY(icr, APICState, 2),
-        VMSTATE_UINT32(divide_conf, APICState),
-        VMSTATE_INT32(count_shift, APICState),
-        VMSTATE_UINT32(initial_count, APICState),
-        VMSTATE_INT64(initial_count_load_time, APICState),
-        VMSTATE_INT64(next_time, APICState),
-        VMSTATE_TIMER(timer, APICState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void apic_reset(DeviceState *d)
-{
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-    int bsp;
-
-    bsp = cpu_is_bsp(s->cpu_env);
-    s->apicbase = 0xfee00000 |
-        (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
-
-    apic_init_reset(d);
-
-    if (bsp) {
-        /*
-         * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
-         * time typically by BIOS, so PIC interrupt can be delivered to the
-         * processor when local APIC is enabled.
-         */
-        s->lvt[APIC_LVT_LINT0] = 0x700;
-    }
-}
-
 static const MemoryRegionOps apic_io_ops = {
     .old_mmio = {
         .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, },
@@ -1002,41 +767,47 @@ static const MemoryRegionOps apic_io_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static int apic_init1(SysBusDevice *dev)
+static void apic_init(APICCommonState *s)
 {
-    APICState *s = FROM_SYSBUS(APICState, dev);
-    static int last_apic_idx;
-
-    if (last_apic_idx >= MAX_APICS) {
-        return -1;
-    }
-    memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic",
-                          MSI_ADDR_SIZE);
-    sysbus_init_mmio(dev, &s->io_memory);
+    memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic-msi",
+                          MSI_SPACE_SIZE);
 
     s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s);
-    s->idx = last_apic_idx++;
     local_apics[s->idx] = s;
-    return 0;
 }
 
-static SysBusDeviceInfo apic_info = {
-    .init = apic_init1,
-    .qdev.name = "apic",
-    .qdev.size = sizeof(APICState),
-    .qdev.vmsd = &vmstate_apic,
-    .qdev.reset = apic_reset,
-    .qdev.no_user = 1,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT8("id", APICState, id, -1),
-        DEFINE_PROP_PTR("cpu_env", APICState, cpu_env),
-        DEFINE_PROP_END_OF_LIST(),
+static const VMStateDescription vmstate_apic = {
+    .name = "apic",
+    .version_id = APIC_VMSTATE_VERSION,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(apic, APICState, 0, vmstate_apic_common,
+                       APICCommonState),
+        VMSTATE_END_OF_LIST()
     }
 };
 
+static APICCommonInfo apic_info = {
+    .busdev.init = apic_init_common,
+    .busdev.qdev.name = "apic",
+    .busdev.qdev.size = sizeof(APICState),
+    .busdev.qdev.vmsd = &vmstate_apic,
+    .busdev.qdev.reset = apic_reset_common,
+    .busdev.qdev.no_user = 1,
+    .busdev.qdev.props = (Property[]) {
+        APIC_PROPERTIES_COMMON(APICState, apic),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+    .init = apic_init,
+    .set_base = apic_set_base,
+    .set_tpr = apic_set_tpr,
+    .external_nmi = apic_external_nmi,
+};
+
 static void apic_register_devices(void)
 {
-    sysbus_register_withprop(&apic_info);
+    sysbus_register_withprop(&apic_info.busdev);
 }
 
 device_init(apic_register_devices)
diff --git a/hw/apic.h b/hw/apic.h
index 8173d8a..a62d83b 100644
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -10,7 +10,6 @@ int apic_accept_pic_intr(DeviceState *s);
 void apic_deliver_pic_intr(DeviceState *s, int level);
 void apic_deliver_nmi(DeviceState *d);
 int apic_get_interrupt(DeviceState *s);
-void apic_report_irq_delivered(int delivered);
 void apic_reset_irq_delivered(void);
 int apic_get_irq_delivered(void);
 void cpu_set_apic_base(DeviceState *s, uint64_t val);
diff --git a/hw/apic_common.c b/hw/apic_common.c
new file mode 100644
index 0000000..455d44c
--- /dev/null
+++ b/hw/apic_common.c
@@ -0,0 +1,236 @@
+/*
+ *  APIC support - common bits of emulated and KVM kernel model
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#include "apic.h"
+#include "apic_internal.h"
+#include "trace.h"
+
+static QSIMPLEQ_HEAD(, APICBackend) backends =
+    QSIMPLEQ_HEAD_INITIALIZER(backends);
+static int apic_irq_delivered;
+
+void cpu_set_apic_base(DeviceState *d, uint64_t val)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonInfo *info;
+
+    trace_cpu_set_apic_base(val);
+
+    if (s) {
+        info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+        info->set_base(s, val);
+    }
+}
+
+uint64_t cpu_get_apic_base(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    trace_cpu_get_apic_base(s ? (uint64_t)s->apicbase : 0);
+
+    return s ? s->apicbase : 0;
+}
+
+void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonInfo *info;
+
+    if (s) {
+        info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+        info->set_tpr(s, val);
+    }
+}
+
+uint8_t cpu_get_apic_tpr(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    return s ? s->tpr >> 4 : 0;
+}
+
+void apic_report_irq_delivered(int delivered)
+{
+    apic_irq_delivered += delivered;
+
+    trace_apic_report_irq_delivered(apic_irq_delivered);
+}
+
+void apic_reset_irq_delivered(void)
+{
+    trace_apic_reset_irq_delivered(apic_irq_delivered);
+
+    apic_irq_delivered = 0;
+}
+
+int apic_get_irq_delivered(void)
+{
+    trace_apic_get_irq_delivered(apic_irq_delivered);
+
+    return apic_irq_delivered;
+}
+
+void apic_deliver_nmi(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonInfo *info;
+
+    info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+    info->external_nmi(s);
+}
+
+void apic_init_reset(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    int i;
+
+    if (!s) {
+        return;
+    }
+    s->tpr = 0;
+    s->spurious_vec = 0xff;
+    s->log_dest = 0;
+    s->dest_mode = 0xf;
+    memset(s->isr, 0, sizeof(s->isr));
+    memset(s->tmr, 0, sizeof(s->tmr));
+    memset(s->irr, 0, sizeof(s->irr));
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        s->lvt[i] = APIC_LVT_MASKED;
+    }
+    s->esr = 0;
+    memset(s->icr, 0, sizeof(s->icr));
+    s->divide_conf = 0;
+    s->count_shift = 0;
+    s->initial_count = 0;
+    s->initial_count_load_time = 0;
+    s->next_time = 0;
+    s->wait_for_sipi = 1;
+
+    qemu_del_timer(s->timer);
+}
+
+void apic_reset_common(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    bool bsp;
+
+    bsp = cpu_is_bsp(s->cpu_env);
+    s->apicbase = 0xfee00000 |
+        (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
+
+    apic_init_reset(d);
+
+    if (bsp) {
+        /*
+         * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
+         * time typically by BIOS, so PIC interrupt can be delivered to the
+         * processor when local APIC is enabled.
+         */
+        s->lvt[APIC_LVT_LINT0] = 0x700;
+    }
+}
+
+/* This function is only used for old state version 1 and 2 */
+static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
+{
+    APICCommonState *s = opaque;
+    int i;
+
+    if (version_id > 2) {
+        return -EINVAL;
+    }
+
+    /* XXX: what if the base changes? (registered memory regions) */
+    qemu_get_be32s(f, &s->apicbase);
+    qemu_get_8s(f, &s->id);
+    qemu_get_8s(f, &s->arb_id);
+    qemu_get_8s(f, &s->tpr);
+    qemu_get_be32s(f, &s->spurious_vec);
+    qemu_get_8s(f, &s->log_dest);
+    qemu_get_8s(f, &s->dest_mode);
+    for (i = 0; i < 8; i++) {
+        qemu_get_be32s(f, &s->isr[i]);
+        qemu_get_be32s(f, &s->tmr[i]);
+        qemu_get_be32s(f, &s->irr[i]);
+    }
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        qemu_get_be32s(f, &s->lvt[i]);
+    }
+    qemu_get_be32s(f, &s->esr);
+    qemu_get_be32s(f, &s->icr[0]);
+    qemu_get_be32s(f, &s->icr[1]);
+    qemu_get_be32s(f, &s->divide_conf);
+    s->count_shift = qemu_get_be32(f);
+    qemu_get_be32s(f, &s->initial_count);
+    s->initial_count_load_time = qemu_get_be64(f);
+    s->next_time = qemu_get_be64(f);
+
+    if (version_id >= 2) {
+        qemu_get_timer(f, s->timer);
+    }
+    return 0;
+}
+
+const VMStateDescription vmstate_apic_common = {
+    .name = "apic",
+    .version_id = APIC_VMSTATE_VERSION,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .load_state_old = apic_load_old,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(apicbase, APICCommonState),
+        VMSTATE_UINT8(id, APICCommonState),
+        VMSTATE_UINT8(arb_id, APICCommonState),
+        VMSTATE_UINT8(tpr, APICCommonState),
+        VMSTATE_UINT32(spurious_vec, APICCommonState),
+        VMSTATE_UINT8(log_dest, APICCommonState),
+        VMSTATE_UINT8(dest_mode, APICCommonState),
+        VMSTATE_UINT32_ARRAY(isr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(tmr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(irr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(lvt, APICCommonState, APIC_LVT_NB),
+        VMSTATE_UINT32(esr, APICCommonState),
+        VMSTATE_UINT32_ARRAY(icr, APICCommonState, 2),
+        VMSTATE_UINT32(divide_conf, APICCommonState),
+        VMSTATE_INT32(count_shift, APICCommonState),
+        VMSTATE_UINT32(initial_count, APICCommonState),
+        VMSTATE_INT64(initial_count_load_time, APICCommonState),
+        VMSTATE_INT64(next_time, APICCommonState),
+        VMSTATE_TIMER(timer, APICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+int apic_init_common(SysBusDevice *dev)
+{
+    APICCommonState *s = FROM_SYSBUS(APICCommonState, dev);
+    APICCommonInfo *info;
+    static int apic_no;
+
+    if (apic_no >= MAX_APICS) {
+        return -1;
+    }
+    s->idx = apic_no++;
+
+    info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+    info->init(s);
+
+    sysbus_init_mmio(&s->busdev, &s->io_memory);
+    return 0;
+}
diff --git a/hw/apic_internal.h b/hw/apic_internal.h
new file mode 100644
index 0000000..2ca18d4
--- /dev/null
+++ b/hw/apic_internal.h
@@ -0,0 +1,121 @@
+/*
+ *  APIC support - internal interfaces
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#ifndef QEMU_APIC_INTERNAL_H
+#define QEMU_APIC_INTERNAL_H
+
+#include "memory.h"
+#include "sysbus.h"
+#include "qemu-timer.h"
+
+/* APIC Local Vector Table */
+#define APIC_LVT_TIMER                  0
+#define APIC_LVT_THERMAL                1
+#define APIC_LVT_PERFORM                2
+#define APIC_LVT_LINT0                  3
+#define APIC_LVT_LINT1                  4
+#define APIC_LVT_ERROR                  5
+#define APIC_LVT_NB                     6
+
+/* APIC delivery modes */
+#define APIC_DM_FIXED                   0
+#define APIC_DM_LOWPRI                  1
+#define APIC_DM_SMI                     2
+#define APIC_DM_NMI                     4
+#define APIC_DM_INIT                    5
+#define APIC_DM_SIPI                    6
+#define APIC_DM_EXTINT                  7
+
+/* APIC destination mode */
+#define APIC_DESTMODE_FLAT              0xf
+#define APIC_DESTMODE_CLUSTER           1
+
+#define APIC_TRIGGER_EDGE               0
+#define APIC_TRIGGER_LEVEL              1
+
+#define APIC_LVT_TIMER_PERIODIC         (1<<17)
+#define APIC_LVT_MASKED                 (1<<16)
+#define APIC_LVT_LEVEL_TRIGGER          (1<<15)
+#define APIC_LVT_REMOTE_IRR             (1<<14)
+#define APIC_INPUT_POLARITY             (1<<13)
+#define APIC_SEND_PENDING               (1<<12)
+
+#define ESR_ILLEGAL_ADDRESS (1 << 7)
+
+#define APIC_SV_DIRECTED_IO             (1<<12)
+#define APIC_SV_ENABLE                  (1<<8)
+
+#define MAX_APICS 255
+
+#define MSI_SPACE_SIZE                  0x100000
+
+typedef struct APICCommonState APICCommonState;
+
+struct APICCommonState {
+    SysBusDevice busdev;
+    MemoryRegion io_memory;
+    void *cpu_env;
+    uint32_t apicbase;
+    uint8_t id;
+    uint8_t arb_id;
+    uint8_t tpr;
+    uint32_t spurious_vec;
+    uint8_t log_dest;
+    uint8_t dest_mode;
+    uint32_t isr[8];  /* in service register */
+    uint32_t tmr[8];  /* trigger mode register */
+    uint32_t irr[8]; /* interrupt request register */
+    uint32_t lvt[APIC_LVT_NB];
+    uint32_t esr; /* error register */
+    uint32_t icr[2];
+
+    uint32_t divide_conf;
+    int count_shift;
+    uint32_t initial_count;
+    int64_t initial_count_load_time;
+    int64_t next_time;
+    int idx;
+    QEMUTimer *timer;
+    int sipi_vector;
+    int wait_for_sipi;
+};
+
+typedef struct APICCommonInfo APICCommonInfo;
+
+struct APICCommonInfo {
+    SysBusDeviceInfo busdev;
+    void (*init)(APICCommonState *s);
+    void (*set_base)(APICCommonState *s, uint64_t val);
+    void (*set_tpr)(APICCommonState *s, uint8_t val);
+    void (*external_nmi)(APICCommonState *s);
+};
+
+#define APIC_VMSTATE_VERSION 3
+
+extern const VMStateDescription vmstate_apic_common;
+
+#define APIC_PROPERTIES_COMMON(cont_type, cont_var)         \
+    DEFINE_PROP_UINT8("id", cont_type, cont_var.id, -1),    \
+    DEFINE_PROP_PTR("cpu_env", cont_type, cont_var.cpu_env)
+
+void apic_report_irq_delivered(int delivered);
+void apic_reset_common(DeviceState *d);
+int apic_init_common(SysBusDevice *d);
+
+#endif /* !QEMU_APIC_INTERNAL_H */
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 06/18] apic: Factor out base class for KVM reuse
@ 2012-01-13 17:35   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

The KVM in-kernel APIC model will reuse parts of the user space model
while providing the same frontend view to guest and most management
interfaces.

Factor out an APIC base class to encapsulate those parts that will be
shared by user space and KVM model. This class offers callback hooks for
init, base/tpr setting, and the external NMI delivery that will be
set via APICCommonInfo super-structure and implemented specifically in
the subclasses.

Furthermore, a common vmstate and a common list of qdev properties is
provided with the base clase. Also the reset handler will be shared.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.target    |    2 +-
 hw/apic.c          |  353 +++++++++-------------------------------------------
 hw/apic.h          |    1 -
 hw/apic_common.c   |  236 +++++++++++++++++++++++++++++++++++
 hw/apic_internal.h |  121 ++++++++++++++++++
 5 files changed, 420 insertions(+), 293 deletions(-)
 create mode 100644 hw/apic_common.c
 create mode 100644 hw/apic_internal.h

diff --git a/Makefile.target b/Makefile.target
index 974cd72..a8acece 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -223,7 +223,7 @@ obj-$(CONFIG_IVSHMEM) += ivshmem.o
 # Hardware support
 obj-i386-y += vga.o
 obj-i386-y += mc146818rtc.o pc.o
-obj-i386-y += cirrus_vga.o sga.o apic.o ioapic.o piix_pci.o
+obj-i386-y += cirrus_vga.o sga.o apic_common.o apic.o ioapic.o piix_pci.o
 obj-i386-y += vmport.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
diff --git a/hw/apic.c b/hw/apic.c
index bec493b..8f1d5aa 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -16,53 +16,13 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library; if not, see <http://www.gnu.org/licenses/>
  */
-#include "hw.h"
+#include "apic_internal.h"
 #include "apic.h"
 #include "ioapic.h"
-#include "qemu-timer.h"
 #include "host-utils.h"
-#include "sysbus.h"
 #include "trace.h"
 #include "pc.h"
 
-/* APIC Local Vector Table */
-#define APIC_LVT_TIMER   0
-#define APIC_LVT_THERMAL 1
-#define APIC_LVT_PERFORM 2
-#define APIC_LVT_LINT0   3
-#define APIC_LVT_LINT1   4
-#define APIC_LVT_ERROR   5
-#define APIC_LVT_NB      6
-
-/* APIC delivery modes */
-#define APIC_DM_FIXED	0
-#define APIC_DM_LOWPRI	1
-#define APIC_DM_SMI	2
-#define APIC_DM_NMI	4
-#define APIC_DM_INIT	5
-#define APIC_DM_SIPI	6
-#define APIC_DM_EXTINT	7
-
-/* APIC destination mode */
-#define APIC_DESTMODE_FLAT	0xf
-#define APIC_DESTMODE_CLUSTER	1
-
-#define APIC_TRIGGER_EDGE  0
-#define APIC_TRIGGER_LEVEL 1
-
-#define	APIC_LVT_TIMER_PERIODIC		(1<<17)
-#define	APIC_LVT_MASKED			(1<<16)
-#define	APIC_LVT_LEVEL_TRIGGER		(1<<15)
-#define	APIC_LVT_REMOTE_IRR		(1<<14)
-#define	APIC_INPUT_POLARITY		(1<<13)
-#define	APIC_SEND_PENDING		(1<<12)
-
-#define ESR_ILLEGAL_ADDRESS (1 << 7)
-
-#define APIC_SV_DIRECTED_IO             (1<<12)
-#define APIC_SV_ENABLE                  (1<<8)
-
-#define MAX_APICS 255
 #define MAX_APIC_WORDS 8
 
 /* Intel APIC constants: from include/asm/msidef.h */
@@ -75,43 +35,16 @@
 #define MSI_ADDR_DEST_ID_SHIFT		12
 #define	MSI_ADDR_DEST_ID_MASK		0x00ffff0
 
-#define MSI_ADDR_SIZE                   0x100000
-
 typedef struct APICState APICState;
 
 struct APICState {
-    SysBusDevice busdev;
-    MemoryRegion io_memory;
-    void *cpu_env;
-    uint32_t apicbase;
-    uint8_t id;
-    uint8_t arb_id;
-    uint8_t tpr;
-    uint32_t spurious_vec;
-    uint8_t log_dest;
-    uint8_t dest_mode;
-    uint32_t isr[8];  /* in service register */
-    uint32_t tmr[8];  /* trigger mode register */
-    uint32_t irr[8]; /* interrupt request register */
-    uint32_t lvt[APIC_LVT_NB];
-    uint32_t esr; /* error register */
-    uint32_t icr[2];
-
-    uint32_t divide_conf;
-    int count_shift;
-    uint32_t initial_count;
-    int64_t initial_count_load_time, next_time;
-    uint32_t idx;
-    QEMUTimer *timer;
-    int sipi_vector;
-    int wait_for_sipi;
+    APICCommonState apic;
 };
 
-static APICState *local_apics[MAX_APICS + 1];
-static int apic_irq_delivered;
+static APICCommonState *local_apics[MAX_APICS + 1];
 
-static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
-static void apic_update_irq(APICState *s);
+static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode);
+static void apic_update_irq(APICCommonState *s);
 static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
                                       uint8_t dest, uint8_t dest_mode);
 
@@ -151,7 +84,7 @@ static inline int get_bit(uint32_t *tab, int index)
     return !!(tab[i] & mask);
 }
 
-static void apic_local_deliver(APICState *s, int vector)
+static void apic_local_deliver(APICCommonState *s, int vector)
 {
     uint32_t lvt = s->lvt[vector];
     int trigger_mode;
@@ -185,7 +118,7 @@ static void apic_local_deliver(APICState *s, int vector)
 
 void apic_deliver_pic_intr(DeviceState *d, int level)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
 
     if (level) {
         apic_local_deliver(s, APIC_LVT_LINT0);
@@ -205,10 +138,8 @@ void apic_deliver_pic_intr(DeviceState *d, int level)
     }
 }
 
-void apic_deliver_nmi(DeviceState *d)
+static void apic_external_nmi(APICCommonState *s)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
     apic_local_deliver(s, APIC_LVT_LINT1);
 }
 
@@ -234,7 +165,7 @@ static void apic_bus_deliver(const uint32_t *deliver_bitmask,
                              uint8_t delivery_mode, uint8_t vector_num,
                              uint8_t trigger_mode)
 {
-    APICState *apic_iter;
+    APICCommonState *apic_iter;
 
     switch (delivery_mode) {
         case APIC_DM_LOWPRI:
@@ -300,14 +231,8 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode, uint8_t delivery_mode,
     apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, trigger_mode);
 }
 
-void cpu_set_apic_base(DeviceState *d, uint64_t val)
+static void apic_set_base(APICCommonState *s, uint64_t val)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
-    trace_cpu_set_apic_base(val);
-
-    if (!s)
-        return;
     s->apicbase = (val & 0xfffff000) |
         (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
     /* if disabled, cannot be enabled again */
@@ -318,32 +243,12 @@ void cpu_set_apic_base(DeviceState *d, uint64_t val)
     }
 }
 
-uint64_t cpu_get_apic_base(DeviceState *d)
-{
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
-    trace_cpu_get_apic_base(s ? (uint64_t)s->apicbase: 0);
-
-    return s ? s->apicbase : 0;
-}
-
-void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
+static void apic_set_tpr(APICCommonState *s, uint8_t val)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
-    if (!s)
-        return;
     s->tpr = (val & 0x0f) << 4;
     apic_update_irq(s);
 }
 
-uint8_t cpu_get_apic_tpr(DeviceState *d)
-{
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-
-    return s ? s->tpr >> 4 : 0;
-}
-
 /* return -1 if no bit is set */
 static int get_highest_priority_int(uint32_t *tab)
 {
@@ -356,7 +261,7 @@ static int get_highest_priority_int(uint32_t *tab)
     return -1;
 }
 
-static int apic_get_ppr(APICState *s)
+static int apic_get_ppr(APICCommonState *s)
 {
     int tpr, isrv, ppr;
 
@@ -372,7 +277,7 @@ static int apic_get_ppr(APICState *s)
     return ppr;
 }
 
-static int apic_get_arb_pri(APICState *s)
+static int apic_get_arb_pri(APICCommonState *s)
 {
     /* XXX: arbitration */
     return 0;
@@ -384,7 +289,7 @@ static int apic_get_arb_pri(APICState *s)
  * 0  - no interrupt,
  * >0 - interrupt number
  */
-static int apic_irq_pending(APICState *s)
+static int apic_irq_pending(APICCommonState *s)
 {
     int irrv, ppr;
     irrv = get_highest_priority_int(s->irr);
@@ -400,7 +305,7 @@ static int apic_irq_pending(APICState *s)
 }
 
 /* signal the CPU if an irq is pending */
-static void apic_update_irq(APICState *s)
+static void apic_update_irq(APICCommonState *s)
 {
     if (!(s->spurious_vec & APIC_SV_ENABLE)) {
         return;
@@ -413,28 +318,7 @@ static void apic_update_irq(APICState *s)
     }
 }
 
-void apic_report_irq_delivered(int delivered)
-{
-    apic_irq_delivered += delivered;
-
-    trace_apic_report_irq_delivered(apic_irq_delivered);
-}
-
-void apic_reset_irq_delivered(void)
-{
-    trace_apic_reset_irq_delivered(apic_irq_delivered);
-
-    apic_irq_delivered = 0;
-}
-
-int apic_get_irq_delivered(void)
-{
-    trace_apic_get_irq_delivered(apic_irq_delivered);
-
-    return apic_irq_delivered;
-}
-
-static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
+static void apic_set_irq(APICCommonState *s, int vector_num, int trigger_mode)
 {
     apic_report_irq_delivered(!get_bit(s->irr, vector_num));
 
@@ -446,7 +330,7 @@ static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
     apic_update_irq(s);
 }
 
-static void apic_eoi(APICState *s)
+static void apic_eoi(APICCommonState *s)
 {
     int isrv;
     isrv = get_highest_priority_int(s->isr);
@@ -461,7 +345,7 @@ static void apic_eoi(APICState *s)
 
 static int apic_find_dest(uint8_t dest)
 {
-    APICState *apic = local_apics[dest];
+    APICCommonState *apic = local_apics[dest];
     int i;
 
     if (apic && apic->id == dest)
@@ -481,7 +365,7 @@ static int apic_find_dest(uint8_t dest)
 static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
                                       uint8_t dest, uint8_t dest_mode)
 {
-    APICState *apic_iter;
+    APICCommonState *apic_iter;
     int i;
 
     if (dest_mode == 0) {
@@ -515,36 +399,7 @@ static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
     }
 }
 
-void apic_init_reset(DeviceState *d)
-{
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-    int i;
-
-    if (!s)
-        return;
-
-    s->tpr = 0;
-    s->spurious_vec = 0xff;
-    s->log_dest = 0;
-    s->dest_mode = 0xf;
-    memset(s->isr, 0, sizeof(s->isr));
-    memset(s->tmr, 0, sizeof(s->tmr));
-    memset(s->irr, 0, sizeof(s->irr));
-    for(i = 0; i < APIC_LVT_NB; i++)
-        s->lvt[i] = 1 << 16; /* mask LVT */
-    s->esr = 0;
-    memset(s->icr, 0, sizeof(s->icr));
-    s->divide_conf = 0;
-    s->count_shift = 0;
-    s->initial_count = 0;
-    s->initial_count_load_time = 0;
-    s->next_time = 0;
-    s->wait_for_sipi = 1;
-
-    qemu_del_timer(s->timer);
-}
-
-static void apic_startup(APICState *s, int vector_num)
+static void apic_startup(APICCommonState *s, int vector_num)
 {
     s->sipi_vector = vector_num;
     cpu_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
@@ -552,7 +407,7 @@ static void apic_startup(APICState *s, int vector_num)
 
 void apic_sipi(DeviceState *d)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
 
     cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_SIPI);
 
@@ -566,10 +421,10 @@ static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
                          uint8_t delivery_mode, uint8_t vector_num,
                          uint8_t trigger_mode)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
     uint32_t deliver_bitmask[MAX_APIC_WORDS];
     int dest_shorthand = (s->icr[0] >> 18) & 3;
-    APICState *apic_iter;
+    APICCommonState *apic_iter;
 
     switch (dest_shorthand) {
     case 0:
@@ -612,7 +467,7 @@ static void apic_deliver(DeviceState *d, uint8_t dest, uint8_t dest_mode,
 
 int apic_get_interrupt(DeviceState *d)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
     int intno;
 
     /* if the APIC is installed or enabled, we let the 8259 handle the
@@ -637,7 +492,7 @@ int apic_get_interrupt(DeviceState *d)
 
 int apic_accept_pic_intr(DeviceState *d)
 {
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
     uint32_t lvt0;
 
     if (!s)
@@ -652,7 +507,7 @@ int apic_accept_pic_intr(DeviceState *d)
     return 0;
 }
 
-static uint32_t apic_get_current_count(APICState *s)
+static uint32_t apic_get_current_count(APICCommonState *s)
 {
     int64_t d;
     uint32_t val;
@@ -670,7 +525,7 @@ static uint32_t apic_get_current_count(APICState *s)
     return val;
 }
 
-static void apic_timer_update(APICState *s, int64_t current_time)
+static void apic_timer_update(APICCommonState *s, int64_t current_time)
 {
     int64_t next_time, d;
 
@@ -697,7 +552,7 @@ static void apic_timer_update(APICState *s, int64_t current_time)
 
 static void apic_timer(void *opaque)
 {
-    APICState *s = opaque;
+    APICCommonState *s = opaque;
 
     apic_local_deliver(s, APIC_LVT_TIMER);
     apic_timer_update(s, s->next_time);
@@ -724,7 +579,7 @@ static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
 static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
 {
     DeviceState *d;
-    APICState *s;
+    APICCommonState *s;
     uint32_t val;
     int index;
 
@@ -732,7 +587,7 @@ static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
     if (!d) {
         return 0;
     }
-    s = DO_UPCAST(APICState, busdev.qdev, d);
+    s = DO_UPCAST(APICCommonState, busdev.qdev, d);
 
     index = (addr >> 4) & 0xff;
     switch(index) {
@@ -815,7 +670,7 @@ static void apic_send_msi(target_phys_addr_t addr, uint32_t data)
 static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     DeviceState *d;
-    APICState *s;
+    APICCommonState *s;
     int index = (addr >> 4) & 0xff;
     if (addr > 0xfff || !index) {
         /* MSI and MMIO APIC are at the same memory location,
@@ -831,7 +686,7 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     if (!d) {
         return;
     }
-    s = DO_UPCAST(APICState, busdev.qdev, d);
+    s = DO_UPCAST(APICCommonState, busdev.qdev, d);
 
     trace_apic_mem_writel(addr, val);
 
@@ -904,96 +759,6 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     }
 }
 
-/* This function is only used for old state version 1 and 2 */
-static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
-{
-    APICState *s = opaque;
-    int i;
-
-    if (version_id > 2)
-        return -EINVAL;
-
-    /* XXX: what if the base changes? (registered memory regions) */
-    qemu_get_be32s(f, &s->apicbase);
-    qemu_get_8s(f, &s->id);
-    qemu_get_8s(f, &s->arb_id);
-    qemu_get_8s(f, &s->tpr);
-    qemu_get_be32s(f, &s->spurious_vec);
-    qemu_get_8s(f, &s->log_dest);
-    qemu_get_8s(f, &s->dest_mode);
-    for (i = 0; i < 8; i++) {
-        qemu_get_be32s(f, &s->isr[i]);
-        qemu_get_be32s(f, &s->tmr[i]);
-        qemu_get_be32s(f, &s->irr[i]);
-    }
-    for (i = 0; i < APIC_LVT_NB; i++) {
-        qemu_get_be32s(f, &s->lvt[i]);
-    }
-    qemu_get_be32s(f, &s->esr);
-    qemu_get_be32s(f, &s->icr[0]);
-    qemu_get_be32s(f, &s->icr[1]);
-    qemu_get_be32s(f, &s->divide_conf);
-    s->count_shift=qemu_get_be32(f);
-    qemu_get_be32s(f, &s->initial_count);
-    s->initial_count_load_time=qemu_get_be64(f);
-    s->next_time=qemu_get_be64(f);
-
-    if (version_id >= 2)
-        qemu_get_timer(f, s->timer);
-    return 0;
-}
-
-static const VMStateDescription vmstate_apic = {
-    .name = "apic",
-    .version_id = 3,
-    .minimum_version_id = 3,
-    .minimum_version_id_old = 1,
-    .load_state_old = apic_load_old,
-    .fields      = (VMStateField []) {
-        VMSTATE_UINT32(apicbase, APICState),
-        VMSTATE_UINT8(id, APICState),
-        VMSTATE_UINT8(arb_id, APICState),
-        VMSTATE_UINT8(tpr, APICState),
-        VMSTATE_UINT32(spurious_vec, APICState),
-        VMSTATE_UINT8(log_dest, APICState),
-        VMSTATE_UINT8(dest_mode, APICState),
-        VMSTATE_UINT32_ARRAY(isr, APICState, 8),
-        VMSTATE_UINT32_ARRAY(tmr, APICState, 8),
-        VMSTATE_UINT32_ARRAY(irr, APICState, 8),
-        VMSTATE_UINT32_ARRAY(lvt, APICState, APIC_LVT_NB),
-        VMSTATE_UINT32(esr, APICState),
-        VMSTATE_UINT32_ARRAY(icr, APICState, 2),
-        VMSTATE_UINT32(divide_conf, APICState),
-        VMSTATE_INT32(count_shift, APICState),
-        VMSTATE_UINT32(initial_count, APICState),
-        VMSTATE_INT64(initial_count_load_time, APICState),
-        VMSTATE_INT64(next_time, APICState),
-        VMSTATE_TIMER(timer, APICState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void apic_reset(DeviceState *d)
-{
-    APICState *s = DO_UPCAST(APICState, busdev.qdev, d);
-    int bsp;
-
-    bsp = cpu_is_bsp(s->cpu_env);
-    s->apicbase = 0xfee00000 |
-        (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
-
-    apic_init_reset(d);
-
-    if (bsp) {
-        /*
-         * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
-         * time typically by BIOS, so PIC interrupt can be delivered to the
-         * processor when local APIC is enabled.
-         */
-        s->lvt[APIC_LVT_LINT0] = 0x700;
-    }
-}
-
 static const MemoryRegionOps apic_io_ops = {
     .old_mmio = {
         .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, },
@@ -1002,41 +767,47 @@ static const MemoryRegionOps apic_io_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static int apic_init1(SysBusDevice *dev)
+static void apic_init(APICCommonState *s)
 {
-    APICState *s = FROM_SYSBUS(APICState, dev);
-    static int last_apic_idx;
-
-    if (last_apic_idx >= MAX_APICS) {
-        return -1;
-    }
-    memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic",
-                          MSI_ADDR_SIZE);
-    sysbus_init_mmio(dev, &s->io_memory);
+    memory_region_init_io(&s->io_memory, &apic_io_ops, s, "apic-msi",
+                          MSI_SPACE_SIZE);
 
     s->timer = qemu_new_timer_ns(vm_clock, apic_timer, s);
-    s->idx = last_apic_idx++;
     local_apics[s->idx] = s;
-    return 0;
 }
 
-static SysBusDeviceInfo apic_info = {
-    .init = apic_init1,
-    .qdev.name = "apic",
-    .qdev.size = sizeof(APICState),
-    .qdev.vmsd = &vmstate_apic,
-    .qdev.reset = apic_reset,
-    .qdev.no_user = 1,
-    .qdev.props = (Property[]) {
-        DEFINE_PROP_UINT8("id", APICState, id, -1),
-        DEFINE_PROP_PTR("cpu_env", APICState, cpu_env),
-        DEFINE_PROP_END_OF_LIST(),
+static const VMStateDescription vmstate_apic = {
+    .name = "apic",
+    .version_id = APIC_VMSTATE_VERSION,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(apic, APICState, 0, vmstate_apic_common,
+                       APICCommonState),
+        VMSTATE_END_OF_LIST()
     }
 };
 
+static APICCommonInfo apic_info = {
+    .busdev.init = apic_init_common,
+    .busdev.qdev.name = "apic",
+    .busdev.qdev.size = sizeof(APICState),
+    .busdev.qdev.vmsd = &vmstate_apic,
+    .busdev.qdev.reset = apic_reset_common,
+    .busdev.qdev.no_user = 1,
+    .busdev.qdev.props = (Property[]) {
+        APIC_PROPERTIES_COMMON(APICState, apic),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+    .init = apic_init,
+    .set_base = apic_set_base,
+    .set_tpr = apic_set_tpr,
+    .external_nmi = apic_external_nmi,
+};
+
 static void apic_register_devices(void)
 {
-    sysbus_register_withprop(&apic_info);
+    sysbus_register_withprop(&apic_info.busdev);
 }
 
 device_init(apic_register_devices)
diff --git a/hw/apic.h b/hw/apic.h
index 8173d8a..a62d83b 100644
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -10,7 +10,6 @@ int apic_accept_pic_intr(DeviceState *s);
 void apic_deliver_pic_intr(DeviceState *s, int level);
 void apic_deliver_nmi(DeviceState *d);
 int apic_get_interrupt(DeviceState *s);
-void apic_report_irq_delivered(int delivered);
 void apic_reset_irq_delivered(void);
 int apic_get_irq_delivered(void);
 void cpu_set_apic_base(DeviceState *s, uint64_t val);
diff --git a/hw/apic_common.c b/hw/apic_common.c
new file mode 100644
index 0000000..455d44c
--- /dev/null
+++ b/hw/apic_common.c
@@ -0,0 +1,236 @@
+/*
+ *  APIC support - common bits of emulated and KVM kernel model
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#include "apic.h"
+#include "apic_internal.h"
+#include "trace.h"
+
+static QSIMPLEQ_HEAD(, APICBackend) backends =
+    QSIMPLEQ_HEAD_INITIALIZER(backends);
+static int apic_irq_delivered;
+
+void cpu_set_apic_base(DeviceState *d, uint64_t val)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonInfo *info;
+
+    trace_cpu_set_apic_base(val);
+
+    if (s) {
+        info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+        info->set_base(s, val);
+    }
+}
+
+uint64_t cpu_get_apic_base(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    trace_cpu_get_apic_base(s ? (uint64_t)s->apicbase : 0);
+
+    return s ? s->apicbase : 0;
+}
+
+void cpu_set_apic_tpr(DeviceState *d, uint8_t val)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonInfo *info;
+
+    if (s) {
+        info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+        info->set_tpr(s, val);
+    }
+}
+
+uint8_t cpu_get_apic_tpr(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+
+    return s ? s->tpr >> 4 : 0;
+}
+
+void apic_report_irq_delivered(int delivered)
+{
+    apic_irq_delivered += delivered;
+
+    trace_apic_report_irq_delivered(apic_irq_delivered);
+}
+
+void apic_reset_irq_delivered(void)
+{
+    trace_apic_reset_irq_delivered(apic_irq_delivered);
+
+    apic_irq_delivered = 0;
+}
+
+int apic_get_irq_delivered(void)
+{
+    trace_apic_get_irq_delivered(apic_irq_delivered);
+
+    return apic_irq_delivered;
+}
+
+void apic_deliver_nmi(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    APICCommonInfo *info;
+
+    info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+    info->external_nmi(s);
+}
+
+void apic_init_reset(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    int i;
+
+    if (!s) {
+        return;
+    }
+    s->tpr = 0;
+    s->spurious_vec = 0xff;
+    s->log_dest = 0;
+    s->dest_mode = 0xf;
+    memset(s->isr, 0, sizeof(s->isr));
+    memset(s->tmr, 0, sizeof(s->tmr));
+    memset(s->irr, 0, sizeof(s->irr));
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        s->lvt[i] = APIC_LVT_MASKED;
+    }
+    s->esr = 0;
+    memset(s->icr, 0, sizeof(s->icr));
+    s->divide_conf = 0;
+    s->count_shift = 0;
+    s->initial_count = 0;
+    s->initial_count_load_time = 0;
+    s->next_time = 0;
+    s->wait_for_sipi = 1;
+
+    qemu_del_timer(s->timer);
+}
+
+void apic_reset_common(DeviceState *d)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    bool bsp;
+
+    bsp = cpu_is_bsp(s->cpu_env);
+    s->apicbase = 0xfee00000 |
+        (bsp ? MSR_IA32_APICBASE_BSP : 0) | MSR_IA32_APICBASE_ENABLE;
+
+    apic_init_reset(d);
+
+    if (bsp) {
+        /*
+         * LINT0 delivery mode on CPU #0 is set to ExtInt at initialization
+         * time typically by BIOS, so PIC interrupt can be delivered to the
+         * processor when local APIC is enabled.
+         */
+        s->lvt[APIC_LVT_LINT0] = 0x700;
+    }
+}
+
+/* This function is only used for old state version 1 and 2 */
+static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
+{
+    APICCommonState *s = opaque;
+    int i;
+
+    if (version_id > 2) {
+        return -EINVAL;
+    }
+
+    /* XXX: what if the base changes? (registered memory regions) */
+    qemu_get_be32s(f, &s->apicbase);
+    qemu_get_8s(f, &s->id);
+    qemu_get_8s(f, &s->arb_id);
+    qemu_get_8s(f, &s->tpr);
+    qemu_get_be32s(f, &s->spurious_vec);
+    qemu_get_8s(f, &s->log_dest);
+    qemu_get_8s(f, &s->dest_mode);
+    for (i = 0; i < 8; i++) {
+        qemu_get_be32s(f, &s->isr[i]);
+        qemu_get_be32s(f, &s->tmr[i]);
+        qemu_get_be32s(f, &s->irr[i]);
+    }
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        qemu_get_be32s(f, &s->lvt[i]);
+    }
+    qemu_get_be32s(f, &s->esr);
+    qemu_get_be32s(f, &s->icr[0]);
+    qemu_get_be32s(f, &s->icr[1]);
+    qemu_get_be32s(f, &s->divide_conf);
+    s->count_shift = qemu_get_be32(f);
+    qemu_get_be32s(f, &s->initial_count);
+    s->initial_count_load_time = qemu_get_be64(f);
+    s->next_time = qemu_get_be64(f);
+
+    if (version_id >= 2) {
+        qemu_get_timer(f, s->timer);
+    }
+    return 0;
+}
+
+const VMStateDescription vmstate_apic_common = {
+    .name = "apic",
+    .version_id = APIC_VMSTATE_VERSION,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .load_state_old = apic_load_old,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(apicbase, APICCommonState),
+        VMSTATE_UINT8(id, APICCommonState),
+        VMSTATE_UINT8(arb_id, APICCommonState),
+        VMSTATE_UINT8(tpr, APICCommonState),
+        VMSTATE_UINT32(spurious_vec, APICCommonState),
+        VMSTATE_UINT8(log_dest, APICCommonState),
+        VMSTATE_UINT8(dest_mode, APICCommonState),
+        VMSTATE_UINT32_ARRAY(isr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(tmr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(irr, APICCommonState, 8),
+        VMSTATE_UINT32_ARRAY(lvt, APICCommonState, APIC_LVT_NB),
+        VMSTATE_UINT32(esr, APICCommonState),
+        VMSTATE_UINT32_ARRAY(icr, APICCommonState, 2),
+        VMSTATE_UINT32(divide_conf, APICCommonState),
+        VMSTATE_INT32(count_shift, APICCommonState),
+        VMSTATE_UINT32(initial_count, APICCommonState),
+        VMSTATE_INT64(initial_count_load_time, APICCommonState),
+        VMSTATE_INT64(next_time, APICCommonState),
+        VMSTATE_TIMER(timer, APICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+int apic_init_common(SysBusDevice *dev)
+{
+    APICCommonState *s = FROM_SYSBUS(APICCommonState, dev);
+    APICCommonInfo *info;
+    static int apic_no;
+
+    if (apic_no >= MAX_APICS) {
+        return -1;
+    }
+    s->idx = apic_no++;
+
+    info = DO_UPCAST(APICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+    info->init(s);
+
+    sysbus_init_mmio(&s->busdev, &s->io_memory);
+    return 0;
+}
diff --git a/hw/apic_internal.h b/hw/apic_internal.h
new file mode 100644
index 0000000..2ca18d4
--- /dev/null
+++ b/hw/apic_internal.h
@@ -0,0 +1,121 @@
+/*
+ *  APIC support - internal interfaces
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#ifndef QEMU_APIC_INTERNAL_H
+#define QEMU_APIC_INTERNAL_H
+
+#include "memory.h"
+#include "sysbus.h"
+#include "qemu-timer.h"
+
+/* APIC Local Vector Table */
+#define APIC_LVT_TIMER                  0
+#define APIC_LVT_THERMAL                1
+#define APIC_LVT_PERFORM                2
+#define APIC_LVT_LINT0                  3
+#define APIC_LVT_LINT1                  4
+#define APIC_LVT_ERROR                  5
+#define APIC_LVT_NB                     6
+
+/* APIC delivery modes */
+#define APIC_DM_FIXED                   0
+#define APIC_DM_LOWPRI                  1
+#define APIC_DM_SMI                     2
+#define APIC_DM_NMI                     4
+#define APIC_DM_INIT                    5
+#define APIC_DM_SIPI                    6
+#define APIC_DM_EXTINT                  7
+
+/* APIC destination mode */
+#define APIC_DESTMODE_FLAT              0xf
+#define APIC_DESTMODE_CLUSTER           1
+
+#define APIC_TRIGGER_EDGE               0
+#define APIC_TRIGGER_LEVEL              1
+
+#define APIC_LVT_TIMER_PERIODIC         (1<<17)
+#define APIC_LVT_MASKED                 (1<<16)
+#define APIC_LVT_LEVEL_TRIGGER          (1<<15)
+#define APIC_LVT_REMOTE_IRR             (1<<14)
+#define APIC_INPUT_POLARITY             (1<<13)
+#define APIC_SEND_PENDING               (1<<12)
+
+#define ESR_ILLEGAL_ADDRESS (1 << 7)
+
+#define APIC_SV_DIRECTED_IO             (1<<12)
+#define APIC_SV_ENABLE                  (1<<8)
+
+#define MAX_APICS 255
+
+#define MSI_SPACE_SIZE                  0x100000
+
+typedef struct APICCommonState APICCommonState;
+
+struct APICCommonState {
+    SysBusDevice busdev;
+    MemoryRegion io_memory;
+    void *cpu_env;
+    uint32_t apicbase;
+    uint8_t id;
+    uint8_t arb_id;
+    uint8_t tpr;
+    uint32_t spurious_vec;
+    uint8_t log_dest;
+    uint8_t dest_mode;
+    uint32_t isr[8];  /* in service register */
+    uint32_t tmr[8];  /* trigger mode register */
+    uint32_t irr[8]; /* interrupt request register */
+    uint32_t lvt[APIC_LVT_NB];
+    uint32_t esr; /* error register */
+    uint32_t icr[2];
+
+    uint32_t divide_conf;
+    int count_shift;
+    uint32_t initial_count;
+    int64_t initial_count_load_time;
+    int64_t next_time;
+    int idx;
+    QEMUTimer *timer;
+    int sipi_vector;
+    int wait_for_sipi;
+};
+
+typedef struct APICCommonInfo APICCommonInfo;
+
+struct APICCommonInfo {
+    SysBusDeviceInfo busdev;
+    void (*init)(APICCommonState *s);
+    void (*set_base)(APICCommonState *s, uint64_t val);
+    void (*set_tpr)(APICCommonState *s, uint8_t val);
+    void (*external_nmi)(APICCommonState *s);
+};
+
+#define APIC_VMSTATE_VERSION 3
+
+extern const VMStateDescription vmstate_apic_common;
+
+#define APIC_PROPERTIES_COMMON(cont_type, cont_var)         \
+    DEFINE_PROP_UINT8("id", cont_type, cont_var.id, -1),    \
+    DEFINE_PROP_PTR("cpu_env", cont_type, cont_var.cpu_env)
+
+void apic_report_irq_delivered(int delivered);
+void apic_reset_common(DeviceState *d);
+int apic_init_common(SysBusDevice *d);
+
+#endif /* !QEMU_APIC_INTERNAL_H */
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 07/18] apic: Open-code timer save/restore
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:35   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl

To enable migration between accelerated and non-accelerated APIC models,
we will need to handle the timer saving and restoring specially and can
no longer rely on the automatics of VMSTATE_TIMER. Specifically,
accelerated model will not start any QEMUTimer.

This patch therefore factors out the generic bits into apic_next_timer
and uses the post-load callback to implemented model-specific logic.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/apic.c          |   33 +++++++++++++++------------------
 hw/apic_common.c   |   41 +++++++++++++++++++++++++++++++++++++++--
 hw/apic_internal.h |    2 ++
 3 files changed, 56 insertions(+), 20 deletions(-)

diff --git a/hw/apic.c b/hw/apic.c
index 8f1d5aa..94b0841 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -527,25 +527,9 @@ static uint32_t apic_get_current_count(APICCommonState *s)
 
 static void apic_timer_update(APICCommonState *s, int64_t current_time)
 {
-    int64_t next_time, d;
-
-    if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
-        d = (current_time - s->initial_count_load_time) >>
-            s->count_shift;
-        if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
-            if (!s->initial_count)
-                goto no_timer;
-            d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
-        } else {
-            if (d >= s->initial_count)
-                goto no_timer;
-            d = (uint64_t)s->initial_count + 1;
-        }
-        next_time = s->initial_count_load_time + (d << s->count_shift);
-        qemu_mod_timer(s->timer, next_time);
-        s->next_time = next_time;
+    if (apic_next_timer(s, current_time)) {
+        qemu_mod_timer(s->timer, s->next_time);
     } else {
-    no_timer:
         qemu_del_timer(s->timer);
     }
 }
@@ -759,6 +743,18 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     }
 }
 
+static int apic_post_load(void *opaque, int version_id)
+{
+    APICState *s = opaque;
+
+    if (s->apic.timer_expiry != -1) {
+        qemu_mod_timer(s->apic.timer, s->apic.timer_expiry);
+    } else {
+        qemu_del_timer(s->apic.timer);
+    }
+    return 0;
+}
+
 static const MemoryRegionOps apic_io_ops = {
     .old_mmio = {
         .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, },
@@ -781,6 +777,7 @@ static const VMStateDescription vmstate_apic = {
     .version_id = APIC_VMSTATE_VERSION,
     .minimum_version_id = 3,
     .minimum_version_id_old = 1,
+    .post_load = apic_post_load,
     .fields = (VMStateField[]) {
         VMSTATE_STRUCT(apic, APICState, 0, vmstate_apic_common,
                        APICCommonState),
diff --git a/hw/apic_common.c b/hw/apic_common.c
index 455d44c..1aeb909 100644
--- a/hw/apic_common.c
+++ b/hw/apic_common.c
@@ -95,6 +95,39 @@ void apic_deliver_nmi(DeviceState *d)
     info->external_nmi(s);
 }
 
+bool apic_next_timer(APICCommonState *s, int64_t current_time)
+{
+    int64_t d;
+
+    /* We need to store the timer state separately to support APIC
+     * implementations that maintain a non-QEMU timer, e.g. inside the
+     * host kernel. This open-coded state allows us to migrate between
+     * both models. */
+    s->timer_expiry = -1;
+
+    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) {
+        return false;
+    }
+
+    d = (current_time - s->initial_count_load_time) >> s->count_shift;
+
+    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
+        if (!s->initial_count) {
+            return false;
+        }
+        d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
+            ((uint64_t)s->initial_count + 1);
+    } else {
+        if (d >= s->initial_count) {
+            return false;
+        }
+        d = (uint64_t)s->initial_count + 1;
+    }
+    s->next_time = s->initial_count_load_time + (d << s->count_shift);
+    s->timer_expiry = s->next_time;
+    return true;
+}
+
 void apic_init_reset(DeviceState *d)
 {
     APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
@@ -122,7 +155,10 @@ void apic_init_reset(DeviceState *d)
     s->next_time = 0;
     s->wait_for_sipi = 1;
 
-    qemu_del_timer(s->timer);
+    if (s->timer) {
+        qemu_del_timer(s->timer);
+    }
+    s->timer_expiry = -1;
 }
 
 void apic_reset_common(DeviceState *d)
@@ -212,7 +248,8 @@ const VMStateDescription vmstate_apic_common = {
         VMSTATE_UINT32(initial_count, APICCommonState),
         VMSTATE_INT64(initial_count_load_time, APICCommonState),
         VMSTATE_INT64(next_time, APICCommonState),
-        VMSTATE_TIMER(timer, APICCommonState),
+        VMSTATE_INT64(timer_expiry,
+                      APICCommonState), /* open-coded timer state */
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/hw/apic_internal.h b/hw/apic_internal.h
index 2ca18d4..eaddf7f 100644
--- a/hw/apic_internal.h
+++ b/hw/apic_internal.h
@@ -92,6 +92,7 @@ struct APICCommonState {
     int64_t next_time;
     int idx;
     QEMUTimer *timer;
+    int64_t timer_expiry;
     int sipi_vector;
     int wait_for_sipi;
 };
@@ -115,6 +116,7 @@ extern const VMStateDescription vmstate_apic_common;
     DEFINE_PROP_PTR("cpu_env", cont_type, cont_var.cpu_env)
 
 void apic_report_irq_delivered(int delivered);
+bool apic_next_timer(APICCommonState *s, int64_t current_time);
 void apic_reset_common(DeviceState *d);
 int apic_init_common(SysBusDevice *d);
 
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 07/18] apic: Open-code timer save/restore
@ 2012-01-13 17:35   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

To enable migration between accelerated and non-accelerated APIC models,
we will need to handle the timer saving and restoring specially and can
no longer rely on the automatics of VMSTATE_TIMER. Specifically,
accelerated model will not start any QEMUTimer.

This patch therefore factors out the generic bits into apic_next_timer
and uses the post-load callback to implemented model-specific logic.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/apic.c          |   33 +++++++++++++++------------------
 hw/apic_common.c   |   41 +++++++++++++++++++++++++++++++++++++++--
 hw/apic_internal.h |    2 ++
 3 files changed, 56 insertions(+), 20 deletions(-)

diff --git a/hw/apic.c b/hw/apic.c
index 8f1d5aa..94b0841 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -527,25 +527,9 @@ static uint32_t apic_get_current_count(APICCommonState *s)
 
 static void apic_timer_update(APICCommonState *s, int64_t current_time)
 {
-    int64_t next_time, d;
-
-    if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
-        d = (current_time - s->initial_count_load_time) >>
-            s->count_shift;
-        if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
-            if (!s->initial_count)
-                goto no_timer;
-            d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
-        } else {
-            if (d >= s->initial_count)
-                goto no_timer;
-            d = (uint64_t)s->initial_count + 1;
-        }
-        next_time = s->initial_count_load_time + (d << s->count_shift);
-        qemu_mod_timer(s->timer, next_time);
-        s->next_time = next_time;
+    if (apic_next_timer(s, current_time)) {
+        qemu_mod_timer(s->timer, s->next_time);
     } else {
-    no_timer:
         qemu_del_timer(s->timer);
     }
 }
@@ -759,6 +743,18 @@ static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
     }
 }
 
+static int apic_post_load(void *opaque, int version_id)
+{
+    APICState *s = opaque;
+
+    if (s->apic.timer_expiry != -1) {
+        qemu_mod_timer(s->apic.timer, s->apic.timer_expiry);
+    } else {
+        qemu_del_timer(s->apic.timer);
+    }
+    return 0;
+}
+
 static const MemoryRegionOps apic_io_ops = {
     .old_mmio = {
         .read = { apic_mem_readb, apic_mem_readw, apic_mem_readl, },
@@ -781,6 +777,7 @@ static const VMStateDescription vmstate_apic = {
     .version_id = APIC_VMSTATE_VERSION,
     .minimum_version_id = 3,
     .minimum_version_id_old = 1,
+    .post_load = apic_post_load,
     .fields = (VMStateField[]) {
         VMSTATE_STRUCT(apic, APICState, 0, vmstate_apic_common,
                        APICCommonState),
diff --git a/hw/apic_common.c b/hw/apic_common.c
index 455d44c..1aeb909 100644
--- a/hw/apic_common.c
+++ b/hw/apic_common.c
@@ -95,6 +95,39 @@ void apic_deliver_nmi(DeviceState *d)
     info->external_nmi(s);
 }
 
+bool apic_next_timer(APICCommonState *s, int64_t current_time)
+{
+    int64_t d;
+
+    /* We need to store the timer state separately to support APIC
+     * implementations that maintain a non-QEMU timer, e.g. inside the
+     * host kernel. This open-coded state allows us to migrate between
+     * both models. */
+    s->timer_expiry = -1;
+
+    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED) {
+        return false;
+    }
+
+    d = (current_time - s->initial_count_load_time) >> s->count_shift;
+
+    if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
+        if (!s->initial_count) {
+            return false;
+        }
+        d = ((d / ((uint64_t)s->initial_count + 1)) + 1) *
+            ((uint64_t)s->initial_count + 1);
+    } else {
+        if (d >= s->initial_count) {
+            return false;
+        }
+        d = (uint64_t)s->initial_count + 1;
+    }
+    s->next_time = s->initial_count_load_time + (d << s->count_shift);
+    s->timer_expiry = s->next_time;
+    return true;
+}
+
 void apic_init_reset(DeviceState *d)
 {
     APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
@@ -122,7 +155,10 @@ void apic_init_reset(DeviceState *d)
     s->next_time = 0;
     s->wait_for_sipi = 1;
 
-    qemu_del_timer(s->timer);
+    if (s->timer) {
+        qemu_del_timer(s->timer);
+    }
+    s->timer_expiry = -1;
 }
 
 void apic_reset_common(DeviceState *d)
@@ -212,7 +248,8 @@ const VMStateDescription vmstate_apic_common = {
         VMSTATE_UINT32(initial_count, APICCommonState),
         VMSTATE_INT64(initial_count_load_time, APICCommonState),
         VMSTATE_INT64(next_time, APICCommonState),
-        VMSTATE_TIMER(timer, APICCommonState),
+        VMSTATE_INT64(timer_expiry,
+                      APICCommonState), /* open-coded timer state */
         VMSTATE_END_OF_LIST()
     }
 };
diff --git a/hw/apic_internal.h b/hw/apic_internal.h
index 2ca18d4..eaddf7f 100644
--- a/hw/apic_internal.h
+++ b/hw/apic_internal.h
@@ -92,6 +92,7 @@ struct APICCommonState {
     int64_t next_time;
     int idx;
     QEMUTimer *timer;
+    int64_t timer_expiry;
     int sipi_vector;
     int wait_for_sipi;
 };
@@ -115,6 +116,7 @@ extern const VMStateDescription vmstate_apic_common;
     DEFINE_PROP_PTR("cpu_env", cont_type, cont_var.cpu_env)
 
 void apic_report_irq_delivered(int delivered);
+bool apic_next_timer(APICCommonState *s, int64_t current_time);
 void apic_reset_common(DeviceState *d);
 int apic_init_common(SysBusDevice *d);
 
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 08/18] i8259: Completely privatize PicState
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:35   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

Use DeviceState instead of PicState in the public i8259 API. This is
cleaner and allows to reorganize the PIC data structures for KVM reuse.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/i8259.c |   15 ++++++++++-----
 hw/pc.h    |    7 +++----
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/hw/i8259.c b/hw/i8259.c
index 7331e0e..8464d07 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -40,6 +40,8 @@
 //#define DEBUG_IRQ_LATENCY
 //#define DEBUG_IRQ_COUNT
 
+typedef struct PicState PicState;
+
 struct PicState {
     ISADevice dev;
     uint8_t last_irr; /* edge detection */
@@ -76,7 +78,7 @@ static uint64_t irq_count[16];
 #ifdef DEBUG_IRQ_LATENCY
 static int64_t irq_time[16];
 #endif
-PicState *isa_pic;
+DeviceState *isa_pic;
 static PicState *slave_pic;
 
 /* return the highest priority found in mask (highest = smallest
@@ -206,8 +208,9 @@ static void pic_intack(PicState *s, int irq)
     pic_update_irq(s);
 }
 
-int pic_read_irq(PicState *s)
+int pic_read_irq(DeviceState *d)
 {
+    PicState *s = DO_UPCAST(PicState, dev.qdev, d);
     int irq, irq2, intno;
 
     irq = pic_get_irq(s);
@@ -399,8 +402,10 @@ static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr,
     return ret;
 }
 
-int pic_get_output(PicState *s)
+int pic_get_output(DeviceState *d)
 {
+    PicState *s = DO_UPCAST(PicState, dev.qdev, d);
+
     return (pic_get_irq(s) >= 0);
 }
 
@@ -491,7 +496,7 @@ void pic_info(Monitor *mon)
         return;
     }
     for (i = 0; i < 2; i++) {
-        s = i == 0 ? isa_pic : slave_pic;
+        s = i == 0 ? DO_UPCAST(PicState, dev.qdev, isa_pic) : slave_pic;
         monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
                        "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
                        i, s->irr, s->imr, s->isr, s->priority_add,
@@ -538,7 +543,7 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
         irq_set[i] = qdev_get_gpio_in(&dev->qdev, i);
     }
 
-    isa_pic = DO_UPCAST(PicState, dev, dev);
+    isa_pic = &dev->qdev;
 
     dev = isa_create(bus, "isa-i8259");
     qdev_prop_set_uint32(&dev->qdev, "iobase", 0xa0);
diff --git a/hw/pc.h b/hw/pc.h
index 13e41f1..ece069a 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -62,11 +62,10 @@ bool parallel_mm_init(MemoryRegion *address_space,
 
 /* i8259.c */
 
-typedef struct PicState PicState;
-extern PicState *isa_pic;
+extern DeviceState *isa_pic;
 qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq);
-int pic_read_irq(PicState *s);
-int pic_get_output(PicState *s);
+int pic_read_irq(DeviceState *d);
+int pic_get_output(DeviceState *d);
 void pic_info(Monitor *mon);
 void irq_info(Monitor *mon);
 
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 08/18] i8259: Completely privatize PicState
@ 2012-01-13 17:35   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

Use DeviceState instead of PicState in the public i8259 API. This is
cleaner and allows to reorganize the PIC data structures for KVM reuse.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/i8259.c |   15 ++++++++++-----
 hw/pc.h    |    7 +++----
 2 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/hw/i8259.c b/hw/i8259.c
index 7331e0e..8464d07 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -40,6 +40,8 @@
 //#define DEBUG_IRQ_LATENCY
 //#define DEBUG_IRQ_COUNT
 
+typedef struct PicState PicState;
+
 struct PicState {
     ISADevice dev;
     uint8_t last_irr; /* edge detection */
@@ -76,7 +78,7 @@ static uint64_t irq_count[16];
 #ifdef DEBUG_IRQ_LATENCY
 static int64_t irq_time[16];
 #endif
-PicState *isa_pic;
+DeviceState *isa_pic;
 static PicState *slave_pic;
 
 /* return the highest priority found in mask (highest = smallest
@@ -206,8 +208,9 @@ static void pic_intack(PicState *s, int irq)
     pic_update_irq(s);
 }
 
-int pic_read_irq(PicState *s)
+int pic_read_irq(DeviceState *d)
 {
+    PicState *s = DO_UPCAST(PicState, dev.qdev, d);
     int irq, irq2, intno;
 
     irq = pic_get_irq(s);
@@ -399,8 +402,10 @@ static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr,
     return ret;
 }
 
-int pic_get_output(PicState *s)
+int pic_get_output(DeviceState *d)
 {
+    PicState *s = DO_UPCAST(PicState, dev.qdev, d);
+
     return (pic_get_irq(s) >= 0);
 }
 
@@ -491,7 +496,7 @@ void pic_info(Monitor *mon)
         return;
     }
     for (i = 0; i < 2; i++) {
-        s = i == 0 ? isa_pic : slave_pic;
+        s = i == 0 ? DO_UPCAST(PicState, dev.qdev, isa_pic) : slave_pic;
         monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
                        "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
                        i, s->irr, s->imr, s->isr, s->priority_add,
@@ -538,7 +543,7 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
         irq_set[i] = qdev_get_gpio_in(&dev->qdev, i);
     }
 
-    isa_pic = DO_UPCAST(PicState, dev, dev);
+    isa_pic = &dev->qdev;
 
     dev = isa_create(bus, "isa-i8259");
     qdev_prop_set_uint32(&dev->qdev, "iobase", 0xa0);
diff --git a/hw/pc.h b/hw/pc.h
index 13e41f1..ece069a 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -62,11 +62,10 @@ bool parallel_mm_init(MemoryRegion *address_space,
 
 /* i8259.c */
 
-typedef struct PicState PicState;
-extern PicState *isa_pic;
+extern DeviceState *isa_pic;
 qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq);
-int pic_read_irq(PicState *s);
-int pic_get_output(PicState *s);
+int pic_read_irq(DeviceState *d);
+int pic_get_output(DeviceState *d);
 void pic_info(Monitor *mon);
 void irq_info(Monitor *mon);
 
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 09/18] i8259: Factor out base class for KVM reuse
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:35   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

Analogously to the APIC, we will reuse some parts of the user space
i8259 model for KVM. In this case it is a common device state, a common
vmstate, the property list, a reset core and some init bits.

This also introduces a common helper to instantiate a single i8259 chip
from the cascade-creating i8259_init function.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.objs       |    2 +-
 hw/i8259.c          |  160 +++++++++++++++------------------------------------
 hw/i8259_common.c   |   96 ++++++++++++++++++++++++++++++
 hw/i8259_internal.h |   76 ++++++++++++++++++++++++
 4 files changed, 220 insertions(+), 114 deletions(-)
 create mode 100644 hw/i8259_common.c
 create mode 100644 hw/i8259_internal.h

diff --git a/Makefile.objs b/Makefile.objs
index f753d83..39c994b 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -220,7 +220,7 @@ hw-obj-$(CONFIG_APPLESMC) += applesmc.o
 hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o ccid-card-passthru.o
 hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
 hw-obj-$(CONFIG_USB_REDIR) += usb-redir.o
-hw-obj-$(CONFIG_I8259) += i8259.o
+hw-obj-$(CONFIG_I8259) += i8259_common.o i8259.o
 
 # PPC devices
 hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o
diff --git a/hw/i8259.c b/hw/i8259.c
index 8464d07..97582f3 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -26,6 +26,7 @@
 #include "isa.h"
 #include "monitor.h"
 #include "qemu-timer.h"
+#include "i8259_internal.h"
 
 /* debug PIC */
 //#define DEBUG_PIC
@@ -40,33 +41,10 @@
 //#define DEBUG_IRQ_LATENCY
 //#define DEBUG_IRQ_COUNT
 
-typedef struct PicState PicState;
-
-struct PicState {
-    ISADevice dev;
-    uint8_t last_irr; /* edge detection */
-    uint8_t irr; /* interrupt request register */
-    uint8_t imr; /* interrupt mask register */
-    uint8_t isr; /* interrupt service register */
-    uint8_t priority_add; /* highest irq priority */
-    uint8_t irq_base;
-    uint8_t read_reg_select;
-    uint8_t poll;
-    uint8_t special_mask;
-    uint8_t init_state;
-    uint8_t auto_eoi;
-    uint8_t rotate_on_auto_eoi;
-    uint8_t special_fully_nested_mode;
-    uint8_t init4; /* true if 4 byte init */
-    uint8_t single_mode; /* true if slave pic is not initialized */
-    uint8_t elcr; /* PIIX edge/trigger selection*/
-    uint8_t elcr_mask;
-    qemu_irq int_out[1];
-    uint32_t master; /* reflects /SP input pin */
-    uint32_t iobase;
-    uint32_t elcr_addr;
-    MemoryRegion base_io;
-    MemoryRegion elcr_io;
+typedef struct PICState PICState;
+
+struct PICState {
+    PICCommonState pic;
 };
 
 #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
@@ -79,11 +57,11 @@ static uint64_t irq_count[16];
 static int64_t irq_time[16];
 #endif
 DeviceState *isa_pic;
-static PicState *slave_pic;
+static PICCommonState *slave_pic;
 
 /* return the highest priority found in mask (highest = smallest
    number). Return 8 if no irq */
-static int get_priority(PicState *s, int mask)
+static int get_priority(PICCommonState *s, int mask)
 {
     int priority;
 
@@ -98,7 +76,7 @@ static int get_priority(PicState *s, int mask)
 }
 
 /* return the pic wanted interrupt. return -1 if none */
-static int pic_get_irq(PicState *s)
+static int pic_get_irq(PICCommonState *s)
 {
     int mask, cur_priority, priority;
 
@@ -127,7 +105,7 @@ static int pic_get_irq(PicState *s)
 }
 
 /* Update INT output. Must be called every time the output may have changed. */
-static void pic_update_irq(PicState *s)
+static void pic_update_irq(PICCommonState *s)
 {
     int irq;
 
@@ -144,7 +122,7 @@ static void pic_update_irq(PicState *s)
 /* set irq level. If an edge is detected, then the IRR is set to 1 */
 static void pic_set_irq(void *opaque, int irq, int level)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     int mask = 1 << irq;
 
 #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
@@ -192,7 +170,7 @@ static void pic_set_irq(void *opaque, int irq, int level)
 }
 
 /* acknowledge interrupt 'irq' */
-static void pic_intack(PicState *s, int irq)
+static void pic_intack(PICCommonState *s, int irq)
 {
     if (s->auto_eoi) {
         if (s->rotate_on_auto_eoi) {
@@ -210,7 +188,7 @@ static void pic_intack(PicState *s, int irq)
 
 int pic_read_irq(DeviceState *d)
 {
-    PicState *s = DO_UPCAST(PicState, dev.qdev, d);
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
     int irq, irq2, intno;
 
     irq = pic_get_irq(s);
@@ -249,30 +227,15 @@ int pic_read_irq(DeviceState *d)
     return intno;
 }
 
-static void pic_init_reset(PicState *s)
+static void pic_init_reset(PICCommonState *s)
 {
-    s->last_irr = 0;
-    s->irr = 0;
-    s->imr = 0;
-    s->isr = 0;
-    s->priority_add = 0;
-    s->irq_base = 0;
-    s->read_reg_select = 0;
-    s->poll = 0;
-    s->special_mask = 0;
-    s->init_state = 0;
-    s->auto_eoi = 0;
-    s->rotate_on_auto_eoi = 0;
-    s->special_fully_nested_mode = 0;
-    s->init4 = 0;
-    s->single_mode = 0;
-    /* Note: ELCR is not reset */
+    pic_reset_common(s);
     pic_update_irq(s);
 }
 
 static void pic_reset(DeviceState *dev)
 {
-    PicState *s = container_of(dev, PicState, dev.qdev);
+    PICCommonState *s = container_of(dev, PICCommonState, dev.qdev);
 
     pic_init_reset(s);
     s->elcr = 0;
@@ -281,7 +244,7 @@ static void pic_reset(DeviceState *dev)
 static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
                              uint64_t val64, unsigned size)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     uint32_t addr = addr64;
     uint32_t val = val64;
     int priority, cmd, irq;
@@ -375,7 +338,7 @@ static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
 static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr,
                                 unsigned size)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     int ret;
 
     if (s->poll) {
@@ -404,7 +367,7 @@ static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr,
 
 int pic_get_output(DeviceState *d)
 {
-    PicState *s = DO_UPCAST(PicState, dev.qdev, d);
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
 
     return (pic_get_irq(s) >= 0);
 }
@@ -412,43 +375,17 @@ int pic_get_output(DeviceState *d)
 static void elcr_ioport_write(void *opaque, target_phys_addr_t addr,
                               uint64_t val, unsigned size)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     s->elcr = val & s->elcr_mask;
 }
 
 static uint64_t elcr_ioport_read(void *opaque, target_phys_addr_t addr,
                                  unsigned size)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     return s->elcr;
 }
 
-static const VMStateDescription vmstate_pic = {
-    .name = "i8259",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(last_irr, PicState),
-        VMSTATE_UINT8(irr, PicState),
-        VMSTATE_UINT8(imr, PicState),
-        VMSTATE_UINT8(isr, PicState),
-        VMSTATE_UINT8(priority_add, PicState),
-        VMSTATE_UINT8(irq_base, PicState),
-        VMSTATE_UINT8(read_reg_select, PicState),
-        VMSTATE_UINT8(poll, PicState),
-        VMSTATE_UINT8(special_mask, PicState),
-        VMSTATE_UINT8(init_state, PicState),
-        VMSTATE_UINT8(auto_eoi, PicState),
-        VMSTATE_UINT8(rotate_on_auto_eoi, PicState),
-        VMSTATE_UINT8(special_fully_nested_mode, PicState),
-        VMSTATE_UINT8(init4, PicState),
-        VMSTATE_UINT8(single_mode, PicState),
-        VMSTATE_UINT8(elcr, PicState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
 static const MemoryRegionOps pic_base_ioport_ops = {
     .read = pic_ioport_read,
     .write = pic_ioport_write,
@@ -469,20 +406,17 @@ static const MemoryRegionOps pic_elcr_ioport_ops = {
 
 static int pic_initfn(ISADevice *dev)
 {
-    PicState *s = DO_UPCAST(PicState, dev, dev);
-
-    memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
-    memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
+    PICState *s = DO_UPCAST(PICState, pic.dev, dev);
 
-    isa_register_ioport(dev, &s->base_io, s->iobase);
-    if (s->elcr_addr != -1) {
-        isa_register_ioport(dev, &s->elcr_io, s->elcr_addr);
-    }
+    memory_region_init_io(&s->pic.base_io, &pic_base_ioport_ops, &s->pic,
+                          "pic", 2);
+    memory_region_init_io(&s->pic.elcr_io, &pic_elcr_ioport_ops, &s->pic,
+                          "elcr", 1);
 
-    qdev_init_gpio_out(&dev->qdev, s->int_out, ARRAY_SIZE(s->int_out));
+    qdev_init_gpio_out(&dev->qdev, s->pic.int_out, ARRAY_SIZE(s->pic.int_out));
     qdev_init_gpio_in(&dev->qdev, pic_set_irq, 8);
 
-    qdev_set_legacy_instance_id(&dev->qdev, s->iobase, 1);
+    pic_init_common(&s->pic);
 
     return 0;
 }
@@ -490,13 +424,13 @@ static int pic_initfn(ISADevice *dev)
 void pic_info(Monitor *mon)
 {
     int i;
-    PicState *s;
+    PICCommonState *s;
 
     if (!isa_pic) {
         return;
     }
     for (i = 0; i < 2; i++) {
-        s = i == 0 ? DO_UPCAST(PicState, dev.qdev, isa_pic) : slave_pic;
+        s = i == 0 ? DO_UPCAST(PICCommonState, dev.qdev, isa_pic) : slave_pic;
         monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
                        "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
                        i, s->irr, s->imr, s->isr, s->priority_add,
@@ -531,12 +465,7 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
 
     irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
 
-    dev = isa_create(bus, "isa-i8259");
-    qdev_prop_set_uint32(&dev->qdev, "iobase", 0x20);
-    qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d0);
-    qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xf8);
-    qdev_prop_set_bit(&dev->qdev, "master", true);
-    qdev_init_nofail(&dev->qdev);
+    dev = i8259_init_chip("isa-i8259", bus, true);
 
     qdev_connect_gpio_out(&dev->qdev, 0, parent_irq);
     for (i = 0 ; i < 8; i++) {
@@ -545,35 +474,39 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
 
     isa_pic = &dev->qdev;
 
-    dev = isa_create(bus, "isa-i8259");
-    qdev_prop_set_uint32(&dev->qdev, "iobase", 0xa0);
-    qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d1);
-    qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xde);
-    qdev_init_nofail(&dev->qdev);
+    dev = i8259_init_chip("isa-i8259", bus, false);
 
     qdev_connect_gpio_out(&dev->qdev, 0, irq_set[2]);
     for (i = 0 ; i < 8; i++) {
         irq_set[i + 8] = qdev_get_gpio_in(&dev->qdev, i);
     }
 
-    slave_pic = DO_UPCAST(PicState, dev, dev);
+    slave_pic = DO_UPCAST(PICCommonState, dev, dev);
 
     return irq_set;
 }
 
+static const VMStateDescription vmstate_pic = {
+    .name = "i8259",
+    .version_id = PIC_VMSTATE_VERSION,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(pic, PICState, 0, vmstate_pic_common, PICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static ISADeviceInfo i8259_info = {
     .qdev.name     = "isa-i8259",
-    .qdev.size     = sizeof(PicState),
+    .qdev.size     = sizeof(PICState),
     .qdev.vmsd     = &vmstate_pic,
     .qdev.reset    = pic_reset,
     .qdev.no_user  = 1,
     .init          = pic_initfn,
     .qdev.props = (Property[]) {
-        DEFINE_PROP_HEX32("iobase", PicState, iobase,  -1),
-        DEFINE_PROP_HEX32("elcr_addr", PicState, elcr_addr,  -1),
-        DEFINE_PROP_HEX8("elcr_mask", PicState, elcr_mask,  -1),
-        DEFINE_PROP_BIT("master", PicState, master,  0, false),
-        DEFINE_PROP_END_OF_LIST(),
+        PIC_PROPERTIES_COMMON(PICState, pic),
+        DEFINE_PROP_END_OF_LIST()
     },
 };
 
@@ -581,4 +514,5 @@ static void pic_register(void)
 {
     isa_qdev_register(&i8259_info);
 }
+
 device_init(pic_register)
diff --git a/hw/i8259_common.c b/hw/i8259_common.c
new file mode 100644
index 0000000..9e34922
--- /dev/null
+++ b/hw/i8259_common.c
@@ -0,0 +1,96 @@
+/*
+ * QEMU 8259 - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "pc.h"
+#include "i8259_internal.h"
+
+void pic_reset_common(PICCommonState *s)
+{
+    s->last_irr = 0;
+    s->irr = 0;
+    s->imr = 0;
+    s->isr = 0;
+    s->priority_add = 0;
+    s->irq_base = 0;
+    s->read_reg_select = 0;
+    s->poll = 0;
+    s->special_mask = 0;
+    s->init_state = 0;
+    s->auto_eoi = 0;
+    s->rotate_on_auto_eoi = 0;
+    s->special_fully_nested_mode = 0;
+    s->init4 = 0;
+    s->single_mode = 0;
+    /* Note: ELCR is not reset */
+}
+
+const VMStateDescription vmstate_pic_common = {
+    .name = "i8259",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(last_irr, PICCommonState),
+        VMSTATE_UINT8(irr, PICCommonState),
+        VMSTATE_UINT8(imr, PICCommonState),
+        VMSTATE_UINT8(isr, PICCommonState),
+        VMSTATE_UINT8(priority_add, PICCommonState),
+        VMSTATE_UINT8(irq_base, PICCommonState),
+        VMSTATE_UINT8(read_reg_select, PICCommonState),
+        VMSTATE_UINT8(poll, PICCommonState),
+        VMSTATE_UINT8(special_mask, PICCommonState),
+        VMSTATE_UINT8(init_state, PICCommonState),
+        VMSTATE_UINT8(auto_eoi, PICCommonState),
+        VMSTATE_UINT8(rotate_on_auto_eoi, PICCommonState),
+        VMSTATE_UINT8(special_fully_nested_mode, PICCommonState),
+        VMSTATE_UINT8(init4, PICCommonState),
+        VMSTATE_UINT8(single_mode, PICCommonState),
+        VMSTATE_UINT8(elcr, PICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void pic_init_common(PICCommonState *s)
+{
+    isa_register_ioport(NULL, &s->base_io, s->iobase);
+    if (s->elcr_addr != -1) {
+        isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr);
+    }
+
+    qdev_set_legacy_instance_id(&s->dev.qdev, s->iobase, 1);
+}
+
+ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master)
+{
+    ISADevice *dev;
+
+    dev = isa_create(bus, name);
+    qdev_prop_set_uint32(&dev->qdev, "iobase", master ? 0x20 : 0xa0);
+    qdev_prop_set_uint32(&dev->qdev, "elcr_addr", master ? 0x4d0 : 0x4d1);
+    qdev_prop_set_uint8(&dev->qdev, "elcr_mask", master ? 0xf8 : 0xde);
+    qdev_prop_set_bit(&dev->qdev, "master", master);
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
diff --git a/hw/i8259_internal.h b/hw/i8259_internal.h
new file mode 100644
index 0000000..aedd55f
--- /dev/null
+++ b/hw/i8259_internal.h
@@ -0,0 +1,76 @@
+/*
+ * QEMU 8259 - internal interfaces
+ *
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_I8259_INTERNAL_H
+#define QEMU_I8259_INTERNAL_H
+
+#include "hw.h"
+#include "pc.h"
+#include "isa.h"
+
+typedef struct PICCommonState PICCommonState;
+
+struct PICCommonState {
+    ISADevice dev;
+    uint8_t last_irr; /* edge detection */
+    uint8_t irr; /* interrupt request register */
+    uint8_t imr; /* interrupt mask register */
+    uint8_t isr; /* interrupt service register */
+    uint8_t priority_add; /* highest irq priority */
+    uint8_t irq_base;
+    uint8_t read_reg_select;
+    uint8_t poll;
+    uint8_t special_mask;
+    uint8_t init_state;
+    uint8_t auto_eoi;
+    uint8_t rotate_on_auto_eoi;
+    uint8_t special_fully_nested_mode;
+    uint8_t init4; /* true if 4 byte init */
+    uint8_t single_mode; /* true if slave pic is not initialized */
+    uint8_t elcr; /* PIIX edge/trigger selection*/
+    uint8_t elcr_mask;
+    qemu_irq int_out[1];
+    uint32_t master; /* reflects /SP input pin */
+    uint32_t iobase;
+    uint32_t elcr_addr;
+    MemoryRegion base_io;
+    MemoryRegion elcr_io;
+};
+
+#define PIC_VMSTATE_VERSION 1
+
+extern const VMStateDescription vmstate_pic_common;
+
+#define PIC_PROPERTIES_COMMON(cont_type, cont_var)                      \
+    DEFINE_PROP_HEX32("iobase", cont_type, cont_var.iobase,  -1),       \
+    DEFINE_PROP_HEX32("elcr_addr", cont_type, cont_var.elcr_addr,  -1), \
+    DEFINE_PROP_HEX8("elcr_mask", cont_type, cont_var.elcr_mask,  -1),  \
+    DEFINE_PROP_BIT("master", cont_type, cont_var.master,  0, false)
+
+void pic_init_common(PICCommonState *s);
+void pic_reset_common(PICCommonState *s);
+
+ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master);
+
+#endif /* !QEMU_I8259_INTERNAL_H */
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 09/18] i8259: Factor out base class for KVM reuse
@ 2012-01-13 17:35   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

Analogously to the APIC, we will reuse some parts of the user space
i8259 model for KVM. In this case it is a common device state, a common
vmstate, the property list, a reset core and some init bits.

This also introduces a common helper to instantiate a single i8259 chip
from the cascade-creating i8259_init function.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.objs       |    2 +-
 hw/i8259.c          |  160 +++++++++++++++------------------------------------
 hw/i8259_common.c   |   96 ++++++++++++++++++++++++++++++
 hw/i8259_internal.h |   76 ++++++++++++++++++++++++
 4 files changed, 220 insertions(+), 114 deletions(-)
 create mode 100644 hw/i8259_common.c
 create mode 100644 hw/i8259_internal.h

diff --git a/Makefile.objs b/Makefile.objs
index f753d83..39c994b 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -220,7 +220,7 @@ hw-obj-$(CONFIG_APPLESMC) += applesmc.o
 hw-obj-$(CONFIG_SMARTCARD) += usb-ccid.o ccid-card-passthru.o
 hw-obj-$(CONFIG_SMARTCARD_NSS) += ccid-card-emulated.o
 hw-obj-$(CONFIG_USB_REDIR) += usb-redir.o
-hw-obj-$(CONFIG_I8259) += i8259.o
+hw-obj-$(CONFIG_I8259) += i8259_common.o i8259.o
 
 # PPC devices
 hw-obj-$(CONFIG_PREP_PCI) += prep_pci.o
diff --git a/hw/i8259.c b/hw/i8259.c
index 8464d07..97582f3 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -26,6 +26,7 @@
 #include "isa.h"
 #include "monitor.h"
 #include "qemu-timer.h"
+#include "i8259_internal.h"
 
 /* debug PIC */
 //#define DEBUG_PIC
@@ -40,33 +41,10 @@
 //#define DEBUG_IRQ_LATENCY
 //#define DEBUG_IRQ_COUNT
 
-typedef struct PicState PicState;
-
-struct PicState {
-    ISADevice dev;
-    uint8_t last_irr; /* edge detection */
-    uint8_t irr; /* interrupt request register */
-    uint8_t imr; /* interrupt mask register */
-    uint8_t isr; /* interrupt service register */
-    uint8_t priority_add; /* highest irq priority */
-    uint8_t irq_base;
-    uint8_t read_reg_select;
-    uint8_t poll;
-    uint8_t special_mask;
-    uint8_t init_state;
-    uint8_t auto_eoi;
-    uint8_t rotate_on_auto_eoi;
-    uint8_t special_fully_nested_mode;
-    uint8_t init4; /* true if 4 byte init */
-    uint8_t single_mode; /* true if slave pic is not initialized */
-    uint8_t elcr; /* PIIX edge/trigger selection*/
-    uint8_t elcr_mask;
-    qemu_irq int_out[1];
-    uint32_t master; /* reflects /SP input pin */
-    uint32_t iobase;
-    uint32_t elcr_addr;
-    MemoryRegion base_io;
-    MemoryRegion elcr_io;
+typedef struct PICState PICState;
+
+struct PICState {
+    PICCommonState pic;
 };
 
 #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
@@ -79,11 +57,11 @@ static uint64_t irq_count[16];
 static int64_t irq_time[16];
 #endif
 DeviceState *isa_pic;
-static PicState *slave_pic;
+static PICCommonState *slave_pic;
 
 /* return the highest priority found in mask (highest = smallest
    number). Return 8 if no irq */
-static int get_priority(PicState *s, int mask)
+static int get_priority(PICCommonState *s, int mask)
 {
     int priority;
 
@@ -98,7 +76,7 @@ static int get_priority(PicState *s, int mask)
 }
 
 /* return the pic wanted interrupt. return -1 if none */
-static int pic_get_irq(PicState *s)
+static int pic_get_irq(PICCommonState *s)
 {
     int mask, cur_priority, priority;
 
@@ -127,7 +105,7 @@ static int pic_get_irq(PicState *s)
 }
 
 /* Update INT output. Must be called every time the output may have changed. */
-static void pic_update_irq(PicState *s)
+static void pic_update_irq(PICCommonState *s)
 {
     int irq;
 
@@ -144,7 +122,7 @@ static void pic_update_irq(PicState *s)
 /* set irq level. If an edge is detected, then the IRR is set to 1 */
 static void pic_set_irq(void *opaque, int irq, int level)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     int mask = 1 << irq;
 
 #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT) || \
@@ -192,7 +170,7 @@ static void pic_set_irq(void *opaque, int irq, int level)
 }
 
 /* acknowledge interrupt 'irq' */
-static void pic_intack(PicState *s, int irq)
+static void pic_intack(PICCommonState *s, int irq)
 {
     if (s->auto_eoi) {
         if (s->rotate_on_auto_eoi) {
@@ -210,7 +188,7 @@ static void pic_intack(PicState *s, int irq)
 
 int pic_read_irq(DeviceState *d)
 {
-    PicState *s = DO_UPCAST(PicState, dev.qdev, d);
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
     int irq, irq2, intno;
 
     irq = pic_get_irq(s);
@@ -249,30 +227,15 @@ int pic_read_irq(DeviceState *d)
     return intno;
 }
 
-static void pic_init_reset(PicState *s)
+static void pic_init_reset(PICCommonState *s)
 {
-    s->last_irr = 0;
-    s->irr = 0;
-    s->imr = 0;
-    s->isr = 0;
-    s->priority_add = 0;
-    s->irq_base = 0;
-    s->read_reg_select = 0;
-    s->poll = 0;
-    s->special_mask = 0;
-    s->init_state = 0;
-    s->auto_eoi = 0;
-    s->rotate_on_auto_eoi = 0;
-    s->special_fully_nested_mode = 0;
-    s->init4 = 0;
-    s->single_mode = 0;
-    /* Note: ELCR is not reset */
+    pic_reset_common(s);
     pic_update_irq(s);
 }
 
 static void pic_reset(DeviceState *dev)
 {
-    PicState *s = container_of(dev, PicState, dev.qdev);
+    PICCommonState *s = container_of(dev, PICCommonState, dev.qdev);
 
     pic_init_reset(s);
     s->elcr = 0;
@@ -281,7 +244,7 @@ static void pic_reset(DeviceState *dev)
 static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
                              uint64_t val64, unsigned size)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     uint32_t addr = addr64;
     uint32_t val = val64;
     int priority, cmd, irq;
@@ -375,7 +338,7 @@ static void pic_ioport_write(void *opaque, target_phys_addr_t addr64,
 static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr,
                                 unsigned size)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     int ret;
 
     if (s->poll) {
@@ -404,7 +367,7 @@ static uint64_t pic_ioport_read(void *opaque, target_phys_addr_t addr,
 
 int pic_get_output(DeviceState *d)
 {
-    PicState *s = DO_UPCAST(PicState, dev.qdev, d);
+    PICCommonState *s = DO_UPCAST(PICCommonState, dev.qdev, d);
 
     return (pic_get_irq(s) >= 0);
 }
@@ -412,43 +375,17 @@ int pic_get_output(DeviceState *d)
 static void elcr_ioport_write(void *opaque, target_phys_addr_t addr,
                               uint64_t val, unsigned size)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     s->elcr = val & s->elcr_mask;
 }
 
 static uint64_t elcr_ioport_read(void *opaque, target_phys_addr_t addr,
                                  unsigned size)
 {
-    PicState *s = opaque;
+    PICCommonState *s = opaque;
     return s->elcr;
 }
 
-static const VMStateDescription vmstate_pic = {
-    .name = "i8259",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(last_irr, PicState),
-        VMSTATE_UINT8(irr, PicState),
-        VMSTATE_UINT8(imr, PicState),
-        VMSTATE_UINT8(isr, PicState),
-        VMSTATE_UINT8(priority_add, PicState),
-        VMSTATE_UINT8(irq_base, PicState),
-        VMSTATE_UINT8(read_reg_select, PicState),
-        VMSTATE_UINT8(poll, PicState),
-        VMSTATE_UINT8(special_mask, PicState),
-        VMSTATE_UINT8(init_state, PicState),
-        VMSTATE_UINT8(auto_eoi, PicState),
-        VMSTATE_UINT8(rotate_on_auto_eoi, PicState),
-        VMSTATE_UINT8(special_fully_nested_mode, PicState),
-        VMSTATE_UINT8(init4, PicState),
-        VMSTATE_UINT8(single_mode, PicState),
-        VMSTATE_UINT8(elcr, PicState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
 static const MemoryRegionOps pic_base_ioport_ops = {
     .read = pic_ioport_read,
     .write = pic_ioport_write,
@@ -469,20 +406,17 @@ static const MemoryRegionOps pic_elcr_ioport_ops = {
 
 static int pic_initfn(ISADevice *dev)
 {
-    PicState *s = DO_UPCAST(PicState, dev, dev);
-
-    memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2);
-    memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1);
+    PICState *s = DO_UPCAST(PICState, pic.dev, dev);
 
-    isa_register_ioport(dev, &s->base_io, s->iobase);
-    if (s->elcr_addr != -1) {
-        isa_register_ioport(dev, &s->elcr_io, s->elcr_addr);
-    }
+    memory_region_init_io(&s->pic.base_io, &pic_base_ioport_ops, &s->pic,
+                          "pic", 2);
+    memory_region_init_io(&s->pic.elcr_io, &pic_elcr_ioport_ops, &s->pic,
+                          "elcr", 1);
 
-    qdev_init_gpio_out(&dev->qdev, s->int_out, ARRAY_SIZE(s->int_out));
+    qdev_init_gpio_out(&dev->qdev, s->pic.int_out, ARRAY_SIZE(s->pic.int_out));
     qdev_init_gpio_in(&dev->qdev, pic_set_irq, 8);
 
-    qdev_set_legacy_instance_id(&dev->qdev, s->iobase, 1);
+    pic_init_common(&s->pic);
 
     return 0;
 }
@@ -490,13 +424,13 @@ static int pic_initfn(ISADevice *dev)
 void pic_info(Monitor *mon)
 {
     int i;
-    PicState *s;
+    PICCommonState *s;
 
     if (!isa_pic) {
         return;
     }
     for (i = 0; i < 2; i++) {
-        s = i == 0 ? DO_UPCAST(PicState, dev.qdev, isa_pic) : slave_pic;
+        s = i == 0 ? DO_UPCAST(PICCommonState, dev.qdev, isa_pic) : slave_pic;
         monitor_printf(mon, "pic%d: irr=%02x imr=%02x isr=%02x hprio=%d "
                        "irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
                        i, s->irr, s->imr, s->isr, s->priority_add,
@@ -531,12 +465,7 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
 
     irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
 
-    dev = isa_create(bus, "isa-i8259");
-    qdev_prop_set_uint32(&dev->qdev, "iobase", 0x20);
-    qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d0);
-    qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xf8);
-    qdev_prop_set_bit(&dev->qdev, "master", true);
-    qdev_init_nofail(&dev->qdev);
+    dev = i8259_init_chip("isa-i8259", bus, true);
 
     qdev_connect_gpio_out(&dev->qdev, 0, parent_irq);
     for (i = 0 ; i < 8; i++) {
@@ -545,35 +474,39 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
 
     isa_pic = &dev->qdev;
 
-    dev = isa_create(bus, "isa-i8259");
-    qdev_prop_set_uint32(&dev->qdev, "iobase", 0xa0);
-    qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d1);
-    qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xde);
-    qdev_init_nofail(&dev->qdev);
+    dev = i8259_init_chip("isa-i8259", bus, false);
 
     qdev_connect_gpio_out(&dev->qdev, 0, irq_set[2]);
     for (i = 0 ; i < 8; i++) {
         irq_set[i + 8] = qdev_get_gpio_in(&dev->qdev, i);
     }
 
-    slave_pic = DO_UPCAST(PicState, dev, dev);
+    slave_pic = DO_UPCAST(PICCommonState, dev, dev);
 
     return irq_set;
 }
 
+static const VMStateDescription vmstate_pic = {
+    .name = "i8259",
+    .version_id = PIC_VMSTATE_VERSION,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(pic, PICState, 0, vmstate_pic_common, PICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
 static ISADeviceInfo i8259_info = {
     .qdev.name     = "isa-i8259",
-    .qdev.size     = sizeof(PicState),
+    .qdev.size     = sizeof(PICState),
     .qdev.vmsd     = &vmstate_pic,
     .qdev.reset    = pic_reset,
     .qdev.no_user  = 1,
     .init          = pic_initfn,
     .qdev.props = (Property[]) {
-        DEFINE_PROP_HEX32("iobase", PicState, iobase,  -1),
-        DEFINE_PROP_HEX32("elcr_addr", PicState, elcr_addr,  -1),
-        DEFINE_PROP_HEX8("elcr_mask", PicState, elcr_mask,  -1),
-        DEFINE_PROP_BIT("master", PicState, master,  0, false),
-        DEFINE_PROP_END_OF_LIST(),
+        PIC_PROPERTIES_COMMON(PICState, pic),
+        DEFINE_PROP_END_OF_LIST()
     },
 };
 
@@ -581,4 +514,5 @@ static void pic_register(void)
 {
     isa_qdev_register(&i8259_info);
 }
+
 device_init(pic_register)
diff --git a/hw/i8259_common.c b/hw/i8259_common.c
new file mode 100644
index 0000000..9e34922
--- /dev/null
+++ b/hw/i8259_common.c
@@ -0,0 +1,96 @@
+/*
+ * QEMU 8259 - common bits of emulated and KVM kernel model
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "pc.h"
+#include "i8259_internal.h"
+
+void pic_reset_common(PICCommonState *s)
+{
+    s->last_irr = 0;
+    s->irr = 0;
+    s->imr = 0;
+    s->isr = 0;
+    s->priority_add = 0;
+    s->irq_base = 0;
+    s->read_reg_select = 0;
+    s->poll = 0;
+    s->special_mask = 0;
+    s->init_state = 0;
+    s->auto_eoi = 0;
+    s->rotate_on_auto_eoi = 0;
+    s->special_fully_nested_mode = 0;
+    s->init4 = 0;
+    s->single_mode = 0;
+    /* Note: ELCR is not reset */
+}
+
+const VMStateDescription vmstate_pic_common = {
+    .name = "i8259",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(last_irr, PICCommonState),
+        VMSTATE_UINT8(irr, PICCommonState),
+        VMSTATE_UINT8(imr, PICCommonState),
+        VMSTATE_UINT8(isr, PICCommonState),
+        VMSTATE_UINT8(priority_add, PICCommonState),
+        VMSTATE_UINT8(irq_base, PICCommonState),
+        VMSTATE_UINT8(read_reg_select, PICCommonState),
+        VMSTATE_UINT8(poll, PICCommonState),
+        VMSTATE_UINT8(special_mask, PICCommonState),
+        VMSTATE_UINT8(init_state, PICCommonState),
+        VMSTATE_UINT8(auto_eoi, PICCommonState),
+        VMSTATE_UINT8(rotate_on_auto_eoi, PICCommonState),
+        VMSTATE_UINT8(special_fully_nested_mode, PICCommonState),
+        VMSTATE_UINT8(init4, PICCommonState),
+        VMSTATE_UINT8(single_mode, PICCommonState),
+        VMSTATE_UINT8(elcr, PICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void pic_init_common(PICCommonState *s)
+{
+    isa_register_ioport(NULL, &s->base_io, s->iobase);
+    if (s->elcr_addr != -1) {
+        isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr);
+    }
+
+    qdev_set_legacy_instance_id(&s->dev.qdev, s->iobase, 1);
+}
+
+ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master)
+{
+    ISADevice *dev;
+
+    dev = isa_create(bus, name);
+    qdev_prop_set_uint32(&dev->qdev, "iobase", master ? 0x20 : 0xa0);
+    qdev_prop_set_uint32(&dev->qdev, "elcr_addr", master ? 0x4d0 : 0x4d1);
+    qdev_prop_set_uint8(&dev->qdev, "elcr_mask", master ? 0xf8 : 0xde);
+    qdev_prop_set_bit(&dev->qdev, "master", master);
+    qdev_init_nofail(&dev->qdev);
+
+    return dev;
+}
diff --git a/hw/i8259_internal.h b/hw/i8259_internal.h
new file mode 100644
index 0000000..aedd55f
--- /dev/null
+++ b/hw/i8259_internal.h
@@ -0,0 +1,76 @@
+/*
+ * QEMU 8259 - internal interfaces
+ *
+ * Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef QEMU_I8259_INTERNAL_H
+#define QEMU_I8259_INTERNAL_H
+
+#include "hw.h"
+#include "pc.h"
+#include "isa.h"
+
+typedef struct PICCommonState PICCommonState;
+
+struct PICCommonState {
+    ISADevice dev;
+    uint8_t last_irr; /* edge detection */
+    uint8_t irr; /* interrupt request register */
+    uint8_t imr; /* interrupt mask register */
+    uint8_t isr; /* interrupt service register */
+    uint8_t priority_add; /* highest irq priority */
+    uint8_t irq_base;
+    uint8_t read_reg_select;
+    uint8_t poll;
+    uint8_t special_mask;
+    uint8_t init_state;
+    uint8_t auto_eoi;
+    uint8_t rotate_on_auto_eoi;
+    uint8_t special_fully_nested_mode;
+    uint8_t init4; /* true if 4 byte init */
+    uint8_t single_mode; /* true if slave pic is not initialized */
+    uint8_t elcr; /* PIIX edge/trigger selection*/
+    uint8_t elcr_mask;
+    qemu_irq int_out[1];
+    uint32_t master; /* reflects /SP input pin */
+    uint32_t iobase;
+    uint32_t elcr_addr;
+    MemoryRegion base_io;
+    MemoryRegion elcr_io;
+};
+
+#define PIC_VMSTATE_VERSION 1
+
+extern const VMStateDescription vmstate_pic_common;
+
+#define PIC_PROPERTIES_COMMON(cont_type, cont_var)                      \
+    DEFINE_PROP_HEX32("iobase", cont_type, cont_var.iobase,  -1),       \
+    DEFINE_PROP_HEX32("elcr_addr", cont_type, cont_var.elcr_addr,  -1), \
+    DEFINE_PROP_HEX8("elcr_mask", cont_type, cont_var.elcr_mask,  -1),  \
+    DEFINE_PROP_BIT("master", cont_type, cont_var.master,  0, false)
+
+void pic_init_common(PICCommonState *s);
+void pic_reset_common(PICCommonState *s);
+
+ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master);
+
+#endif /* !QEMU_I8259_INTERNAL_H */
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 10/18] ioapic: Drop post-load irr initialization
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:35   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

As all devices undergo a reset prior to vmloa, and the reset value of
irr is 0, we do not need to do this clearing for older vmstates
explicitly. Dropping this redundant code will also make KVM integration
a bit simpler.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/ioapic.c |   12 ------------
 1 files changed, 0 insertions(+), 12 deletions(-)

diff --git a/hw/ioapic.c b/hw/ioapic.c
index 27b07c6..0743af6 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -278,21 +278,9 @@ ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val,
     }
 }
 
-static int ioapic_post_load(void *opaque, int version_id)
-{
-    IOAPICState *s = opaque;
-
-    if (version_id == 1) {
-        /* set sane value */
-        s->irr = 0;
-    }
-    return 0;
-}
-
 static const VMStateDescription vmstate_ioapic = {
     .name = "ioapic",
     .version_id = 3,
-    .post_load = ioapic_post_load,
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields = (VMStateField[]) {
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 10/18] ioapic: Drop post-load irr initialization
@ 2012-01-13 17:35   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

As all devices undergo a reset prior to vmloa, and the reset value of
irr is 0, we do not need to do this clearing for older vmstates
explicitly. Dropping this redundant code will also make KVM integration
a bit simpler.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/ioapic.c |   12 ------------
 1 files changed, 0 insertions(+), 12 deletions(-)

diff --git a/hw/ioapic.c b/hw/ioapic.c
index 27b07c6..0743af6 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -278,21 +278,9 @@ ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val,
     }
 }
 
-static int ioapic_post_load(void *opaque, int version_id)
-{
-    IOAPICState *s = opaque;
-
-    if (version_id == 1) {
-        /* set sane value */
-        s->irr = 0;
-    }
-    return 0;
-}
-
 static const VMStateDescription vmstate_ioapic = {
     .name = "ioapic",
     .version_id = 3,
-    .post_load = ioapic_post_load,
     .minimum_version_id = 1,
     .minimum_version_id_old = 1,
     .fields = (VMStateField[]) {
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 11/18] ioapic: Factor out base class for KVM reuse
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:35   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl

Split up the IOAPIC analogously to APIC and i8259. KVM will share the
IOAPICCommonState, the vmstate, reset logic and certain init parts with
the user space model.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.target      |    2 +-
 hw/ioapic.c          |  140 ++++++++++++-------------------------------------
 hw/ioapic_common.c   |   70 +++++++++++++++++++++++++
 hw/ioapic_internal.h |   99 +++++++++++++++++++++++++++++++++++
 4 files changed, 205 insertions(+), 106 deletions(-)
 create mode 100644 hw/ioapic_common.c
 create mode 100644 hw/ioapic_internal.h

diff --git a/Makefile.target b/Makefile.target
index a8acece..4fa91d3 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -223,7 +223,7 @@ obj-$(CONFIG_IVSHMEM) += ivshmem.o
 # Hardware support
 obj-i386-y += vga.o
 obj-i386-y += mc146818rtc.o pc.o
-obj-i386-y += cirrus_vga.o sga.o apic_common.o apic.o ioapic.o piix_pci.o
+obj-i386-y += cirrus_vga.o sga.o apic_common.o apic.o ioapic_common.o ioapic.o piix_pci.o
 obj-i386-y += vmport.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
diff --git a/hw/ioapic.c b/hw/ioapic.c
index 0743af6..a61aeba 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -24,9 +24,7 @@
 #include "pc.h"
 #include "apic.h"
 #include "ioapic.h"
-#include "qemu-timer.h"
-#include "host-utils.h"
-#include "sysbus.h"
+#include "ioapic_internal.h"
 
 //#define DEBUG_IOAPIC
 
@@ -37,65 +35,15 @@
 #define DPRINTF(fmt, ...)
 #endif
 
-#define MAX_IOAPICS                     1
-
-#define IOAPIC_VERSION                  0x11
-
-#define IOAPIC_LVT_DEST_SHIFT           56
-#define IOAPIC_LVT_MASKED_SHIFT         16
-#define IOAPIC_LVT_TRIGGER_MODE_SHIFT   15
-#define IOAPIC_LVT_REMOTE_IRR_SHIFT     14
-#define IOAPIC_LVT_POLARITY_SHIFT       13
-#define IOAPIC_LVT_DELIV_STATUS_SHIFT   12
-#define IOAPIC_LVT_DEST_MODE_SHIFT      11
-#define IOAPIC_LVT_DELIV_MODE_SHIFT     8
-
-#define IOAPIC_LVT_MASKED               (1 << IOAPIC_LVT_MASKED_SHIFT)
-#define IOAPIC_LVT_REMOTE_IRR           (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT)
-
-#define IOAPIC_TRIGGER_EDGE             0
-#define IOAPIC_TRIGGER_LEVEL            1
-
-/*io{apic,sapic} delivery mode*/
-#define IOAPIC_DM_FIXED                 0x0
-#define IOAPIC_DM_LOWEST_PRIORITY       0x1
-#define IOAPIC_DM_PMI                   0x2
-#define IOAPIC_DM_NMI                   0x4
-#define IOAPIC_DM_INIT                  0x5
-#define IOAPIC_DM_SIPI                  0x6
-#define IOAPIC_DM_EXTINT                0x7
-#define IOAPIC_DM_MASK                  0x7
-
-#define IOAPIC_VECTOR_MASK              0xff
-
-#define IOAPIC_IOREGSEL                 0x00
-#define IOAPIC_IOWIN                    0x10
-
-#define IOAPIC_REG_ID                   0x00
-#define IOAPIC_REG_VER                  0x01
-#define IOAPIC_REG_ARB                  0x02
-#define IOAPIC_REG_REDTBL_BASE          0x10
-#define IOAPIC_ID                       0x00
-
-#define IOAPIC_ID_SHIFT                 24
-#define IOAPIC_ID_MASK                  0xf
-
-#define IOAPIC_VER_ENTRIES_SHIFT        16
-
 typedef struct IOAPICState IOAPICState;
 
 struct IOAPICState {
-    SysBusDevice busdev;
-    MemoryRegion io_memory;
-    uint8_t id;
-    uint8_t ioregsel;
-    uint32_t irr;
-    uint64_t ioredtbl[IOAPIC_NUM_PINS];
+    IOAPICCommonState ioapic;
 };
 
-static IOAPICState *ioapics[MAX_IOAPICS];
+static IOAPICCommonState *ioapics[MAX_IOAPICS];
 
-static void ioapic_service(IOAPICState *s)
+static void ioapic_service(IOAPICCommonState *s)
 {
     uint8_t i;
     uint8_t trig_mode;
@@ -135,7 +83,7 @@ static void ioapic_service(IOAPICState *s)
 
 static void ioapic_set_irq(void *opaque, int vector, int level)
 {
-    IOAPICState *s = opaque;
+    IOAPICCommonState *s = opaque;
 
     /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
      * to GSI 2.  GSI maps to ioapic 1-1.  This is not
@@ -174,7 +122,7 @@ static void ioapic_set_irq(void *opaque, int vector, int level)
 
 void ioapic_eoi_broadcast(int vector)
 {
-    IOAPICState *s;
+    IOAPICCommonState *s;
     uint64_t entry;
     int i, n;
 
@@ -199,7 +147,7 @@ void ioapic_eoi_broadcast(int vector)
 static uint64_t
 ioapic_mem_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
-    IOAPICState *s = opaque;
+    IOAPICCommonState *s = opaque;
     int index;
     uint32_t val = 0;
 
@@ -242,7 +190,7 @@ static void
 ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val,
                  unsigned int size)
 {
-    IOAPICState *s = opaque;
+    IOAPICCommonState *s = opaque;
     int index;
 
     switch (addr & 0xff) {
@@ -278,32 +226,11 @@ ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val,
     }
 }
 
-static const VMStateDescription vmstate_ioapic = {
-    .name = "ioapic",
-    .version_id = 3,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(id, IOAPICState),
-        VMSTATE_UINT8(ioregsel, IOAPICState),
-        VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
-        VMSTATE_UINT32_V(irr, IOAPICState, 2),
-        VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void ioapic_reset(DeviceState *d)
+static void ioapic_reset(DeviceState *dev)
 {
-    IOAPICState *s = DO_UPCAST(IOAPICState, busdev.qdev, d);
-    int i;
+    IOAPICState *s = DO_UPCAST(IOAPICState, ioapic.busdev.qdev, dev);
 
-    s->id = 0;
-    s->ioregsel = 0;
-    s->irr = 0;
-    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
-        s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
-    }
+    ioapic_reset_common(&s->ioapic);
 }
 
 static const MemoryRegionOps ioapic_io_ops = {
@@ -312,37 +239,40 @@ static const MemoryRegionOps ioapic_io_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static int ioapic_init1(SysBusDevice *dev)
+static void ioapic_init(IOAPICCommonState *s, int instance_no)
 {
-    IOAPICState *s = FROM_SYSBUS(IOAPICState, dev);
-    static int ioapic_no;
-
-    if (ioapic_no >= MAX_IOAPICS) {
-        return -1;
-    }
-
     memory_region_init_io(&s->io_memory, &ioapic_io_ops, s, "ioapic", 0x1000);
-    sysbus_init_mmio(dev, &s->io_memory);
 
-    qdev_init_gpio_in(&dev->qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
+    qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
 
-    ioapics[ioapic_no++] = s;
-
-    return 0;
+    ioapics[instance_no] = s;
 }
 
-static SysBusDeviceInfo ioapic_info = {
-    .init = ioapic_init1,
-    .qdev.name = "ioapic",
-    .qdev.size = sizeof(IOAPICState),
-    .qdev.vmsd = &vmstate_ioapic,
-    .qdev.reset = ioapic_reset,
-    .qdev.no_user = 1,
+static const VMStateDescription vmstate_ioapic = {
+    .name = "ioapic",
+    .version_id = IOAPIC_VMSTATE_VERSION,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(ioapic, IOAPICState, 0, vmstate_ioapic_common,
+                       IOAPICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static IOAPICCommonInfo ioapic_info = {
+    .busdev.init = ioapic_init_common,
+    .busdev.qdev.name = "ioapic",
+    .busdev.qdev.size = sizeof(IOAPICState),
+    .busdev.qdev.vmsd = &vmstate_ioapic,
+    .busdev.qdev.reset = ioapic_reset,
+    .busdev.qdev.no_user = 1,
+    .init = ioapic_init,
 };
 
 static void ioapic_register_devices(void)
 {
-    sysbus_register_withprop(&ioapic_info);
+    sysbus_register_withprop(&ioapic_info.busdev);
 }
 
 device_init(ioapic_register_devices)
diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c
new file mode 100644
index 0000000..8535ce2
--- /dev/null
+++ b/hw/ioapic_common.c
@@ -0,0 +1,70 @@
+/*
+ *  IOAPIC emulation logic - common bits of emulated and KVM kernel model
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2009      Xiantao Zhang, Intel
+ *  Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ioapic.h"
+#include "ioapic_internal.h"
+#include "sysbus.h"
+
+void ioapic_reset_common(IOAPICCommonState *s)
+{
+    int i;
+
+    s->id = 0;
+    s->ioregsel = 0;
+    s->irr = 0;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
+    }
+}
+
+const VMStateDescription vmstate_ioapic_common = {
+    .name = "ioapic",
+    .version_id = 3,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(id, IOAPICCommonState),
+        VMSTATE_UINT8(ioregsel, IOAPICCommonState),
+        VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
+        VMSTATE_UINT32_V(irr, IOAPICCommonState, 2),
+        VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICCommonState, IOAPIC_NUM_PINS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+int ioapic_init_common(SysBusDevice *dev)
+{
+    IOAPICCommonState *s = FROM_SYSBUS(IOAPICCommonState, dev);
+    IOAPICCommonInfo *info;
+    static int ioapic_no;
+
+    if (ioapic_no >= MAX_IOAPICS) {
+        return -1;
+    }
+
+    info = DO_UPCAST(IOAPICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+    info->init(s, ioapic_no);
+
+    sysbus_init_mmio(&s->busdev, &s->io_memory);
+    ioapic_no++;
+
+    return 0;
+}
diff --git a/hw/ioapic_internal.h b/hw/ioapic_internal.h
new file mode 100644
index 0000000..44d5294
--- /dev/null
+++ b/hw/ioapic_internal.h
@@ -0,0 +1,99 @@
+/*
+ *  IOAPIC emulation logic - internal interfaces
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2009      Xiantao Zhang, Intel
+ *  Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_IOAPIC_INTERNAL_H
+#define QEMU_IOAPIC_INTERNAL_H
+
+#include "hw.h"
+#include "memory.h"
+#include "sysbus.h"
+
+#define MAX_IOAPICS                     1
+
+#define IOAPIC_VERSION                  0x11
+
+#define IOAPIC_LVT_DEST_SHIFT           56
+#define IOAPIC_LVT_MASKED_SHIFT         16
+#define IOAPIC_LVT_TRIGGER_MODE_SHIFT   15
+#define IOAPIC_LVT_REMOTE_IRR_SHIFT     14
+#define IOAPIC_LVT_POLARITY_SHIFT       13
+#define IOAPIC_LVT_DELIV_STATUS_SHIFT   12
+#define IOAPIC_LVT_DEST_MODE_SHIFT      11
+#define IOAPIC_LVT_DELIV_MODE_SHIFT     8
+
+#define IOAPIC_LVT_MASKED               (1 << IOAPIC_LVT_MASKED_SHIFT)
+#define IOAPIC_LVT_REMOTE_IRR           (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT)
+
+#define IOAPIC_TRIGGER_EDGE             0
+#define IOAPIC_TRIGGER_LEVEL            1
+
+/*io{apic,sapic} delivery mode*/
+#define IOAPIC_DM_FIXED                 0x0
+#define IOAPIC_DM_LOWEST_PRIORITY       0x1
+#define IOAPIC_DM_PMI                   0x2
+#define IOAPIC_DM_NMI                   0x4
+#define IOAPIC_DM_INIT                  0x5
+#define IOAPIC_DM_SIPI                  0x6
+#define IOAPIC_DM_EXTINT                0x7
+#define IOAPIC_DM_MASK                  0x7
+
+#define IOAPIC_VECTOR_MASK              0xff
+
+#define IOAPIC_IOREGSEL                 0x00
+#define IOAPIC_IOWIN                    0x10
+
+#define IOAPIC_REG_ID                   0x00
+#define IOAPIC_REG_VER                  0x01
+#define IOAPIC_REG_ARB                  0x02
+#define IOAPIC_REG_REDTBL_BASE          0x10
+#define IOAPIC_ID                       0x00
+
+#define IOAPIC_ID_SHIFT                 24
+#define IOAPIC_ID_MASK                  0xf
+
+#define IOAPIC_VER_ENTRIES_SHIFT        16
+
+typedef struct IOAPICCommonState IOAPICCommonState;
+
+struct IOAPICCommonState {
+    SysBusDevice busdev;
+    MemoryRegion io_memory;
+    uint8_t id;
+    uint8_t ioregsel;
+    uint32_t irr;
+    uint64_t ioredtbl[IOAPIC_NUM_PINS];
+};
+
+typedef struct IOAPICCommonInfo IOAPICCommonInfo;
+
+struct IOAPICCommonInfo {
+    SysBusDeviceInfo busdev;
+    void (*init)(IOAPICCommonState *s, int instance_no);
+};
+
+#define IOAPIC_VMSTATE_VERSION 3
+
+extern const VMStateDescription vmstate_ioapic_common;
+
+int ioapic_init_common(SysBusDevice *dev);
+void ioapic_reset_common(IOAPICCommonState *s);
+
+#endif /* !QEMU_IOAPIC_INTERNAL_H */
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 11/18] ioapic: Factor out base class for KVM reuse
@ 2012-01-13 17:35   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

Split up the IOAPIC analogously to APIC and i8259. KVM will share the
IOAPICCommonState, the vmstate, reset logic and certain init parts with
the user space model.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.target      |    2 +-
 hw/ioapic.c          |  140 ++++++++++++-------------------------------------
 hw/ioapic_common.c   |   70 +++++++++++++++++++++++++
 hw/ioapic_internal.h |   99 +++++++++++++++++++++++++++++++++++
 4 files changed, 205 insertions(+), 106 deletions(-)
 create mode 100644 hw/ioapic_common.c
 create mode 100644 hw/ioapic_internal.h

diff --git a/Makefile.target b/Makefile.target
index a8acece..4fa91d3 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -223,7 +223,7 @@ obj-$(CONFIG_IVSHMEM) += ivshmem.o
 # Hardware support
 obj-i386-y += vga.o
 obj-i386-y += mc146818rtc.o pc.o
-obj-i386-y += cirrus_vga.o sga.o apic_common.o apic.o ioapic.o piix_pci.o
+obj-i386-y += cirrus_vga.o sga.o apic_common.o apic.o ioapic_common.o ioapic.o piix_pci.o
 obj-i386-y += vmport.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
diff --git a/hw/ioapic.c b/hw/ioapic.c
index 0743af6..a61aeba 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -24,9 +24,7 @@
 #include "pc.h"
 #include "apic.h"
 #include "ioapic.h"
-#include "qemu-timer.h"
-#include "host-utils.h"
-#include "sysbus.h"
+#include "ioapic_internal.h"
 
 //#define DEBUG_IOAPIC
 
@@ -37,65 +35,15 @@
 #define DPRINTF(fmt, ...)
 #endif
 
-#define MAX_IOAPICS                     1
-
-#define IOAPIC_VERSION                  0x11
-
-#define IOAPIC_LVT_DEST_SHIFT           56
-#define IOAPIC_LVT_MASKED_SHIFT         16
-#define IOAPIC_LVT_TRIGGER_MODE_SHIFT   15
-#define IOAPIC_LVT_REMOTE_IRR_SHIFT     14
-#define IOAPIC_LVT_POLARITY_SHIFT       13
-#define IOAPIC_LVT_DELIV_STATUS_SHIFT   12
-#define IOAPIC_LVT_DEST_MODE_SHIFT      11
-#define IOAPIC_LVT_DELIV_MODE_SHIFT     8
-
-#define IOAPIC_LVT_MASKED               (1 << IOAPIC_LVT_MASKED_SHIFT)
-#define IOAPIC_LVT_REMOTE_IRR           (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT)
-
-#define IOAPIC_TRIGGER_EDGE             0
-#define IOAPIC_TRIGGER_LEVEL            1
-
-/*io{apic,sapic} delivery mode*/
-#define IOAPIC_DM_FIXED                 0x0
-#define IOAPIC_DM_LOWEST_PRIORITY       0x1
-#define IOAPIC_DM_PMI                   0x2
-#define IOAPIC_DM_NMI                   0x4
-#define IOAPIC_DM_INIT                  0x5
-#define IOAPIC_DM_SIPI                  0x6
-#define IOAPIC_DM_EXTINT                0x7
-#define IOAPIC_DM_MASK                  0x7
-
-#define IOAPIC_VECTOR_MASK              0xff
-
-#define IOAPIC_IOREGSEL                 0x00
-#define IOAPIC_IOWIN                    0x10
-
-#define IOAPIC_REG_ID                   0x00
-#define IOAPIC_REG_VER                  0x01
-#define IOAPIC_REG_ARB                  0x02
-#define IOAPIC_REG_REDTBL_BASE          0x10
-#define IOAPIC_ID                       0x00
-
-#define IOAPIC_ID_SHIFT                 24
-#define IOAPIC_ID_MASK                  0xf
-
-#define IOAPIC_VER_ENTRIES_SHIFT        16
-
 typedef struct IOAPICState IOAPICState;
 
 struct IOAPICState {
-    SysBusDevice busdev;
-    MemoryRegion io_memory;
-    uint8_t id;
-    uint8_t ioregsel;
-    uint32_t irr;
-    uint64_t ioredtbl[IOAPIC_NUM_PINS];
+    IOAPICCommonState ioapic;
 };
 
-static IOAPICState *ioapics[MAX_IOAPICS];
+static IOAPICCommonState *ioapics[MAX_IOAPICS];
 
-static void ioapic_service(IOAPICState *s)
+static void ioapic_service(IOAPICCommonState *s)
 {
     uint8_t i;
     uint8_t trig_mode;
@@ -135,7 +83,7 @@ static void ioapic_service(IOAPICState *s)
 
 static void ioapic_set_irq(void *opaque, int vector, int level)
 {
-    IOAPICState *s = opaque;
+    IOAPICCommonState *s = opaque;
 
     /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
      * to GSI 2.  GSI maps to ioapic 1-1.  This is not
@@ -174,7 +122,7 @@ static void ioapic_set_irq(void *opaque, int vector, int level)
 
 void ioapic_eoi_broadcast(int vector)
 {
-    IOAPICState *s;
+    IOAPICCommonState *s;
     uint64_t entry;
     int i, n;
 
@@ -199,7 +147,7 @@ void ioapic_eoi_broadcast(int vector)
 static uint64_t
 ioapic_mem_read(void *opaque, target_phys_addr_t addr, unsigned int size)
 {
-    IOAPICState *s = opaque;
+    IOAPICCommonState *s = opaque;
     int index;
     uint32_t val = 0;
 
@@ -242,7 +190,7 @@ static void
 ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val,
                  unsigned int size)
 {
-    IOAPICState *s = opaque;
+    IOAPICCommonState *s = opaque;
     int index;
 
     switch (addr & 0xff) {
@@ -278,32 +226,11 @@ ioapic_mem_write(void *opaque, target_phys_addr_t addr, uint64_t val,
     }
 }
 
-static const VMStateDescription vmstate_ioapic = {
-    .name = "ioapic",
-    .version_id = 3,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_UINT8(id, IOAPICState),
-        VMSTATE_UINT8(ioregsel, IOAPICState),
-        VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
-        VMSTATE_UINT32_V(irr, IOAPICState, 2),
-        VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICState, IOAPIC_NUM_PINS),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void ioapic_reset(DeviceState *d)
+static void ioapic_reset(DeviceState *dev)
 {
-    IOAPICState *s = DO_UPCAST(IOAPICState, busdev.qdev, d);
-    int i;
+    IOAPICState *s = DO_UPCAST(IOAPICState, ioapic.busdev.qdev, dev);
 
-    s->id = 0;
-    s->ioregsel = 0;
-    s->irr = 0;
-    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
-        s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
-    }
+    ioapic_reset_common(&s->ioapic);
 }
 
 static const MemoryRegionOps ioapic_io_ops = {
@@ -312,37 +239,40 @@ static const MemoryRegionOps ioapic_io_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static int ioapic_init1(SysBusDevice *dev)
+static void ioapic_init(IOAPICCommonState *s, int instance_no)
 {
-    IOAPICState *s = FROM_SYSBUS(IOAPICState, dev);
-    static int ioapic_no;
-
-    if (ioapic_no >= MAX_IOAPICS) {
-        return -1;
-    }
-
     memory_region_init_io(&s->io_memory, &ioapic_io_ops, s, "ioapic", 0x1000);
-    sysbus_init_mmio(dev, &s->io_memory);
 
-    qdev_init_gpio_in(&dev->qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
+    qdev_init_gpio_in(&s->busdev.qdev, ioapic_set_irq, IOAPIC_NUM_PINS);
 
-    ioapics[ioapic_no++] = s;
-
-    return 0;
+    ioapics[instance_no] = s;
 }
 
-static SysBusDeviceInfo ioapic_info = {
-    .init = ioapic_init1,
-    .qdev.name = "ioapic",
-    .qdev.size = sizeof(IOAPICState),
-    .qdev.vmsd = &vmstate_ioapic,
-    .qdev.reset = ioapic_reset,
-    .qdev.no_user = 1,
+static const VMStateDescription vmstate_ioapic = {
+    .name = "ioapic",
+    .version_id = IOAPIC_VMSTATE_VERSION,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(ioapic, IOAPICState, 0, vmstate_ioapic_common,
+                       IOAPICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static IOAPICCommonInfo ioapic_info = {
+    .busdev.init = ioapic_init_common,
+    .busdev.qdev.name = "ioapic",
+    .busdev.qdev.size = sizeof(IOAPICState),
+    .busdev.qdev.vmsd = &vmstate_ioapic,
+    .busdev.qdev.reset = ioapic_reset,
+    .busdev.qdev.no_user = 1,
+    .init = ioapic_init,
 };
 
 static void ioapic_register_devices(void)
 {
-    sysbus_register_withprop(&ioapic_info);
+    sysbus_register_withprop(&ioapic_info.busdev);
 }
 
 device_init(ioapic_register_devices)
diff --git a/hw/ioapic_common.c b/hw/ioapic_common.c
new file mode 100644
index 0000000..8535ce2
--- /dev/null
+++ b/hw/ioapic_common.c
@@ -0,0 +1,70 @@
+/*
+ *  IOAPIC emulation logic - common bits of emulated and KVM kernel model
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2009      Xiantao Zhang, Intel
+ *  Copyright (c) 2011      Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ioapic.h"
+#include "ioapic_internal.h"
+#include "sysbus.h"
+
+void ioapic_reset_common(IOAPICCommonState *s)
+{
+    int i;
+
+    s->id = 0;
+    s->ioregsel = 0;
+    s->irr = 0;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        s->ioredtbl[i] = 1 << IOAPIC_LVT_MASKED_SHIFT;
+    }
+}
+
+const VMStateDescription vmstate_ioapic_common = {
+    .name = "ioapic",
+    .version_id = 3,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8(id, IOAPICCommonState),
+        VMSTATE_UINT8(ioregsel, IOAPICCommonState),
+        VMSTATE_UNUSED_V(2, 8), /* to account for qemu-kvm's v2 format */
+        VMSTATE_UINT32_V(irr, IOAPICCommonState, 2),
+        VMSTATE_UINT64_ARRAY(ioredtbl, IOAPICCommonState, IOAPIC_NUM_PINS),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+int ioapic_init_common(SysBusDevice *dev)
+{
+    IOAPICCommonState *s = FROM_SYSBUS(IOAPICCommonState, dev);
+    IOAPICCommonInfo *info;
+    static int ioapic_no;
+
+    if (ioapic_no >= MAX_IOAPICS) {
+        return -1;
+    }
+
+    info = DO_UPCAST(IOAPICCommonInfo, busdev.qdev, s->busdev.qdev.info);
+    info->init(s, ioapic_no);
+
+    sysbus_init_mmio(&s->busdev, &s->io_memory);
+    ioapic_no++;
+
+    return 0;
+}
diff --git a/hw/ioapic_internal.h b/hw/ioapic_internal.h
new file mode 100644
index 0000000..44d5294
--- /dev/null
+++ b/hw/ioapic_internal.h
@@ -0,0 +1,99 @@
+/*
+ *  IOAPIC emulation logic - internal interfaces
+ *
+ *  Copyright (c) 2004-2005 Fabrice Bellard
+ *  Copyright (c) 2009      Xiantao Zhang, Intel
+ *  Copyright (c) 2011 Jan Kiszka, Siemens AG
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef QEMU_IOAPIC_INTERNAL_H
+#define QEMU_IOAPIC_INTERNAL_H
+
+#include "hw.h"
+#include "memory.h"
+#include "sysbus.h"
+
+#define MAX_IOAPICS                     1
+
+#define IOAPIC_VERSION                  0x11
+
+#define IOAPIC_LVT_DEST_SHIFT           56
+#define IOAPIC_LVT_MASKED_SHIFT         16
+#define IOAPIC_LVT_TRIGGER_MODE_SHIFT   15
+#define IOAPIC_LVT_REMOTE_IRR_SHIFT     14
+#define IOAPIC_LVT_POLARITY_SHIFT       13
+#define IOAPIC_LVT_DELIV_STATUS_SHIFT   12
+#define IOAPIC_LVT_DEST_MODE_SHIFT      11
+#define IOAPIC_LVT_DELIV_MODE_SHIFT     8
+
+#define IOAPIC_LVT_MASKED               (1 << IOAPIC_LVT_MASKED_SHIFT)
+#define IOAPIC_LVT_REMOTE_IRR           (1 << IOAPIC_LVT_REMOTE_IRR_SHIFT)
+
+#define IOAPIC_TRIGGER_EDGE             0
+#define IOAPIC_TRIGGER_LEVEL            1
+
+/*io{apic,sapic} delivery mode*/
+#define IOAPIC_DM_FIXED                 0x0
+#define IOAPIC_DM_LOWEST_PRIORITY       0x1
+#define IOAPIC_DM_PMI                   0x2
+#define IOAPIC_DM_NMI                   0x4
+#define IOAPIC_DM_INIT                  0x5
+#define IOAPIC_DM_SIPI                  0x6
+#define IOAPIC_DM_EXTINT                0x7
+#define IOAPIC_DM_MASK                  0x7
+
+#define IOAPIC_VECTOR_MASK              0xff
+
+#define IOAPIC_IOREGSEL                 0x00
+#define IOAPIC_IOWIN                    0x10
+
+#define IOAPIC_REG_ID                   0x00
+#define IOAPIC_REG_VER                  0x01
+#define IOAPIC_REG_ARB                  0x02
+#define IOAPIC_REG_REDTBL_BASE          0x10
+#define IOAPIC_ID                       0x00
+
+#define IOAPIC_ID_SHIFT                 24
+#define IOAPIC_ID_MASK                  0xf
+
+#define IOAPIC_VER_ENTRIES_SHIFT        16
+
+typedef struct IOAPICCommonState IOAPICCommonState;
+
+struct IOAPICCommonState {
+    SysBusDevice busdev;
+    MemoryRegion io_memory;
+    uint8_t id;
+    uint8_t ioregsel;
+    uint32_t irr;
+    uint64_t ioredtbl[IOAPIC_NUM_PINS];
+};
+
+typedef struct IOAPICCommonInfo IOAPICCommonInfo;
+
+struct IOAPICCommonInfo {
+    SysBusDeviceInfo busdev;
+    void (*init)(IOAPICCommonState *s, int instance_no);
+};
+
+#define IOAPIC_VMSTATE_VERSION 3
+
+extern const VMStateDescription vmstate_ioapic_common;
+
+int ioapic_init_common(SysBusDevice *dev);
+void ioapic_reset_common(IOAPICCommonState *s);
+
+#endif /* !QEMU_IOAPIC_INTERNAL_H */
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 12/18] memory: Introduce memory_region_init_reservation
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:35   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl

Introduce a memory region type that can reserve I/O space. Such regions
are useful for modeling I/O that is only handled outside of QEMU, i.e.
in the context of an accelerator like KVM.

Any access to such a region from QEMU is a bug, but could theoretically
be triggered by guest code (DMA to reserved region). So only warning
about such events once, then ignore them.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 memory.c |   36 ++++++++++++++++++++++++++++++++++++
 memory.h |   16 ++++++++++++++++
 2 files changed, 52 insertions(+), 0 deletions(-)

diff --git a/memory.c b/memory.c
index a7e615a..30eb1b9 100644
--- a/memory.c
+++ b/memory.c
@@ -1049,6 +1049,42 @@ void memory_region_init_rom_device(MemoryRegion *mr,
     mr->backend_registered = true;
 }
 
+static uint64_t invalid_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
+{
+    MemoryRegion *mr = opaque;
+
+    if (!mr->warning_printed) {
+        fprintf(stderr, "Invalid read from memory region %s\n", mr->name);
+        mr->warning_printed = true;
+    }
+    return -1U;
+}
+
+static void invalid_write(void *opaque, target_phys_addr_t addr, uint64_t data,
+                          unsigned size)
+{
+    MemoryRegion *mr = opaque;
+
+    if (!mr->warning_printed) {
+        fprintf(stderr, "Invalid write to memory region %s\n", mr->name);
+        mr->warning_printed = true;
+    }
+}
+
+static const MemoryRegionOps reservation_ops = {
+    .read = invalid_read,
+    .write = invalid_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void memory_region_init_reservation(MemoryRegion *mr,
+                                    const char *name,
+                                    uint64_t size)
+{
+    memory_region_init_io(mr, &reservation_ops, mr, name, size);
+}
+
 void memory_region_destroy(MemoryRegion *mr)
 {
     assert(QTAILQ_EMPTY(&mr->subregions));
diff --git a/memory.h b/memory.h
index fe643ff..4b5645f 100644
--- a/memory.h
+++ b/memory.h
@@ -124,6 +124,7 @@ struct MemoryRegion {
     bool readable;
     bool readonly; /* For RAM regions */
     bool enabled;
+    bool warning_printed; /* For reservations */
     MemoryRegion *alias;
     target_phys_addr_t alias_offset;
     unsigned priority;
@@ -251,6 +252,21 @@ void memory_region_init_rom_device(MemoryRegion *mr,
                                    uint64_t size);
 
 /**
+ * memory_region_init_reservation: Initialize a memory region that reserves
+ *                                 I/O space.
+ *
+ * A reservation region primariy serves debugging purposes.  It claims I/O
+ * space that is not supposed to be handled by QEMU itself.  Any access via
+ * the memory API will cause an abort().
+ *
+ * @mr: the #MemoryRegion to be initialized
+ * @name: used for debugging; not visible to the user or ABI
+ * @size: size of the region.
+ */
+void memory_region_init_reservation(MemoryRegion *mr,
+                                    const char *name,
+                                    uint64_t size);
+/**
  * memory_region_destroy: Destroy a memory region and reclaim all resources.
  *
  * @mr: the region to be destroyed.  May not currently be a subregion
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 12/18] memory: Introduce memory_region_init_reservation
@ 2012-01-13 17:35   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

Introduce a memory region type that can reserve I/O space. Such regions
are useful for modeling I/O that is only handled outside of QEMU, i.e.
in the context of an accelerator like KVM.

Any access to such a region from QEMU is a bug, but could theoretically
be triggered by guest code (DMA to reserved region). So only warning
about such events once, then ignore them.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 memory.c |   36 ++++++++++++++++++++++++++++++++++++
 memory.h |   16 ++++++++++++++++
 2 files changed, 52 insertions(+), 0 deletions(-)

diff --git a/memory.c b/memory.c
index a7e615a..30eb1b9 100644
--- a/memory.c
+++ b/memory.c
@@ -1049,6 +1049,42 @@ void memory_region_init_rom_device(MemoryRegion *mr,
     mr->backend_registered = true;
 }
 
+static uint64_t invalid_read(void *opaque, target_phys_addr_t addr,
+                             unsigned size)
+{
+    MemoryRegion *mr = opaque;
+
+    if (!mr->warning_printed) {
+        fprintf(stderr, "Invalid read from memory region %s\n", mr->name);
+        mr->warning_printed = true;
+    }
+    return -1U;
+}
+
+static void invalid_write(void *opaque, target_phys_addr_t addr, uint64_t data,
+                          unsigned size)
+{
+    MemoryRegion *mr = opaque;
+
+    if (!mr->warning_printed) {
+        fprintf(stderr, "Invalid write to memory region %s\n", mr->name);
+        mr->warning_printed = true;
+    }
+}
+
+static const MemoryRegionOps reservation_ops = {
+    .read = invalid_read,
+    .write = invalid_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+void memory_region_init_reservation(MemoryRegion *mr,
+                                    const char *name,
+                                    uint64_t size)
+{
+    memory_region_init_io(mr, &reservation_ops, mr, name, size);
+}
+
 void memory_region_destroy(MemoryRegion *mr)
 {
     assert(QTAILQ_EMPTY(&mr->subregions));
diff --git a/memory.h b/memory.h
index fe643ff..4b5645f 100644
--- a/memory.h
+++ b/memory.h
@@ -124,6 +124,7 @@ struct MemoryRegion {
     bool readable;
     bool readonly; /* For RAM regions */
     bool enabled;
+    bool warning_printed; /* For reservations */
     MemoryRegion *alias;
     target_phys_addr_t alias_offset;
     unsigned priority;
@@ -251,6 +252,21 @@ void memory_region_init_rom_device(MemoryRegion *mr,
                                    uint64_t size);
 
 /**
+ * memory_region_init_reservation: Initialize a memory region that reserves
+ *                                 I/O space.
+ *
+ * A reservation region primariy serves debugging purposes.  It claims I/O
+ * space that is not supposed to be handled by QEMU itself.  Any access via
+ * the memory API will cause an abort().
+ *
+ * @mr: the #MemoryRegion to be initialized
+ * @name: used for debugging; not visible to the user or ABI
+ * @size: size of the region.
+ */
+void memory_region_init_reservation(MemoryRegion *mr,
+                                    const char *name,
+                                    uint64_t size);
+/**
  * memory_region_destroy: Destroy a memory region and reclaim all resources.
  *
  * @mr: the region to be destroyed.  May not currently be a subregion
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 13/18] kvm: Introduce core services for in-kernel irqchip support
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:35   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl

Add the basic infrastructure to active in-kernel irqchip support, inject
interrupts into these models, and maintain IRQ routes.

Routing is optional and depends on the host arch supporting
KVM_CAP_IRQ_ROUTING. When it's not available on x86, we looe the HPET as
we can't route GSI0 to IOAPIC pin 2.

In-kernel irqchip support will once be controlled by the machine
property 'kernel_irqchip', but this is not yet wired up.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 kvm-all.c         |  149 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 kvm.h             |    8 +++
 target-i386/kvm.c |   11 ++++
 3 files changed, 168 insertions(+), 0 deletions(-)

diff --git a/kvm-all.c b/kvm-all.c
index ac048bc..e91bb46 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -77,6 +77,13 @@ struct KVMState
     int pit_in_kernel;
     int xsave, xcrs;
     int many_ioeventfds;
+    int irqchip_inject_ioctl;
+#ifdef KVM_CAP_IRQ_ROUTING
+    struct kvm_irq_routing *irq_routes;
+    int nr_allocated_irq_routes;
+    uint32_t *used_gsi_bitmap;
+    unsigned int max_gsi;
+#endif
 };
 
 KVMState *kvm_state;
@@ -693,6 +700,138 @@ static void kvm_handle_interrupt(CPUState *env, int mask)
     }
 }
 
+int kvm_irqchip_set_irq(KVMState *s, int irq, int level)
+{
+    struct kvm_irq_level event;
+    int ret;
+
+    assert(s->irqchip_in_kernel);
+
+    event.level = level;
+    event.irq = irq;
+    ret = kvm_vm_ioctl(s, s->irqchip_inject_ioctl, &event);
+    if (ret < 0) {
+        perror("kvm_set_irqchip_line");
+        abort();
+    }
+
+    return (s->irqchip_inject_ioctl == KVM_IRQ_LINE) ? 1 : event.status;
+}
+
+#ifdef KVM_CAP_IRQ_ROUTING
+static void set_gsi(KVMState *s, unsigned int gsi)
+{
+    assert(gsi < s->max_gsi);
+
+    s->used_gsi_bitmap[gsi / 32] |= 1U << (gsi % 32);
+}
+
+static void kvm_init_irq_routing(KVMState *s)
+{
+    int gsi_count;
+
+    gsi_count = kvm_check_extension(s, KVM_CAP_IRQ_ROUTING);
+    if (gsi_count > 0) {
+        unsigned int gsi_bits, i;
+
+        /* Round up so we can search ints using ffs */
+        gsi_bits = (gsi_count + 31) / 32;
+        s->used_gsi_bitmap = g_malloc0(gsi_bits / 8);
+        s->max_gsi = gsi_bits;
+
+        /* Mark any over-allocated bits as already in use */
+        for (i = gsi_count; i < gsi_bits; i++) {
+            set_gsi(s, i);
+        }
+    }
+
+    s->irq_routes = g_malloc0(sizeof(*s->irq_routes));
+    s->nr_allocated_irq_routes = 0;
+
+    kvm_arch_init_irq_routing(s);
+}
+
+static void kvm_add_routing_entry(KVMState *s,
+                                  struct kvm_irq_routing_entry *entry)
+{
+    struct kvm_irq_routing_entry *new;
+    int n, size;
+
+    if (s->irq_routes->nr == s->nr_allocated_irq_routes) {
+        n = s->nr_allocated_irq_routes * 2;
+        if (n < 64) {
+            n = 64;
+        }
+        size = sizeof(struct kvm_irq_routing);
+        size += n * sizeof(*new);
+        s->irq_routes = g_realloc(s->irq_routes, size);
+        s->nr_allocated_irq_routes = n;
+    }
+    n = s->irq_routes->nr++;
+    new = &s->irq_routes->entries[n];
+    memset(new, 0, sizeof(*new));
+    new->gsi = entry->gsi;
+    new->type = entry->type;
+    new->flags = entry->flags;
+    new->u = entry->u;
+
+    set_gsi(s, entry->gsi);
+}
+
+void kvm_irqchip_add_route(KVMState *s, int irq, int irqchip, int pin)
+{
+    struct kvm_irq_routing_entry e;
+
+    e.gsi = irq;
+    e.type = KVM_IRQ_ROUTING_IRQCHIP;
+    e.flags = 0;
+    e.u.irqchip.irqchip = irqchip;
+    e.u.irqchip.pin = pin;
+    kvm_add_routing_entry(s, &e);
+}
+
+int kvm_irqchip_commit_routes(KVMState *s)
+{
+    s->irq_routes->flags = 0;
+    return kvm_vm_ioctl(s, KVM_SET_GSI_ROUTING, s->irq_routes);
+}
+
+#else /* !KVM_CAP_IRQ_ROUTING */
+
+static void kvm_init_irq_routing(KVMState *s)
+{
+}
+#endif /* !KVM_CAP_IRQ_ROUTING */
+
+static int kvm_irqchip_create(KVMState *s)
+{
+    QemuOptsList *list = qemu_find_opts("machine");
+    int ret;
+
+    if (QTAILQ_EMPTY(&list->head) ||
+        !qemu_opt_get_bool(QTAILQ_FIRST(&list->head),
+                           "kernel_irqchip", false) ||
+        !kvm_check_extension(s, KVM_CAP_IRQCHIP)) {
+        return 0;
+    }
+
+    ret = kvm_vm_ioctl(s, KVM_CREATE_IRQCHIP);
+    if (ret < 0) {
+        fprintf(stderr, "Create kernel irqchip failed\n");
+        return ret;
+    }
+
+    s->irqchip_inject_ioctl = KVM_IRQ_LINE;
+    if (kvm_check_extension(s, KVM_CAP_IRQ_INJECT_STATUS)) {
+        s->irqchip_inject_ioctl = KVM_IRQ_LINE_STATUS;
+    }
+    s->irqchip_in_kernel = 1;
+
+    kvm_init_irq_routing(s);
+
+    return 0;
+}
+
 int kvm_init(void)
 {
     static const char upgrade_note[] =
@@ -788,6 +927,11 @@ int kvm_init(void)
         goto err;
     }
 
+    ret = kvm_irqchip_create(s);
+    if (ret < 0) {
+        goto err;
+    }
+
     kvm_state = s;
     cpu_register_phys_memory_client(&kvm_cpu_phys_memory_client);
 
@@ -1123,6 +1267,11 @@ int kvm_has_many_ioeventfds(void)
     return kvm_state->many_ioeventfds;
 }
 
+int kvm_has_gsi_routing(void)
+{
+    return kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING);
+}
+
 void kvm_setup_guest_memory(void *start, size_t size)
 {
     if (!kvm_has_sync_mmu()) {
diff --git a/kvm.h b/kvm.h
index 243b063..0d6c453 100644
--- a/kvm.h
+++ b/kvm.h
@@ -51,6 +51,7 @@ int kvm_has_debugregs(void);
 int kvm_has_xsave(void);
 int kvm_has_xcrs(void);
 int kvm_has_many_ioeventfds(void);
+int kvm_has_gsi_routing(void);
 
 #ifdef NEED_CPU_H
 int kvm_init_vcpu(CPUState *env);
@@ -124,6 +125,13 @@ void kvm_arch_reset_vcpu(CPUState *env);
 int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr);
 int kvm_arch_on_sigbus(int code, void *addr);
 
+void kvm_arch_init_irq_routing(KVMState *s);
+
+int kvm_irqchip_set_irq(KVMState *s, int irq, int level);
+
+void kvm_irqchip_add_route(KVMState *s, int gsi, int irqchip, int pin);
+int kvm_irqchip_commit_routes(KVMState *s);
+
 struct kvm_guest_debug;
 struct kvm_debug_exit_arch;
 
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index d206852..9d1191f 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1879,3 +1879,14 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env)
     return !(env->cr[0] & CR0_PE_MASK) ||
            ((env->segs[R_CS].selector  & 3) != 3);
 }
+
+void kvm_arch_init_irq_routing(KVMState *s)
+{
+    if (!kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
+        /* If kernel can't do irq routing, interrupt source
+         * override 0->2 cannot be set up as required by HPET.
+         * So we have to disable it.
+         */
+        no_hpet = 1;
+    }
+}
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 13/18] kvm: Introduce core services for in-kernel irqchip support
@ 2012-01-13 17:35   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

Add the basic infrastructure to active in-kernel irqchip support, inject
interrupts into these models, and maintain IRQ routes.

Routing is optional and depends on the host arch supporting
KVM_CAP_IRQ_ROUTING. When it's not available on x86, we looe the HPET as
we can't route GSI0 to IOAPIC pin 2.

In-kernel irqchip support will once be controlled by the machine
property 'kernel_irqchip', but this is not yet wired up.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 kvm-all.c         |  149 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 kvm.h             |    8 +++
 target-i386/kvm.c |   11 ++++
 3 files changed, 168 insertions(+), 0 deletions(-)

diff --git a/kvm-all.c b/kvm-all.c
index ac048bc..e91bb46 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -77,6 +77,13 @@ struct KVMState
     int pit_in_kernel;
     int xsave, xcrs;
     int many_ioeventfds;
+    int irqchip_inject_ioctl;
+#ifdef KVM_CAP_IRQ_ROUTING
+    struct kvm_irq_routing *irq_routes;
+    int nr_allocated_irq_routes;
+    uint32_t *used_gsi_bitmap;
+    unsigned int max_gsi;
+#endif
 };
 
 KVMState *kvm_state;
@@ -693,6 +700,138 @@ static void kvm_handle_interrupt(CPUState *env, int mask)
     }
 }
 
+int kvm_irqchip_set_irq(KVMState *s, int irq, int level)
+{
+    struct kvm_irq_level event;
+    int ret;
+
+    assert(s->irqchip_in_kernel);
+
+    event.level = level;
+    event.irq = irq;
+    ret = kvm_vm_ioctl(s, s->irqchip_inject_ioctl, &event);
+    if (ret < 0) {
+        perror("kvm_set_irqchip_line");
+        abort();
+    }
+
+    return (s->irqchip_inject_ioctl == KVM_IRQ_LINE) ? 1 : event.status;
+}
+
+#ifdef KVM_CAP_IRQ_ROUTING
+static void set_gsi(KVMState *s, unsigned int gsi)
+{
+    assert(gsi < s->max_gsi);
+
+    s->used_gsi_bitmap[gsi / 32] |= 1U << (gsi % 32);
+}
+
+static void kvm_init_irq_routing(KVMState *s)
+{
+    int gsi_count;
+
+    gsi_count = kvm_check_extension(s, KVM_CAP_IRQ_ROUTING);
+    if (gsi_count > 0) {
+        unsigned int gsi_bits, i;
+
+        /* Round up so we can search ints using ffs */
+        gsi_bits = (gsi_count + 31) / 32;
+        s->used_gsi_bitmap = g_malloc0(gsi_bits / 8);
+        s->max_gsi = gsi_bits;
+
+        /* Mark any over-allocated bits as already in use */
+        for (i = gsi_count; i < gsi_bits; i++) {
+            set_gsi(s, i);
+        }
+    }
+
+    s->irq_routes = g_malloc0(sizeof(*s->irq_routes));
+    s->nr_allocated_irq_routes = 0;
+
+    kvm_arch_init_irq_routing(s);
+}
+
+static void kvm_add_routing_entry(KVMState *s,
+                                  struct kvm_irq_routing_entry *entry)
+{
+    struct kvm_irq_routing_entry *new;
+    int n, size;
+
+    if (s->irq_routes->nr == s->nr_allocated_irq_routes) {
+        n = s->nr_allocated_irq_routes * 2;
+        if (n < 64) {
+            n = 64;
+        }
+        size = sizeof(struct kvm_irq_routing);
+        size += n * sizeof(*new);
+        s->irq_routes = g_realloc(s->irq_routes, size);
+        s->nr_allocated_irq_routes = n;
+    }
+    n = s->irq_routes->nr++;
+    new = &s->irq_routes->entries[n];
+    memset(new, 0, sizeof(*new));
+    new->gsi = entry->gsi;
+    new->type = entry->type;
+    new->flags = entry->flags;
+    new->u = entry->u;
+
+    set_gsi(s, entry->gsi);
+}
+
+void kvm_irqchip_add_route(KVMState *s, int irq, int irqchip, int pin)
+{
+    struct kvm_irq_routing_entry e;
+
+    e.gsi = irq;
+    e.type = KVM_IRQ_ROUTING_IRQCHIP;
+    e.flags = 0;
+    e.u.irqchip.irqchip = irqchip;
+    e.u.irqchip.pin = pin;
+    kvm_add_routing_entry(s, &e);
+}
+
+int kvm_irqchip_commit_routes(KVMState *s)
+{
+    s->irq_routes->flags = 0;
+    return kvm_vm_ioctl(s, KVM_SET_GSI_ROUTING, s->irq_routes);
+}
+
+#else /* !KVM_CAP_IRQ_ROUTING */
+
+static void kvm_init_irq_routing(KVMState *s)
+{
+}
+#endif /* !KVM_CAP_IRQ_ROUTING */
+
+static int kvm_irqchip_create(KVMState *s)
+{
+    QemuOptsList *list = qemu_find_opts("machine");
+    int ret;
+
+    if (QTAILQ_EMPTY(&list->head) ||
+        !qemu_opt_get_bool(QTAILQ_FIRST(&list->head),
+                           "kernel_irqchip", false) ||
+        !kvm_check_extension(s, KVM_CAP_IRQCHIP)) {
+        return 0;
+    }
+
+    ret = kvm_vm_ioctl(s, KVM_CREATE_IRQCHIP);
+    if (ret < 0) {
+        fprintf(stderr, "Create kernel irqchip failed\n");
+        return ret;
+    }
+
+    s->irqchip_inject_ioctl = KVM_IRQ_LINE;
+    if (kvm_check_extension(s, KVM_CAP_IRQ_INJECT_STATUS)) {
+        s->irqchip_inject_ioctl = KVM_IRQ_LINE_STATUS;
+    }
+    s->irqchip_in_kernel = 1;
+
+    kvm_init_irq_routing(s);
+
+    return 0;
+}
+
 int kvm_init(void)
 {
     static const char upgrade_note[] =
@@ -788,6 +927,11 @@ int kvm_init(void)
         goto err;
     }
 
+    ret = kvm_irqchip_create(s);
+    if (ret < 0) {
+        goto err;
+    }
+
     kvm_state = s;
     cpu_register_phys_memory_client(&kvm_cpu_phys_memory_client);
 
@@ -1123,6 +1267,11 @@ int kvm_has_many_ioeventfds(void)
     return kvm_state->many_ioeventfds;
 }
 
+int kvm_has_gsi_routing(void)
+{
+    return kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING);
+}
+
 void kvm_setup_guest_memory(void *start, size_t size)
 {
     if (!kvm_has_sync_mmu()) {
diff --git a/kvm.h b/kvm.h
index 243b063..0d6c453 100644
--- a/kvm.h
+++ b/kvm.h
@@ -51,6 +51,7 @@ int kvm_has_debugregs(void);
 int kvm_has_xsave(void);
 int kvm_has_xcrs(void);
 int kvm_has_many_ioeventfds(void);
+int kvm_has_gsi_routing(void);
 
 #ifdef NEED_CPU_H
 int kvm_init_vcpu(CPUState *env);
@@ -124,6 +125,13 @@ void kvm_arch_reset_vcpu(CPUState *env);
 int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr);
 int kvm_arch_on_sigbus(int code, void *addr);
 
+void kvm_arch_init_irq_routing(KVMState *s);
+
+int kvm_irqchip_set_irq(KVMState *s, int irq, int level);
+
+void kvm_irqchip_add_route(KVMState *s, int gsi, int irqchip, int pin);
+int kvm_irqchip_commit_routes(KVMState *s);
+
 struct kvm_guest_debug;
 struct kvm_debug_exit_arch;
 
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index d206852..9d1191f 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1879,3 +1879,14 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env)
     return !(env->cr[0] & CR0_PE_MASK) ||
            ((env->segs[R_CS].selector  & 3) != 3);
 }
+
+void kvm_arch_init_irq_routing(KVMState *s)
+{
+    if (!kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
+        /* If kernel can't do irq routing, interrupt source
+         * override 0->2 cannot be set up as required by HPET.
+         * So we have to disable it.
+         */
+        no_hpet = 1;
+    }
+}
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 14/18] kvm: x86: Establish IRQ0 override control
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:35   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl

KVM is forced to disable the IRQ0 override when we run with in-kernel
irqchip but without IRQ routing support of the kernel. Set the fwcfg
value correspondingly. This aligns us with qemu-kvm.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/pc.c    |    3 ++-
 kvm-all.c  |    5 +++++
 kvm-stub.c |    5 +++++
 kvm.h      |    2 ++
 sysemu.h   |    1 -
 vl.c       |    1 -
 6 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/hw/pc.c b/hw/pc.c
index 3f69e09..9519079 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -39,6 +39,7 @@
 #include "msi.h"
 #include "sysbus.h"
 #include "sysemu.h"
+#include "kvm.h"
 #include "blockdev.h"
 #include "ui/qemu-spice.h"
 #include "memory.h"
@@ -609,7 +610,7 @@ static void *bochs_bios_init(void)
     fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
     fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, (uint8_t *)acpi_tables,
                      acpi_tables_len);
-    fw_cfg_add_bytes(fw_cfg, FW_CFG_IRQ0_OVERRIDE, &irq0override, 1);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
 
     smbios_table = smbios_get_table(&smbios_len);
     if (smbios_table)
diff --git a/kvm-all.c b/kvm-all.c
index e91bb46..b06ed7d 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1272,6 +1272,11 @@ int kvm_has_gsi_routing(void)
     return kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING);
 }
 
+int kvm_allows_irq0_override(void)
+{
+    return !kvm_enabled() || !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
+}
+
 void kvm_setup_guest_memory(void *start, size_t size)
 {
     if (!kvm_has_sync_mmu()) {
diff --git a/kvm-stub.c b/kvm-stub.c
index 06064b9..6c2b06b 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -78,6 +78,11 @@ int kvm_has_many_ioeventfds(void)
     return 0;
 }
 
+int kvm_allows_irq0_override(void)
+{
+    return 1;
+}
+
 void kvm_setup_guest_memory(void *start, size_t size)
 {
 }
diff --git a/kvm.h b/kvm.h
index 0d6c453..a3c87af 100644
--- a/kvm.h
+++ b/kvm.h
@@ -53,6 +53,8 @@ int kvm_has_xcrs(void);
 int kvm_has_many_ioeventfds(void);
 int kvm_has_gsi_routing(void);
 
+int kvm_allows_irq0_override(void);
+
 #ifdef NEED_CPU_H
 int kvm_init_vcpu(CPUState *env);
 
diff --git a/sysemu.h b/sysemu.h
index 3806901..6abded1 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -102,7 +102,6 @@ extern int vga_interface_type;
 extern int graphic_width;
 extern int graphic_height;
 extern int graphic_depth;
-extern uint8_t irq0override;
 extern DisplayType display_type;
 extern const char *keyboard_layout;
 extern int win2k_install_hack;
diff --git a/vl.c b/vl.c
index d925424..f77e687 100644
--- a/vl.c
+++ b/vl.c
@@ -218,7 +218,6 @@ int no_reboot = 0;
 int no_shutdown = 0;
 int cursor_hide = 1;
 int graphic_rotate = 0;
-uint8_t irq0override = 1;
 const char *watchdog;
 QEMUOptionRom option_rom[MAX_OPTION_ROMS];
 int nb_option_roms;
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 14/18] kvm: x86: Establish IRQ0 override control
@ 2012-01-13 17:35   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

KVM is forced to disable the IRQ0 override when we run with in-kernel
irqchip but without IRQ routing support of the kernel. Set the fwcfg
value correspondingly. This aligns us with qemu-kvm.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/pc.c    |    3 ++-
 kvm-all.c  |    5 +++++
 kvm-stub.c |    5 +++++
 kvm.h      |    2 ++
 sysemu.h   |    1 -
 vl.c       |    1 -
 6 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/hw/pc.c b/hw/pc.c
index 3f69e09..9519079 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -39,6 +39,7 @@
 #include "msi.h"
 #include "sysbus.h"
 #include "sysemu.h"
+#include "kvm.h"
 #include "blockdev.h"
 #include "ui/qemu-spice.h"
 #include "memory.h"
@@ -609,7 +610,7 @@ static void *bochs_bios_init(void)
     fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
     fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, (uint8_t *)acpi_tables,
                      acpi_tables_len);
-    fw_cfg_add_bytes(fw_cfg, FW_CFG_IRQ0_OVERRIDE, &irq0override, 1);
+    fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override());
 
     smbios_table = smbios_get_table(&smbios_len);
     if (smbios_table)
diff --git a/kvm-all.c b/kvm-all.c
index e91bb46..b06ed7d 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -1272,6 +1272,11 @@ int kvm_has_gsi_routing(void)
     return kvm_check_extension(kvm_state, KVM_CAP_IRQ_ROUTING);
 }
 
+int kvm_allows_irq0_override(void)
+{
+    return !kvm_enabled() || !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
+}
+
 void kvm_setup_guest_memory(void *start, size_t size)
 {
     if (!kvm_has_sync_mmu()) {
diff --git a/kvm-stub.c b/kvm-stub.c
index 06064b9..6c2b06b 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -78,6 +78,11 @@ int kvm_has_many_ioeventfds(void)
     return 0;
 }
 
+int kvm_allows_irq0_override(void)
+{
+    return 1;
+}
+
 void kvm_setup_guest_memory(void *start, size_t size)
 {
 }
diff --git a/kvm.h b/kvm.h
index 0d6c453..a3c87af 100644
--- a/kvm.h
+++ b/kvm.h
@@ -53,6 +53,8 @@ int kvm_has_xcrs(void);
 int kvm_has_many_ioeventfds(void);
 int kvm_has_gsi_routing(void);
 
+int kvm_allows_irq0_override(void);
+
 #ifdef NEED_CPU_H
 int kvm_init_vcpu(CPUState *env);
 
diff --git a/sysemu.h b/sysemu.h
index 3806901..6abded1 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -102,7 +102,6 @@ extern int vga_interface_type;
 extern int graphic_width;
 extern int graphic_height;
 extern int graphic_depth;
-extern uint8_t irq0override;
 extern DisplayType display_type;
 extern const char *keyboard_layout;
 extern int win2k_install_hack;
diff --git a/vl.c b/vl.c
index d925424..f77e687 100644
--- a/vl.c
+++ b/vl.c
@@ -218,7 +218,6 @@ int no_reboot = 0;
 int no_shutdown = 0;
 int cursor_hide = 1;
 int graphic_rotate = 0;
-uint8_t irq0override = 1;
 const char *watchdog;
 QEMUOptionRom option_rom[MAX_OPTION_ROMS];
 int nb_option_roms;
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 15/18] kvm: x86: Add user space part for in-kernel APIC
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:35   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl,
	Lai Jiangshan

This introduces the alternative APIC device which makes use of KVM's
in-kernel device model. External NMI injection via LINT1 is emulated by
checking the current state of the in-kernel APIC, only injecting a NMI
into the VCPU if LINT1 is unmasked and configured to DM_NMI.

MSI is not yet supported, so we disable this when the in-kernel model is
in use.

CC: Lai Jiangshan <laijs@cn.fujitsu.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.target   |    2 +-
 hw/kvm/apic.c     |  165 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pc.c           |   15 +++--
 kvm.h             |    4 +
 target-i386/kvm.c |   38 ++++++++++++
 5 files changed, 218 insertions(+), 6 deletions(-)
 create mode 100644 hw/kvm/apic.c

diff --git a/Makefile.target b/Makefile.target
index 4fa91d3..5e5b5d1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -228,7 +228,7 @@ obj-i386-y += vmport.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvm/clock.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c
new file mode 100644
index 0000000..0254c63
--- /dev/null
+++ b/hw/kvm/apic.c
@@ -0,0 +1,165 @@
+/*
+ * KVM in-kernel APIC support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+typedef struct KVMAPICState KVMAPICState;
+
+struct KVMAPICState {
+    APICCommonState apic;
+};
+
+static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic,
+                                    int reg_id, uint32_t val)
+{
+    *((uint32_t *)(kapic->regs + (reg_id << 4))) = val;
+}
+
+static inline uint32_t kvm_apic_get_reg(struct kvm_lapic_state *kapic,
+                                        int reg_id)
+{
+    return *((uint32_t *)(kapic->regs + (reg_id << 4)));
+}
+
+void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    int i;
+
+    memset(kapic, 0, sizeof(kapic));
+    kvm_apic_set_reg(kapic, 0x2, s->id << 24);
+    kvm_apic_set_reg(kapic, 0x8, s->tpr);
+    kvm_apic_set_reg(kapic, 0xd, s->log_dest << 24);
+    kvm_apic_set_reg(kapic, 0xe, s->dest_mode << 28 | 0x0fffffff);
+    kvm_apic_set_reg(kapic, 0xf, s->spurious_vec);
+    for (i = 0; i < 8; i++) {
+        kvm_apic_set_reg(kapic, 0x10 + i, s->isr[i]);
+        kvm_apic_set_reg(kapic, 0x18 + i, s->tmr[i]);
+        kvm_apic_set_reg(kapic, 0x20 + i, s->irr[i]);
+    }
+    kvm_apic_set_reg(kapic, 0x28, s->esr);
+    kvm_apic_set_reg(kapic, 0x30, s->icr[0]);
+    kvm_apic_set_reg(kapic, 0x31, s->icr[1]);
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        kvm_apic_set_reg(kapic, 0x32 + i, s->lvt[i]);
+    }
+    kvm_apic_set_reg(kapic, 0x38, s->initial_count);
+    kvm_apic_set_reg(kapic, 0x3e, s->divide_conf);
+}
+
+void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    int i, v;
+
+    s->id = kvm_apic_get_reg(kapic, 0x2) >> 24;
+    s->tpr = kvm_apic_get_reg(kapic, 0x8);
+    s->arb_id = kvm_apic_get_reg(kapic, 0x9);
+    s->log_dest = kvm_apic_get_reg(kapic, 0xd) >> 24;
+    s->dest_mode = kvm_apic_get_reg(kapic, 0xe) >> 28;
+    s->spurious_vec = kvm_apic_get_reg(kapic, 0xf);
+    for (i = 0; i < 8; i++) {
+        s->isr[i] = kvm_apic_get_reg(kapic, 0x10 + i);
+        s->tmr[i] = kvm_apic_get_reg(kapic, 0x18 + i);
+        s->irr[i] = kvm_apic_get_reg(kapic, 0x20 + i);
+    }
+    s->esr = kvm_apic_get_reg(kapic, 0x28);
+    s->icr[0] = kvm_apic_get_reg(kapic, 0x30);
+    s->icr[1] = kvm_apic_get_reg(kapic, 0x31);
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        s->lvt[i] = kvm_apic_get_reg(kapic, 0x32 + i);
+    }
+    s->initial_count = kvm_apic_get_reg(kapic, 0x38);
+    s->divide_conf = kvm_apic_get_reg(kapic, 0x3e);
+
+    v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
+    s->count_shift = (v + 1) & 7;
+
+    s->initial_count_load_time = qemu_get_clock_ns(vm_clock);
+    apic_next_timer(s, s->initial_count_load_time);
+}
+
+static void kvm_apic_set_base(APICCommonState *s, uint64_t val)
+{
+    s->apicbase = val;
+}
+
+static void kvm_apic_set_tpr(APICCommonState *s, uint8_t val)
+{
+    s->tpr = (val & 0x0f) << 4;
+}
+
+static void do_inject_external_nmi(void *data)
+{
+    APICCommonState *s = data;
+    CPUState *env = s->cpu_env;
+    uint32_t lvt;
+    int ret;
+
+    cpu_synchronize_state(env);
+
+    lvt = s->lvt[APIC_LVT_LINT1];
+    if (!(lvt & APIC_LVT_MASKED) && ((lvt >> 8) & 7) == APIC_DM_NMI) {
+        ret = kvm_vcpu_ioctl(env, KVM_NMI);
+        if (ret < 0) {
+            fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n",
+                    strerror(-ret));
+        }
+    }
+}
+
+static void kvm_apic_external_nmi(APICCommonState *s)
+{
+    run_on_cpu(s->cpu_env, do_inject_external_nmi, s);
+}
+
+static void kvm_apic_init(APICCommonState *s)
+{
+    memory_region_init_reservation(&s->io_memory, "kvm-apic-msi",
+                                   MSI_SPACE_SIZE);
+}
+
+static const VMStateDescription vmstate_kvm_apic = {
+    .name = "apic",
+    .version_id = APIC_VMSTATE_VERSION,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(apic, KVMAPICState, 0, vmstate_apic_common,
+                       APICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static APICCommonInfo kvm_apic_info = {
+    .busdev.init = apic_init_common,
+    .busdev.qdev.name = "kvm-apic",
+    .busdev.qdev.size = sizeof(KVMAPICState),
+    .busdev.qdev.vmsd = &vmstate_kvm_apic,
+    .busdev.qdev.reset = apic_reset_common,
+    .busdev.qdev.no_user = 1,
+    .busdev.qdev.props = (Property[]) {
+        APIC_PROPERTIES_COMMON(KVMAPICState, apic),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+    .init = kvm_apic_init,
+    .set_base = kvm_apic_set_base,
+    .set_tpr = kvm_apic_set_tpr,
+    .external_nmi = kvm_apic_external_nmi,
+};
+
+static void kvm_apic_register_device(void)
+{
+    sysbus_register_withprop(&kvm_apic_info.busdev);
+}
+
+device_init(kvm_apic_register_device)
diff --git a/hw/pc.c b/hw/pc.c
index 9519079..5f6ac8a 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -879,25 +879,30 @@ DeviceState *cpu_get_current_apic(void)
 static DeviceState *apic_init(void *env, uint8_t apic_id)
 {
     DeviceState *dev;
-    SysBusDevice *d;
     static int apic_mapped;
 
-    dev = qdev_create(NULL, "apic");
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        dev = qdev_create(NULL, "kvm-apic");
+    } else {
+        dev = qdev_create(NULL, "apic");
+    }
     qdev_prop_set_uint8(dev, "id", apic_id);
     qdev_prop_set_ptr(dev, "cpu_env", env);
     qdev_init_nofail(dev);
-    d = sysbus_from_qdev(dev);
 
     /* XXX: mapping more APICs at the same memory location */
     if (apic_mapped == 0) {
         /* NOTE: the APIC is directly connected to the CPU - it is not
            on the global memory bus. */
         /* XXX: what if the base changes? */
-        sysbus_mmio_map(d, 0, MSI_ADDR_BASE);
+        sysbus_mmio_map(sysbus_from_qdev(dev), 0, MSI_ADDR_BASE);
         apic_mapped = 1;
     }
 
-    msi_supported = true;
+    /* KVM does not support MSI yet. */
+    if (!kvm_enabled() || !kvm_irqchip_in_kernel()) {
+        msi_supported = true;
+    }
 
     return dev;
 }
diff --git a/kvm.h b/kvm.h
index a3c87af..f866296 100644
--- a/kvm.h
+++ b/kvm.h
@@ -31,6 +31,7 @@ extern int kvm_allowed;
 #endif
 
 struct kvm_run;
+struct kvm_lapic_state;
 
 typedef struct KVMCapabilityInfo {
     const char *name;
@@ -134,6 +135,9 @@ int kvm_irqchip_set_irq(KVMState *s, int irq, int level);
 void kvm_irqchip_add_route(KVMState *s, int gsi, int irqchip, int pin);
 int kvm_irqchip_commit_routes(KVMState *s);
 
+void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic);
+void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic);
+
 struct kvm_guest_debug;
 struct kvm_debug_exit_arch;
 
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 9d1191f..274b3cb 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1277,6 +1277,36 @@ static int kvm_get_mp_state(CPUState *env)
     return 0;
 }
 
+static int kvm_get_apic(CPUState *env)
+{
+    DeviceState *apic = env->apic_state;
+    struct kvm_lapic_state kapic;
+    int ret;
+
+    if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) {
+        ret = kvm_vcpu_ioctl(env, KVM_GET_LAPIC, &kapic);
+        if (ret < 0) {
+            return ret;
+        }
+
+        kvm_get_apic_state(apic, &kapic);
+    }
+    return 0;
+}
+
+static int kvm_put_apic(CPUState *env)
+{
+    DeviceState *apic = env->apic_state;
+    struct kvm_lapic_state kapic;
+
+    if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_put_apic_state(apic, &kapic);
+
+        return kvm_vcpu_ioctl(env, KVM_SET_LAPIC, &kapic);
+    }
+    return 0;
+}
+
 static int kvm_put_vcpu_events(CPUState *env, int level)
 {
     struct kvm_vcpu_events events;
@@ -1450,6 +1480,10 @@ int kvm_arch_put_registers(CPUState *env, int level)
         if (ret < 0) {
             return ret;
         }
+        ret = kvm_put_apic(env);
+        if (ret < 0) {
+            return ret;
+        }
     }
     ret = kvm_put_vcpu_events(env, level);
     if (ret < 0) {
@@ -1497,6 +1531,10 @@ int kvm_arch_get_registers(CPUState *env)
     if (ret < 0) {
         return ret;
     }
+    ret = kvm_get_apic(env);
+    if (ret < 0) {
+        return ret;
+    }
     ret = kvm_get_vcpu_events(env);
     if (ret < 0) {
         return ret;
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 15/18] kvm: x86: Add user space part for in-kernel APIC
@ 2012-01-13 17:35   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Anthony Liguori, Lai Jiangshan, kvm, Michael S. Tsirkin,
	qemu-devel, Blue Swirl

This introduces the alternative APIC device which makes use of KVM's
in-kernel device model. External NMI injection via LINT1 is emulated by
checking the current state of the in-kernel APIC, only injecting a NMI
into the VCPU if LINT1 is unmasked and configured to DM_NMI.

MSI is not yet supported, so we disable this when the in-kernel model is
in use.

CC: Lai Jiangshan <laijs@cn.fujitsu.com>
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.target   |    2 +-
 hw/kvm/apic.c     |  165 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pc.c           |   15 +++--
 kvm.h             |    4 +
 target-i386/kvm.c |   38 ++++++++++++
 5 files changed, 218 insertions(+), 6 deletions(-)
 create mode 100644 hw/kvm/apic.c

diff --git a/Makefile.target b/Makefile.target
index 4fa91d3..5e5b5d1 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -228,7 +228,7 @@ obj-i386-y += vmport.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvm/clock.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
diff --git a/hw/kvm/apic.c b/hw/kvm/apic.c
new file mode 100644
index 0000000..0254c63
--- /dev/null
+++ b/hw/kvm/apic.c
@@ -0,0 +1,165 @@
+/*
+ * KVM in-kernel APIC support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+typedef struct KVMAPICState KVMAPICState;
+
+struct KVMAPICState {
+    APICCommonState apic;
+};
+
+static inline void kvm_apic_set_reg(struct kvm_lapic_state *kapic,
+                                    int reg_id, uint32_t val)
+{
+    *((uint32_t *)(kapic->regs + (reg_id << 4))) = val;
+}
+
+static inline uint32_t kvm_apic_get_reg(struct kvm_lapic_state *kapic,
+                                        int reg_id)
+{
+    return *((uint32_t *)(kapic->regs + (reg_id << 4)));
+}
+
+void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    int i;
+
+    memset(kapic, 0, sizeof(kapic));
+    kvm_apic_set_reg(kapic, 0x2, s->id << 24);
+    kvm_apic_set_reg(kapic, 0x8, s->tpr);
+    kvm_apic_set_reg(kapic, 0xd, s->log_dest << 24);
+    kvm_apic_set_reg(kapic, 0xe, s->dest_mode << 28 | 0x0fffffff);
+    kvm_apic_set_reg(kapic, 0xf, s->spurious_vec);
+    for (i = 0; i < 8; i++) {
+        kvm_apic_set_reg(kapic, 0x10 + i, s->isr[i]);
+        kvm_apic_set_reg(kapic, 0x18 + i, s->tmr[i]);
+        kvm_apic_set_reg(kapic, 0x20 + i, s->irr[i]);
+    }
+    kvm_apic_set_reg(kapic, 0x28, s->esr);
+    kvm_apic_set_reg(kapic, 0x30, s->icr[0]);
+    kvm_apic_set_reg(kapic, 0x31, s->icr[1]);
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        kvm_apic_set_reg(kapic, 0x32 + i, s->lvt[i]);
+    }
+    kvm_apic_set_reg(kapic, 0x38, s->initial_count);
+    kvm_apic_set_reg(kapic, 0x3e, s->divide_conf);
+}
+
+void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic)
+{
+    APICCommonState *s = DO_UPCAST(APICCommonState, busdev.qdev, d);
+    int i, v;
+
+    s->id = kvm_apic_get_reg(kapic, 0x2) >> 24;
+    s->tpr = kvm_apic_get_reg(kapic, 0x8);
+    s->arb_id = kvm_apic_get_reg(kapic, 0x9);
+    s->log_dest = kvm_apic_get_reg(kapic, 0xd) >> 24;
+    s->dest_mode = kvm_apic_get_reg(kapic, 0xe) >> 28;
+    s->spurious_vec = kvm_apic_get_reg(kapic, 0xf);
+    for (i = 0; i < 8; i++) {
+        s->isr[i] = kvm_apic_get_reg(kapic, 0x10 + i);
+        s->tmr[i] = kvm_apic_get_reg(kapic, 0x18 + i);
+        s->irr[i] = kvm_apic_get_reg(kapic, 0x20 + i);
+    }
+    s->esr = kvm_apic_get_reg(kapic, 0x28);
+    s->icr[0] = kvm_apic_get_reg(kapic, 0x30);
+    s->icr[1] = kvm_apic_get_reg(kapic, 0x31);
+    for (i = 0; i < APIC_LVT_NB; i++) {
+        s->lvt[i] = kvm_apic_get_reg(kapic, 0x32 + i);
+    }
+    s->initial_count = kvm_apic_get_reg(kapic, 0x38);
+    s->divide_conf = kvm_apic_get_reg(kapic, 0x3e);
+
+    v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
+    s->count_shift = (v + 1) & 7;
+
+    s->initial_count_load_time = qemu_get_clock_ns(vm_clock);
+    apic_next_timer(s, s->initial_count_load_time);
+}
+
+static void kvm_apic_set_base(APICCommonState *s, uint64_t val)
+{
+    s->apicbase = val;
+}
+
+static void kvm_apic_set_tpr(APICCommonState *s, uint8_t val)
+{
+    s->tpr = (val & 0x0f) << 4;
+}
+
+static void do_inject_external_nmi(void *data)
+{
+    APICCommonState *s = data;
+    CPUState *env = s->cpu_env;
+    uint32_t lvt;
+    int ret;
+
+    cpu_synchronize_state(env);
+
+    lvt = s->lvt[APIC_LVT_LINT1];
+    if (!(lvt & APIC_LVT_MASKED) && ((lvt >> 8) & 7) == APIC_DM_NMI) {
+        ret = kvm_vcpu_ioctl(env, KVM_NMI);
+        if (ret < 0) {
+            fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n",
+                    strerror(-ret));
+        }
+    }
+}
+
+static void kvm_apic_external_nmi(APICCommonState *s)
+{
+    run_on_cpu(s->cpu_env, do_inject_external_nmi, s);
+}
+
+static void kvm_apic_init(APICCommonState *s)
+{
+    memory_region_init_reservation(&s->io_memory, "kvm-apic-msi",
+                                   MSI_SPACE_SIZE);
+}
+
+static const VMStateDescription vmstate_kvm_apic = {
+    .name = "apic",
+    .version_id = APIC_VMSTATE_VERSION,
+    .minimum_version_id = 3,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(apic, KVMAPICState, 0, vmstate_apic_common,
+                       APICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static APICCommonInfo kvm_apic_info = {
+    .busdev.init = apic_init_common,
+    .busdev.qdev.name = "kvm-apic",
+    .busdev.qdev.size = sizeof(KVMAPICState),
+    .busdev.qdev.vmsd = &vmstate_kvm_apic,
+    .busdev.qdev.reset = apic_reset_common,
+    .busdev.qdev.no_user = 1,
+    .busdev.qdev.props = (Property[]) {
+        APIC_PROPERTIES_COMMON(KVMAPICState, apic),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+    .init = kvm_apic_init,
+    .set_base = kvm_apic_set_base,
+    .set_tpr = kvm_apic_set_tpr,
+    .external_nmi = kvm_apic_external_nmi,
+};
+
+static void kvm_apic_register_device(void)
+{
+    sysbus_register_withprop(&kvm_apic_info.busdev);
+}
+
+device_init(kvm_apic_register_device)
diff --git a/hw/pc.c b/hw/pc.c
index 9519079..5f6ac8a 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -879,25 +879,30 @@ DeviceState *cpu_get_current_apic(void)
 static DeviceState *apic_init(void *env, uint8_t apic_id)
 {
     DeviceState *dev;
-    SysBusDevice *d;
     static int apic_mapped;
 
-    dev = qdev_create(NULL, "apic");
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        dev = qdev_create(NULL, "kvm-apic");
+    } else {
+        dev = qdev_create(NULL, "apic");
+    }
     qdev_prop_set_uint8(dev, "id", apic_id);
     qdev_prop_set_ptr(dev, "cpu_env", env);
     qdev_init_nofail(dev);
-    d = sysbus_from_qdev(dev);
 
     /* XXX: mapping more APICs at the same memory location */
     if (apic_mapped == 0) {
         /* NOTE: the APIC is directly connected to the CPU - it is not
            on the global memory bus. */
         /* XXX: what if the base changes? */
-        sysbus_mmio_map(d, 0, MSI_ADDR_BASE);
+        sysbus_mmio_map(sysbus_from_qdev(dev), 0, MSI_ADDR_BASE);
         apic_mapped = 1;
     }
 
-    msi_supported = true;
+    /* KVM does not support MSI yet. */
+    if (!kvm_enabled() || !kvm_irqchip_in_kernel()) {
+        msi_supported = true;
+    }
 
     return dev;
 }
diff --git a/kvm.h b/kvm.h
index a3c87af..f866296 100644
--- a/kvm.h
+++ b/kvm.h
@@ -31,6 +31,7 @@ extern int kvm_allowed;
 #endif
 
 struct kvm_run;
+struct kvm_lapic_state;
 
 typedef struct KVMCapabilityInfo {
     const char *name;
@@ -134,6 +135,9 @@ int kvm_irqchip_set_irq(KVMState *s, int irq, int level);
 void kvm_irqchip_add_route(KVMState *s, int gsi, int irqchip, int pin);
 int kvm_irqchip_commit_routes(KVMState *s);
 
+void kvm_put_apic_state(DeviceState *d, struct kvm_lapic_state *kapic);
+void kvm_get_apic_state(DeviceState *d, struct kvm_lapic_state *kapic);
+
 struct kvm_guest_debug;
 struct kvm_debug_exit_arch;
 
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 9d1191f..274b3cb 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -1277,6 +1277,36 @@ static int kvm_get_mp_state(CPUState *env)
     return 0;
 }
 
+static int kvm_get_apic(CPUState *env)
+{
+    DeviceState *apic = env->apic_state;
+    struct kvm_lapic_state kapic;
+    int ret;
+
+    if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) {
+        ret = kvm_vcpu_ioctl(env, KVM_GET_LAPIC, &kapic);
+        if (ret < 0) {
+            return ret;
+        }
+
+        kvm_get_apic_state(apic, &kapic);
+    }
+    return 0;
+}
+
+static int kvm_put_apic(CPUState *env)
+{
+    DeviceState *apic = env->apic_state;
+    struct kvm_lapic_state kapic;
+
+    if (apic && kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_put_apic_state(apic, &kapic);
+
+        return kvm_vcpu_ioctl(env, KVM_SET_LAPIC, &kapic);
+    }
+    return 0;
+}
+
 static int kvm_put_vcpu_events(CPUState *env, int level)
 {
     struct kvm_vcpu_events events;
@@ -1450,6 +1480,10 @@ int kvm_arch_put_registers(CPUState *env, int level)
         if (ret < 0) {
             return ret;
         }
+        ret = kvm_put_apic(env);
+        if (ret < 0) {
+            return ret;
+        }
     }
     ret = kvm_put_vcpu_events(env, level);
     if (ret < 0) {
@@ -1497,6 +1531,10 @@ int kvm_arch_get_registers(CPUState *env)
     if (ret < 0) {
         return ret;
     }
+    ret = kvm_get_apic(env);
+    if (ret < 0) {
+        return ret;
+    }
     ret = kvm_get_vcpu_events(env);
     if (ret < 0) {
         return ret;
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 16/18] kvm: x86: Add user space part for in-kernel i8259
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:35   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl

Introduce the alternative 'kvm-i8259' device model that exploits KVM
in-kernel acceleration.

The PIIX3 initialization code is furthermore extended by KVM specific
IRQ route setup. GSI injection differs in KVM mode from the user space
model. As we can dispatch ISA-range IRQs to both IOAPIC and PIC inside
the kernel, we do not need to inject them separately. This is reflected
by a KVM-specific GSI handler.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.target |    2 +-
 hw/kvm/i8259.c  |  173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pc.h         |    1 +
 hw/pc_piix.c    |   50 +++++++++++++++-
 4 files changed, 221 insertions(+), 5 deletions(-)
 create mode 100644 hw/kvm/i8259.c

diff --git a/Makefile.target b/Makefile.target
index 5e5b5d1..f49f96e 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -228,7 +228,7 @@ obj-i386-y += vmport.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c
new file mode 100644
index 0000000..dc05002
--- /dev/null
+++ b/hw/kvm/i8259.c
@@ -0,0 +1,173 @@
+/*
+ * KVM in-kernel PIC (i8259) support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/i8259_internal.h"
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+typedef struct KVMPICState KVMPICState;
+
+struct KVMPICState {
+    PICCommonState pic;
+};
+
+static void kvm_pic_get(PICCommonState *s)
+{
+    struct kvm_irqchip chip;
+    struct kvm_pic_state *kpic;
+    int ret;
+
+    chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
+    ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+        abort();
+    }
+
+    kpic = &chip.chip.pic;
+
+    s->last_irr = kpic->last_irr;
+    s->irr = kpic->irr;
+    s->imr = kpic->imr;
+    s->isr = kpic->isr;
+    s->priority_add = kpic->priority_add;
+    s->irq_base = kpic->irq_base;
+    s->read_reg_select = kpic->read_reg_select;
+    s->poll = kpic->poll;
+    s->special_mask = kpic->special_mask;
+    s->init_state = kpic->init_state;
+    s->auto_eoi = kpic->auto_eoi;
+    s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi;
+    s->special_fully_nested_mode = kpic->special_fully_nested_mode;
+    s->init4 = kpic->init4;
+    s->elcr = kpic->elcr;
+    s->elcr_mask = kpic->elcr_mask;
+}
+
+static void kvm_pic_put(PICCommonState *s)
+{
+    struct kvm_irqchip chip;
+    struct kvm_pic_state *kpic;
+    int ret;
+
+    chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
+
+    kpic = &chip.chip.pic;
+
+    kpic->last_irr = s->last_irr;
+    kpic->irr = s->irr;
+    kpic->imr = s->imr;
+    kpic->isr = s->isr;
+    kpic->priority_add = s->priority_add;
+    kpic->irq_base = s->irq_base;
+    kpic->read_reg_select = s->read_reg_select;
+    kpic->poll = s->poll;
+    kpic->special_mask = s->special_mask;
+    kpic->init_state = s->init_state;
+    kpic->auto_eoi = s->auto_eoi;
+    kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi;
+    kpic->special_fully_nested_mode = s->special_fully_nested_mode;
+    kpic->init4 = s->init4;
+    kpic->elcr = s->elcr;
+    kpic->elcr_mask = s->elcr_mask;
+
+    ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+        abort();
+    }
+}
+
+static void kvm_pic_pre_save(void *opaque)
+{
+    KVMPICState *s = opaque;
+
+    kvm_pic_get(&s->pic);
+}
+
+static int kvm_pic_post_load(void *opaque, int version_id)
+{
+    KVMPICState *s = opaque;
+
+    kvm_pic_put(&s->pic);
+    return 0;
+}
+
+static void kvm_pic_reset(DeviceState *dev)
+{
+    PICCommonState *s = container_of(dev, PICCommonState, dev.qdev);
+
+    pic_reset_common(s);
+    s->elcr = 0;
+
+    kvm_pic_put(s);
+}
+
+static void kvm_pic_set_irq(void *opaque, int irq, int level)
+{
+    int delivered;
+
+    delivered = kvm_irqchip_set_irq(kvm_state, irq, level);
+    apic_report_irq_delivered(delivered);
+}
+
+static int kvm_pic_init(ISADevice *dev)
+{
+    KVMPICState *s = DO_UPCAST(KVMPICState, pic.dev, dev);
+
+    memory_region_init_reservation(&s->pic.base_io, "kvm-pic", 2);
+    memory_region_init_reservation(&s->pic.elcr_io, "kvm-elcr", 1);
+
+    pic_init_common(&s->pic);
+
+    return 0;
+}
+
+qemu_irq *kvm_i8259_init(ISABus *bus)
+{
+    i8259_init_chip("kvm-i8259", bus, true);
+    i8259_init_chip("kvm-i8259", bus, false);
+
+    return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS);
+}
+
+static const VMStateDescription vmstate_kvm_pic = {
+    .name = "i8259",
+    .version_id = PIC_VMSTATE_VERSION,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = kvm_pic_pre_save,
+    .post_load = kvm_pic_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(pic, KVMPICState, 0, vmstate_pic_common, PICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static ISADeviceInfo kvm_i8259_info = {
+    .qdev.name     = "kvm-i8259",
+    .qdev.size     = sizeof(KVMPICState),
+    .qdev.vmsd     = &vmstate_kvm_pic,
+    .qdev.reset    = kvm_pic_reset,
+    .qdev.no_user  = 1,
+    .init          = kvm_pic_init,
+    .qdev.props = (Property[]) {
+        PIC_PROPERTIES_COMMON(KVMPICState, pic),
+        DEFINE_PROP_END_OF_LIST()
+    },
+};
+
+static void kvm_pic_register(void)
+{
+    isa_qdev_register(&kvm_i8259_info);
+}
+
+device_init(kvm_pic_register)
diff --git a/hw/pc.h b/hw/pc.h
index ece069a..5e913db 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -64,6 +64,7 @@ bool parallel_mm_init(MemoryRegion *address_space,
 
 extern DeviceState *isa_pic;
 qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq);
+qemu_irq *kvm_i8259_init(ISABus *bus);
 int pic_read_irq(DeviceState *d);
 int pic_get_output(DeviceState *d);
 void pic_info(Monitor *mon);
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index f44f00e..868f4a5 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -53,6 +53,40 @@ static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
 static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
 static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
 
+static void kvm_piix3_setup_irq_routing(bool pci_enabled)
+{
+    KVMState *s = kvm_state;
+    int ret, i;
+
+    if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
+        for (i = 0; i < 8; ++i) {
+            if (i == 2) {
+                continue;
+            }
+            kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_MASTER, i);
+        }
+        for (i = 8; i < 16; ++i) {
+            kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8);
+        }
+        ret = kvm_irqchip_commit_routes(s);
+        if (ret < 0) {
+            hw_error("KVM IRQ routing setup failed");
+        }
+    }
+}
+
+static void kvm_piix3_gsi_handler(void *opaque, int n, int level)
+{
+    GSIState *s = opaque;
+
+    if (n < ISA_NUM_IRQS) {
+        /* Kernel will forward to both PIC and IOAPIC */
+        qemu_set_irq(s->i8259_irq[n], level);
+    } else {
+        qemu_set_irq(s->ioapic_irq[n], level);
+    }
+}
+
 static void ioapic_init(GSIState *gsi_state)
 {
     DeviceState *dev;
@@ -134,7 +168,13 @@ static void pc_init1(MemoryRegion *system_memory,
     }
 
     gsi_state = g_malloc0(sizeof(*gsi_state));
-    gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_piix3_setup_irq_routing(pci_enabled);
+        gsi = qemu_allocate_irqs(kvm_piix3_gsi_handler, gsi_state,
+                                 GSI_NUM_PINS);
+    } else {
+        gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
+    }
 
     if (pci_enabled) {
         pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
@@ -154,11 +194,13 @@ static void pc_init1(MemoryRegion *system_memory,
     }
     isa_bus_irqs(isa_bus, gsi);
 
-    if (!xen_enabled()) {
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        i8259 = kvm_i8259_init(isa_bus);
+    } else if (xen_enabled()) {
+        i8259 = xen_interrupt_controller_init();
+    } else {
         cpu_irq = pc_allocate_cpu_irq();
         i8259 = i8259_init(isa_bus, cpu_irq[0]);
-    } else {
-        i8259 = xen_interrupt_controller_init();
     }
 
     for (i = 0; i < ISA_NUM_IRQS; i++) {
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 16/18] kvm: x86: Add user space part for in-kernel i8259
@ 2012-01-13 17:35   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

Introduce the alternative 'kvm-i8259' device model that exploits KVM
in-kernel acceleration.

The PIIX3 initialization code is furthermore extended by KVM specific
IRQ route setup. GSI injection differs in KVM mode from the user space
model. As we can dispatch ISA-range IRQs to both IOAPIC and PIC inside
the kernel, we do not need to inject them separately. This is reflected
by a KVM-specific GSI handler.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.target |    2 +-
 hw/kvm/i8259.c  |  173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pc.h         |    1 +
 hw/pc_piix.c    |   50 +++++++++++++++-
 4 files changed, 221 insertions(+), 5 deletions(-)
 create mode 100644 hw/kvm/i8259.c

diff --git a/Makefile.target b/Makefile.target
index 5e5b5d1..f49f96e 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -228,7 +228,7 @@ obj-i386-y += vmport.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
diff --git a/hw/kvm/i8259.c b/hw/kvm/i8259.c
new file mode 100644
index 0000000..dc05002
--- /dev/null
+++ b/hw/kvm/i8259.c
@@ -0,0 +1,173 @@
+/*
+ * KVM in-kernel PIC (i8259) support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+#include "hw/i8259_internal.h"
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+typedef struct KVMPICState KVMPICState;
+
+struct KVMPICState {
+    PICCommonState pic;
+};
+
+static void kvm_pic_get(PICCommonState *s)
+{
+    struct kvm_irqchip chip;
+    struct kvm_pic_state *kpic;
+    int ret;
+
+    chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
+    ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+        abort();
+    }
+
+    kpic = &chip.chip.pic;
+
+    s->last_irr = kpic->last_irr;
+    s->irr = kpic->irr;
+    s->imr = kpic->imr;
+    s->isr = kpic->isr;
+    s->priority_add = kpic->priority_add;
+    s->irq_base = kpic->irq_base;
+    s->read_reg_select = kpic->read_reg_select;
+    s->poll = kpic->poll;
+    s->special_mask = kpic->special_mask;
+    s->init_state = kpic->init_state;
+    s->auto_eoi = kpic->auto_eoi;
+    s->rotate_on_auto_eoi = kpic->rotate_on_auto_eoi;
+    s->special_fully_nested_mode = kpic->special_fully_nested_mode;
+    s->init4 = kpic->init4;
+    s->elcr = kpic->elcr;
+    s->elcr_mask = kpic->elcr_mask;
+}
+
+static void kvm_pic_put(PICCommonState *s)
+{
+    struct kvm_irqchip chip;
+    struct kvm_pic_state *kpic;
+    int ret;
+
+    chip.chip_id = s->master ? KVM_IRQCHIP_PIC_MASTER : KVM_IRQCHIP_PIC_SLAVE;
+
+    kpic = &chip.chip.pic;
+
+    kpic->last_irr = s->last_irr;
+    kpic->irr = s->irr;
+    kpic->imr = s->imr;
+    kpic->isr = s->isr;
+    kpic->priority_add = s->priority_add;
+    kpic->irq_base = s->irq_base;
+    kpic->read_reg_select = s->read_reg_select;
+    kpic->poll = s->poll;
+    kpic->special_mask = s->special_mask;
+    kpic->init_state = s->init_state;
+    kpic->auto_eoi = s->auto_eoi;
+    kpic->rotate_on_auto_eoi = s->rotate_on_auto_eoi;
+    kpic->special_fully_nested_mode = s->special_fully_nested_mode;
+    kpic->init4 = s->init4;
+    kpic->elcr = s->elcr;
+    kpic->elcr_mask = s->elcr_mask;
+
+    ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+        abort();
+    }
+}
+
+static void kvm_pic_pre_save(void *opaque)
+{
+    KVMPICState *s = opaque;
+
+    kvm_pic_get(&s->pic);
+}
+
+static int kvm_pic_post_load(void *opaque, int version_id)
+{
+    KVMPICState *s = opaque;
+
+    kvm_pic_put(&s->pic);
+    return 0;
+}
+
+static void kvm_pic_reset(DeviceState *dev)
+{
+    PICCommonState *s = container_of(dev, PICCommonState, dev.qdev);
+
+    pic_reset_common(s);
+    s->elcr = 0;
+
+    kvm_pic_put(s);
+}
+
+static void kvm_pic_set_irq(void *opaque, int irq, int level)
+{
+    int delivered;
+
+    delivered = kvm_irqchip_set_irq(kvm_state, irq, level);
+    apic_report_irq_delivered(delivered);
+}
+
+static int kvm_pic_init(ISADevice *dev)
+{
+    KVMPICState *s = DO_UPCAST(KVMPICState, pic.dev, dev);
+
+    memory_region_init_reservation(&s->pic.base_io, "kvm-pic", 2);
+    memory_region_init_reservation(&s->pic.elcr_io, "kvm-elcr", 1);
+
+    pic_init_common(&s->pic);
+
+    return 0;
+}
+
+qemu_irq *kvm_i8259_init(ISABus *bus)
+{
+    i8259_init_chip("kvm-i8259", bus, true);
+    i8259_init_chip("kvm-i8259", bus, false);
+
+    return qemu_allocate_irqs(kvm_pic_set_irq, NULL, ISA_NUM_IRQS);
+}
+
+static const VMStateDescription vmstate_kvm_pic = {
+    .name = "i8259",
+    .version_id = PIC_VMSTATE_VERSION,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = kvm_pic_pre_save,
+    .post_load = kvm_pic_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(pic, KVMPICState, 0, vmstate_pic_common, PICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static ISADeviceInfo kvm_i8259_info = {
+    .qdev.name     = "kvm-i8259",
+    .qdev.size     = sizeof(KVMPICState),
+    .qdev.vmsd     = &vmstate_kvm_pic,
+    .qdev.reset    = kvm_pic_reset,
+    .qdev.no_user  = 1,
+    .init          = kvm_pic_init,
+    .qdev.props = (Property[]) {
+        PIC_PROPERTIES_COMMON(KVMPICState, pic),
+        DEFINE_PROP_END_OF_LIST()
+    },
+};
+
+static void kvm_pic_register(void)
+{
+    isa_qdev_register(&kvm_i8259_info);
+}
+
+device_init(kvm_pic_register)
diff --git a/hw/pc.h b/hw/pc.h
index ece069a..5e913db 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -64,6 +64,7 @@ bool parallel_mm_init(MemoryRegion *address_space,
 
 extern DeviceState *isa_pic;
 qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq);
+qemu_irq *kvm_i8259_init(ISABus *bus);
 int pic_read_irq(DeviceState *d);
 int pic_get_output(DeviceState *d);
 void pic_info(Monitor *mon);
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index f44f00e..868f4a5 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -53,6 +53,40 @@ static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
 static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
 static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
 
+static void kvm_piix3_setup_irq_routing(bool pci_enabled)
+{
+    KVMState *s = kvm_state;
+    int ret, i;
+
+    if (kvm_check_extension(s, KVM_CAP_IRQ_ROUTING)) {
+        for (i = 0; i < 8; ++i) {
+            if (i == 2) {
+                continue;
+            }
+            kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_MASTER, i);
+        }
+        for (i = 8; i < 16; ++i) {
+            kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8);
+        }
+        ret = kvm_irqchip_commit_routes(s);
+        if (ret < 0) {
+            hw_error("KVM IRQ routing setup failed");
+        }
+    }
+}
+
+static void kvm_piix3_gsi_handler(void *opaque, int n, int level)
+{
+    GSIState *s = opaque;
+
+    if (n < ISA_NUM_IRQS) {
+        /* Kernel will forward to both PIC and IOAPIC */
+        qemu_set_irq(s->i8259_irq[n], level);
+    } else {
+        qemu_set_irq(s->ioapic_irq[n], level);
+    }
+}
+
 static void ioapic_init(GSIState *gsi_state)
 {
     DeviceState *dev;
@@ -134,7 +168,13 @@ static void pc_init1(MemoryRegion *system_memory,
     }
 
     gsi_state = g_malloc0(sizeof(*gsi_state));
-    gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        kvm_piix3_setup_irq_routing(pci_enabled);
+        gsi = qemu_allocate_irqs(kvm_piix3_gsi_handler, gsi_state,
+                                 GSI_NUM_PINS);
+    } else {
+        gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS);
+    }
 
     if (pci_enabled) {
         pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi,
@@ -154,11 +194,13 @@ static void pc_init1(MemoryRegion *system_memory,
     }
     isa_bus_irqs(isa_bus, gsi);
 
-    if (!xen_enabled()) {
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        i8259 = kvm_i8259_init(isa_bus);
+    } else if (xen_enabled()) {
+        i8259 = xen_interrupt_controller_init();
+    } else {
         cpu_irq = pc_allocate_cpu_irq();
         i8259 = i8259_init(isa_bus, cpu_irq[0]);
-    } else {
-        i8259 = xen_interrupt_controller_init();
     }
 
     for (i = 0; i < ISA_NUM_IRQS; i++) {
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 17/18] kvm: x86: Add user space part for in-kernel IOAPIC
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:35   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl

This introduces the KVM-accelerated IOAPIC model 'kvm-ioapic' and
extends the IRQ routing setup by the 0->2 redirection when needed.

The kvm-ioapic model has a property that allows to define its GSI base
for injecting interrupts into the kernel model. This will allow to
disentangle PIC and IOAPIC pins for chipsets that support more
sophisticated IRQ routes than the PIIX3. So far the base is kept at 0,
i.e. PIC and IOAPIC share pins 0..15.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.target |    2 +-
 hw/kvm/ioapic.c |  144 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pc_piix.c    |   15 +++++-
 3 files changed, 159 insertions(+), 2 deletions(-)
 create mode 100644 hw/kvm/ioapic.c

diff --git a/Makefile.target b/Makefile.target
index f49f96e..c82671b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -228,7 +228,7 @@ obj-i386-y += vmport.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c
new file mode 100644
index 0000000..3bd388f
--- /dev/null
+++ b/hw/kvm/ioapic.c
@@ -0,0 +1,144 @@
+/*
+ * KVM in-kernel IOPIC support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "hw/pc.h"
+#include "hw/ioapic_internal.h"
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+typedef struct KVMIOAPICState KVMIOAPICState;
+
+struct KVMIOAPICState {
+    IOAPICCommonState ioapic;
+    uint32_t kvm_gsi_base;
+};
+
+static void kvm_ioapic_get(KVMIOAPICState *s)
+{
+    struct kvm_irqchip chip;
+    struct kvm_ioapic_state *kioapic;
+    int ret, i;
+
+    chip.chip_id = KVM_IRQCHIP_IOAPIC;
+    ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+        abort();
+    }
+
+    kioapic = &chip.chip.ioapic;
+
+    s->ioapic.id = kioapic->id;
+    s->ioapic.ioregsel = kioapic->ioregsel;
+    s->ioapic.irr = kioapic->irr;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        s->ioapic.ioredtbl[i] = kioapic->redirtbl[i].bits;
+    }
+}
+
+static void kvm_ioapic_put(KVMIOAPICState *s)
+{
+    struct kvm_irqchip chip;
+    struct kvm_ioapic_state *kioapic;
+    int ret, i;
+
+    chip.chip_id = KVM_IRQCHIP_IOAPIC;
+    kioapic = &chip.chip.ioapic;
+
+    kioapic->id = s->ioapic.id;
+    kioapic->ioregsel = s->ioapic.ioregsel;
+    kioapic->base_address = s->ioapic.busdev.mmio[0].addr;
+    kioapic->irr = s->ioapic.irr;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        kioapic->redirtbl[i].bits = s->ioapic.ioredtbl[i];
+    }
+
+    ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+        abort();
+    }
+}
+
+static void kvm_ioapic_pre_save(void *opaque)
+{
+    KVMIOAPICState *s = opaque;
+
+    kvm_ioapic_get(s);
+}
+
+static int kvm_ioapic_post_load(void *opaque, int version_id)
+{
+    KVMIOAPICState *s = opaque;
+
+    kvm_ioapic_put(s);
+    return 0;
+}
+
+static void kvm_ioapic_reset(DeviceState *dev)
+{
+    KVMIOAPICState *s = DO_UPCAST(KVMIOAPICState, ioapic.busdev.qdev, dev);
+
+    ioapic_reset_common(&s->ioapic);
+    kvm_ioapic_put(s);
+}
+
+static void kvm_ioapic_set_irq(void *opaque, int irq, int level)
+{
+    KVMIOAPICState *s = opaque;
+    int delivered;
+
+    delivered = kvm_irqchip_set_irq(kvm_state, s->kvm_gsi_base + irq, level);
+    apic_report_irq_delivered(delivered);
+}
+
+static void kvm_ioapic_init(IOAPICCommonState *s, int instance_no)
+{
+    memory_region_init_reservation(&s->io_memory, "kvm-ioapic", 0x1000);
+
+    qdev_init_gpio_in(&s->busdev.qdev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS);
+}
+
+static const VMStateDescription vmstate_kvm_ioapic = {
+    .name = "ioapic",
+    .version_id = IOAPIC_VMSTATE_VERSION,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = kvm_ioapic_pre_save,
+    .post_load = kvm_ioapic_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(ioapic, KVMIOAPICState, 0, vmstate_ioapic_common,
+                       IOAPICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static IOAPICCommonInfo kvm_ioapic_info = {
+    .busdev.init = ioapic_init_common,
+    .busdev.qdev.name = "kvm-ioapic",
+    .busdev.qdev.size = sizeof(KVMIOAPICState),
+    .busdev.qdev.vmsd = &vmstate_kvm_ioapic,
+    .busdev.qdev.reset = kvm_ioapic_reset,
+    .busdev.qdev.no_user = 1,
+    .busdev.qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0),
+        DEFINE_PROP_END_OF_LIST()
+    },
+    .init = kvm_ioapic_init,
+};
+
+static void kvm_ioapic_register_device(void)
+{
+    sysbus_register_withprop(&kvm_ioapic_info.busdev);
+}
+
+device_init(kvm_ioapic_register_device)
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 868f4a5..fcc374f 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -68,6 +68,15 @@ static void kvm_piix3_setup_irq_routing(bool pci_enabled)
         for (i = 8; i < 16; ++i) {
             kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8);
         }
+        if (pci_enabled) {
+            for (i = 0; i < 24; ++i) {
+                if (i == 0) {
+                    kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, 2);
+                } else if (i != 2) {
+                    kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, i);
+                }
+            }
+        }
         ret = kvm_irqchip_commit_routes(s);
         if (ret < 0) {
             hw_error("KVM IRQ routing setup failed");
@@ -93,7 +102,11 @@ static void ioapic_init(GSIState *gsi_state)
     SysBusDevice *d;
     unsigned int i;
 
-    dev = qdev_create(NULL, "ioapic");
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        dev = qdev_create(NULL, "kvm-ioapic");
+    } else {
+        dev = qdev_create(NULL, "ioapic");
+    }
     qdev_init_nofail(dev);
     d = sysbus_from_qdev(dev);
     sysbus_mmio_map(d, 0, 0xfec00000);
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 17/18] kvm: x86: Add user space part for in-kernel IOAPIC
@ 2012-01-13 17:35   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

This introduces the KVM-accelerated IOAPIC model 'kvm-ioapic' and
extends the IRQ routing setup by the 0->2 redirection when needed.

The kvm-ioapic model has a property that allows to define its GSI base
for injecting interrupts into the kernel model. This will allow to
disentangle PIC and IOAPIC pins for chipsets that support more
sophisticated IRQ routes than the PIIX3. So far the base is kept at 0,
i.e. PIC and IOAPIC share pins 0..15.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 Makefile.target |    2 +-
 hw/kvm/ioapic.c |  144 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/pc_piix.c    |   15 +++++-
 3 files changed, 159 insertions(+), 2 deletions(-)
 create mode 100644 hw/kvm/ioapic.c

diff --git a/Makefile.target b/Makefile.target
index f49f96e..c82671b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -228,7 +228,7 @@ obj-i386-y += vmport.o
 obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
 obj-i386-y += debugcon.o multiboot.o
 obj-i386-y += pc_piix.o
-obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o
+obj-i386-$(CONFIG_KVM) += kvm/clock.o kvm/apic.o kvm/i8259.o kvm/ioapic.o
 obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o
 
 # shared objects
diff --git a/hw/kvm/ioapic.c b/hw/kvm/ioapic.c
new file mode 100644
index 0000000..3bd388f
--- /dev/null
+++ b/hw/kvm/ioapic.c
@@ -0,0 +1,144 @@
+/*
+ * KVM in-kernel IOPIC support
+ *
+ * Copyright (c) 2011 Siemens AG
+ *
+ * Authors:
+ *  Jan Kiszka          <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL version 2.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "hw/pc.h"
+#include "hw/ioapic_internal.h"
+#include "hw/apic_internal.h"
+#include "kvm.h"
+
+typedef struct KVMIOAPICState KVMIOAPICState;
+
+struct KVMIOAPICState {
+    IOAPICCommonState ioapic;
+    uint32_t kvm_gsi_base;
+};
+
+static void kvm_ioapic_get(KVMIOAPICState *s)
+{
+    struct kvm_irqchip chip;
+    struct kvm_ioapic_state *kioapic;
+    int ret, i;
+
+    chip.chip_id = KVM_IRQCHIP_IOAPIC;
+    ret = kvm_vm_ioctl(kvm_state, KVM_GET_IRQCHIP, &chip);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+        abort();
+    }
+
+    kioapic = &chip.chip.ioapic;
+
+    s->ioapic.id = kioapic->id;
+    s->ioapic.ioregsel = kioapic->ioregsel;
+    s->ioapic.irr = kioapic->irr;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        s->ioapic.ioredtbl[i] = kioapic->redirtbl[i].bits;
+    }
+}
+
+static void kvm_ioapic_put(KVMIOAPICState *s)
+{
+    struct kvm_irqchip chip;
+    struct kvm_ioapic_state *kioapic;
+    int ret, i;
+
+    chip.chip_id = KVM_IRQCHIP_IOAPIC;
+    kioapic = &chip.chip.ioapic;
+
+    kioapic->id = s->ioapic.id;
+    kioapic->ioregsel = s->ioapic.ioregsel;
+    kioapic->base_address = s->ioapic.busdev.mmio[0].addr;
+    kioapic->irr = s->ioapic.irr;
+    for (i = 0; i < IOAPIC_NUM_PINS; i++) {
+        kioapic->redirtbl[i].bits = s->ioapic.ioredtbl[i];
+    }
+
+    ret = kvm_vm_ioctl(kvm_state, KVM_SET_IRQCHIP, &chip);
+    if (ret < 0) {
+        fprintf(stderr, "KVM_GET_IRQCHIP failed: %s\n", strerror(ret));
+        abort();
+    }
+}
+
+static void kvm_ioapic_pre_save(void *opaque)
+{
+    KVMIOAPICState *s = opaque;
+
+    kvm_ioapic_get(s);
+}
+
+static int kvm_ioapic_post_load(void *opaque, int version_id)
+{
+    KVMIOAPICState *s = opaque;
+
+    kvm_ioapic_put(s);
+    return 0;
+}
+
+static void kvm_ioapic_reset(DeviceState *dev)
+{
+    KVMIOAPICState *s = DO_UPCAST(KVMIOAPICState, ioapic.busdev.qdev, dev);
+
+    ioapic_reset_common(&s->ioapic);
+    kvm_ioapic_put(s);
+}
+
+static void kvm_ioapic_set_irq(void *opaque, int irq, int level)
+{
+    KVMIOAPICState *s = opaque;
+    int delivered;
+
+    delivered = kvm_irqchip_set_irq(kvm_state, s->kvm_gsi_base + irq, level);
+    apic_report_irq_delivered(delivered);
+}
+
+static void kvm_ioapic_init(IOAPICCommonState *s, int instance_no)
+{
+    memory_region_init_reservation(&s->io_memory, "kvm-ioapic", 0x1000);
+
+    qdev_init_gpio_in(&s->busdev.qdev, kvm_ioapic_set_irq, IOAPIC_NUM_PINS);
+}
+
+static const VMStateDescription vmstate_kvm_ioapic = {
+    .name = "ioapic",
+    .version_id = IOAPIC_VMSTATE_VERSION,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .pre_save = kvm_ioapic_pre_save,
+    .post_load = kvm_ioapic_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(ioapic, KVMIOAPICState, 0, vmstate_ioapic_common,
+                       IOAPICCommonState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static IOAPICCommonInfo kvm_ioapic_info = {
+    .busdev.init = ioapic_init_common,
+    .busdev.qdev.name = "kvm-ioapic",
+    .busdev.qdev.size = sizeof(KVMIOAPICState),
+    .busdev.qdev.vmsd = &vmstate_kvm_ioapic,
+    .busdev.qdev.reset = kvm_ioapic_reset,
+    .busdev.qdev.no_user = 1,
+    .busdev.qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("gsi_base", KVMIOAPICState, kvm_gsi_base, 0),
+        DEFINE_PROP_END_OF_LIST()
+    },
+    .init = kvm_ioapic_init,
+};
+
+static void kvm_ioapic_register_device(void)
+{
+    sysbus_register_withprop(&kvm_ioapic_info.busdev);
+}
+
+device_init(kvm_ioapic_register_device)
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 868f4a5..fcc374f 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -68,6 +68,15 @@ static void kvm_piix3_setup_irq_routing(bool pci_enabled)
         for (i = 8; i < 16; ++i) {
             kvm_irqchip_add_route(s, i, KVM_IRQCHIP_PIC_SLAVE, i - 8);
         }
+        if (pci_enabled) {
+            for (i = 0; i < 24; ++i) {
+                if (i == 0) {
+                    kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, 2);
+                } else if (i != 2) {
+                    kvm_irqchip_add_route(s, i, KVM_IRQCHIP_IOAPIC, i);
+                }
+            }
+        }
         ret = kvm_irqchip_commit_routes(s);
         if (ret < 0) {
             hw_error("KVM IRQ routing setup failed");
@@ -93,7 +102,11 @@ static void ioapic_init(GSIState *gsi_state)
     SysBusDevice *d;
     unsigned int i;
 
-    dev = qdev_create(NULL, "ioapic");
+    if (kvm_enabled() && kvm_irqchip_in_kernel()) {
+        dev = qdev_create(NULL, "kvm-ioapic");
+    } else {
+        dev = qdev_create(NULL, "ioapic");
+    }
     qdev_init_nofail(dev);
     d = sysbus_from_qdev(dev);
     sysbus_mmio_map(d, 0, 0xfec00000);
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 18/18] kvm: Arm in-kernel irqchip support
  2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 17:35   ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: kvm, qemu-devel, Anthony Liguori, Michael S. Tsirkin, Blue Swirl

Make the basic in-kernel irqchip support selectable via
-machine ...,kernel_irqchip=on. Leave it off by default until it can
fully replace user space models.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 qemu-config.c   |    4 ++++
 qemu-options.hx |    5 ++++-
 2 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/qemu-config.c b/qemu-config.c
index 18f3020..bd93d6f 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -518,6 +518,10 @@ static QemuOptsList qemu_machine_opts = {
             .name = "accel",
             .type = QEMU_OPT_STRING,
             .help = "accelerator list",
+        }, {
+            .name = "kernel_irqchip",
+            .type = QEMU_OPT_BOOL,
+            .help = "use KVM in-kernel irqchip",
         },
         { /* End of list */ }
     },
diff --git a/qemu-options.hx b/qemu-options.hx
index a60191f..f293a50 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -31,7 +31,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
     "-machine [type=]name[,prop[=value][,...]]\n"
     "                selects emulated machine (-machine ? for list)\n"
     "                property accel=accel1[:accel2[:...]] selects accelerator\n"
-    "                supported accelerators are kvm, xen, tcg (default: tcg)\n",
+    "                supported accelerators are kvm, xen, tcg (default: tcg)\n"
+    "                kernel_irqchip=on|off controls accelerated irqchip support\n",
     QEMU_ARCH_ALL)
 STEXI
 @item -machine [type=]@var{name}[,prop=@var{value}[,...]]
@@ -44,6 +45,8 @@ This is used to enable an accelerator. Depending on the target architecture,
 kvm, xen, or tcg can be available. By default, tcg is used. If there is more
 than one accelerator specified, the next one is used if the previous one fails
 to initialize.
+@item kernel_irqchip=on|off
+Enables in-kernel irqchip support for the chosen accelerator when available.
 @end table
 ETEXI
 
-- 
1.7.3.4


^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [Qemu-devel] [PATCH v6 18/18] kvm: Arm in-kernel irqchip support
@ 2012-01-13 17:35   ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 17:35 UTC (permalink / raw)
  To: Avi Kivity, Marcelo Tosatti
  Cc: Blue Swirl, Anthony Liguori, qemu-devel, kvm, Michael S. Tsirkin

Make the basic in-kernel irqchip support selectable via
-machine ...,kernel_irqchip=on. Leave it off by default until it can
fully replace user space models.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 qemu-config.c   |    4 ++++
 qemu-options.hx |    5 ++++-
 2 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/qemu-config.c b/qemu-config.c
index 18f3020..bd93d6f 100644
--- a/qemu-config.c
+++ b/qemu-config.c
@@ -518,6 +518,10 @@ static QemuOptsList qemu_machine_opts = {
             .name = "accel",
             .type = QEMU_OPT_STRING,
             .help = "accelerator list",
+        }, {
+            .name = "kernel_irqchip",
+            .type = QEMU_OPT_BOOL,
+            .help = "use KVM in-kernel irqchip",
         },
         { /* End of list */ }
     },
diff --git a/qemu-options.hx b/qemu-options.hx
index a60191f..f293a50 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -31,7 +31,8 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
     "-machine [type=]name[,prop[=value][,...]]\n"
     "                selects emulated machine (-machine ? for list)\n"
     "                property accel=accel1[:accel2[:...]] selects accelerator\n"
-    "                supported accelerators are kvm, xen, tcg (default: tcg)\n",
+    "                supported accelerators are kvm, xen, tcg (default: tcg)\n"
+    "                kernel_irqchip=on|off controls accelerated irqchip support\n",
     QEMU_ARCH_ALL)
 STEXI
 @item -machine [type=]@var{name}[,prop=@var{value}[,...]]
@@ -44,6 +45,8 @@ This is used to enable an accelerator. Depending on the target architecture,
 kvm, xen, or tcg can be available. By default, tcg is used. If there is more
 than one accelerator specified, the next one is used if the previous one fails
 to initialize.
+@item kernel_irqchip=on|off
+Enables in-kernel irqchip support for the chosen accelerator when available.
 @end table
 ETEXI
 
-- 
1.7.3.4

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: [PATCH v6 18/18] kvm: Arm in-kernel irqchip support
  2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 18:49     ` Peter Maydell
  -1 siblings, 0 replies; 49+ messages in thread
From: Peter Maydell @ 2012-01-13 18:49 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: Anthony Liguori, kvm, Michael S. Tsirkin, Marcelo Tosatti,
	qemu-devel, Blue Swirl, Avi Kivity

On 13 January 2012 17:35, Jan Kiszka <jan.kiszka@siemens.com> wrote:
> Subject: kvm: Arm in-kernel irqchip support

I have to say I found this Subject rather confusing :-)

-- PMM

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [Qemu-devel] [PATCH v6 18/18] kvm: Arm in-kernel irqchip support
@ 2012-01-13 18:49     ` Peter Maydell
  0 siblings, 0 replies; 49+ messages in thread
From: Peter Maydell @ 2012-01-13 18:49 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: Anthony Liguori, kvm, Michael S. Tsirkin, Marcelo Tosatti,
	qemu-devel, Blue Swirl, Avi Kivity

On 13 January 2012 17:35, Jan Kiszka <jan.kiszka@siemens.com> wrote:
> Subject: kvm: Arm in-kernel irqchip support

I have to say I found this Subject rather confusing :-)

-- PMM

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v6 18/18] kvm: Arm in-kernel irqchip support
  2012-01-13 18:49     ` [Qemu-devel] " Peter Maydell
@ 2012-01-13 19:04       ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 19:04 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Anthony Liguori, kvm, Michael S. Tsirkin, Marcelo Tosatti,
	qemu-devel, Blue Swirl, Avi Kivity

On 2012-01-13 19:49, Peter Maydell wrote:
> On 13 January 2012 17:35, Jan Kiszka <jan.kiszka@siemens.com> wrote:
>> Subject: kvm: Arm in-kernel irqchip support
> 
> I have to say I found this Subject rather confusing :-)

Deeply sorry, but I guess that verb predates the architecture by a few
years. ;)

Jan

-- 
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [Qemu-devel] [PATCH v6 18/18] kvm: Arm in-kernel irqchip support
@ 2012-01-13 19:04       ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 19:04 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Anthony Liguori, kvm, Michael S. Tsirkin, Marcelo Tosatti,
	qemu-devel, Blue Swirl, Avi Kivity

On 2012-01-13 19:49, Peter Maydell wrote:
> On 13 January 2012 17:35, Jan Kiszka <jan.kiszka@siemens.com> wrote:
>> Subject: kvm: Arm in-kernel irqchip support
> 
> I have to say I found this Subject rather confusing :-)

Deeply sorry, but I guess that verb predates the architecture by a few
years. ;)

Jan

-- 
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [Qemu-devel] [PATCH v6 18/18] kvm: Arm in-kernel irqchip support
  2012-01-13 19:04       ` [Qemu-devel] " Jan Kiszka
  (?)
@ 2012-01-13 19:36       ` Andreas Färber
  -1 siblings, 0 replies; 49+ messages in thread
From: Andreas Färber @ 2012-01-13 19:36 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: Peter Maydell, Anthony Liguori, kvm, Michael S. Tsirkin,
	Marcelo Tosatti, qemu-devel, Blue Swirl, Avi Kivity

Am 13.01.2012 20:04, schrieb Jan Kiszka:
> On 2012-01-13 19:49, Peter Maydell wrote:
>> On 13 January 2012 17:35, Jan Kiszka <jan.kiszka@siemens.com> wrote:
>>> Subject: kvm: Arm in-kernel irqchip support
>>
>> I have to say I found this Subject rather confusing :-)
> 
> Deeply sorry, but I guess that verb predates the architecture by a few
> years. ;)

"kvm: Add kernel_irqchip command line option" as a pacifist version?

Andreas

-- 
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v6 06/18] apic: Factor out base class for KVM reuse
  2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 21:18     ` Anthony Liguori
  -1 siblings, 0 replies; 49+ messages in thread
From: Anthony Liguori @ 2012-01-13 21:18 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: Avi Kivity, Marcelo Tosatti, kvm, qemu-devel, Michael S. Tsirkin,
	Blue Swirl

On 01/13/2012 11:35 AM, Jan Kiszka wrote:
> The KVM in-kernel APIC model will reuse parts of the user space model
> while providing the same frontend view to guest and most management
> interfaces.
>
> Factor out an APIC base class to encapsulate those parts that will be
> shared by user space and KVM model. This class offers callback hooks for
> init, base/tpr setting, and the external NMI delivery that will be
> set via APICCommonInfo super-structure and implemented specifically in
> the subclasses.
>
> Furthermore, a common vmstate and a common list of qdev properties is
> provided with the base clase. Also the reset handler will be shared.
>
> diff --git a/hw/apic_internal.h b/hw/apic_internal.h
> new file mode 100644
> index 0000000..2ca18d4
> --- /dev/null
> +++ b/hw/apic_internal.h
> @@ -0,0 +1,121 @@
> +/*
> + *  APIC support - internal interfaces
> + *
> + *  Copyright (c) 2004-2005 Fabrice Bellard
> + *  Copyright (c) 2011      Jan Kiszka, Siemens AG
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see<http://www.gnu.org/licenses/>
> + */
> +#ifndef QEMU_APIC_INTERNAL_H
> +#define QEMU_APIC_INTERNAL_H
> +
> +#include "memory.h"
> +#include "sysbus.h"
> +#include "qemu-timer.h"
> +
> +/* APIC Local Vector Table */
> +#define APIC_LVT_TIMER                  0
> +#define APIC_LVT_THERMAL                1
> +#define APIC_LVT_PERFORM                2
> +#define APIC_LVT_LINT0                  3
> +#define APIC_LVT_LINT1                  4
> +#define APIC_LVT_ERROR                  5
> +#define APIC_LVT_NB                     6
> +
> +/* APIC delivery modes */
> +#define APIC_DM_FIXED                   0
> +#define APIC_DM_LOWPRI                  1
> +#define APIC_DM_SMI                     2
> +#define APIC_DM_NMI                     4
> +#define APIC_DM_INIT                    5
> +#define APIC_DM_SIPI                    6
> +#define APIC_DM_EXTINT                  7
> +
> +/* APIC destination mode */
> +#define APIC_DESTMODE_FLAT              0xf
> +#define APIC_DESTMODE_CLUSTER           1
> +
> +#define APIC_TRIGGER_EDGE               0
> +#define APIC_TRIGGER_LEVEL              1
> +
> +#define APIC_LVT_TIMER_PERIODIC         (1<<17)
> +#define APIC_LVT_MASKED                 (1<<16)
> +#define APIC_LVT_LEVEL_TRIGGER          (1<<15)
> +#define APIC_LVT_REMOTE_IRR             (1<<14)
> +#define APIC_INPUT_POLARITY             (1<<13)
> +#define APIC_SEND_PENDING               (1<<12)
> +
> +#define ESR_ILLEGAL_ADDRESS (1<<  7)
> +
> +#define APIC_SV_DIRECTED_IO             (1<<12)
> +#define APIC_SV_ENABLE                  (1<<8)
> +
> +#define MAX_APICS 255
> +
> +#define MSI_SPACE_SIZE                  0x100000
> +
> +typedef struct APICCommonState APICCommonState;
> +
> +struct APICCommonState {
> +    SysBusDevice busdev;
> +    MemoryRegion io_memory;
> +    void *cpu_env;
> +    uint32_t apicbase;
> +    uint8_t id;
> +    uint8_t arb_id;
> +    uint8_t tpr;
> +    uint32_t spurious_vec;
> +    uint8_t log_dest;
> +    uint8_t dest_mode;
> +    uint32_t isr[8];  /* in service register */
> +    uint32_t tmr[8];  /* trigger mode register */
> +    uint32_t irr[8]; /* interrupt request register */
> +    uint32_t lvt[APIC_LVT_NB];
> +    uint32_t esr; /* error register */
> +    uint32_t icr[2];
> +
> +    uint32_t divide_conf;
> +    int count_shift;
> +    uint32_t initial_count;
> +    int64_t initial_count_load_time;
> +    int64_t next_time;
> +    int idx;
> +    QEMUTimer *timer;
> +    int sipi_vector;
> +    int wait_for_sipi;
> +};
> +
> +typedef struct APICCommonInfo APICCommonInfo;
> +
> +struct APICCommonInfo {
> +    SysBusDeviceInfo busdev;
> +    void (*init)(APICCommonState *s);
> +    void (*set_base)(APICCommonState *s, uint64_t val);
> +    void (*set_tpr)(APICCommonState *s, uint8_t val);
> +    void (*external_nmi)(APICCommonState *s);
> +};
> +
> +#define APIC_VMSTATE_VERSION 3
> +
> +extern const VMStateDescription vmstate_apic_common;
> +
> +#define APIC_PROPERTIES_COMMON(cont_type, cont_var)         \
> +    DEFINE_PROP_UINT8("id", cont_type, cont_var.id, -1),    \
> +    DEFINE_PROP_PTR("cpu_env", cont_type, cont_var.cpu_env)
> +
> +void apic_report_irq_delivered(int delivered);
> +void apic_reset_common(DeviceState *d);
> +int apic_init_common(SysBusDevice *d);

I think you want to introduce an apic_qdev_register(APICCommonInfo *).  Then you 
can set info->qdev.vmsd = &vmstate_apic_common and avoid having to make it extern.

Regards,

Anthony Liguori

> +
> +#endif /* !QEMU_APIC_INTERNAL_H */


^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [Qemu-devel] [PATCH v6 06/18] apic: Factor out base class for KVM reuse
@ 2012-01-13 21:18     ` Anthony Liguori
  0 siblings, 0 replies; 49+ messages in thread
From: Anthony Liguori @ 2012-01-13 21:18 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: kvm, Michael S. Tsirkin, Marcelo Tosatti, qemu-devel, Blue Swirl,
	Avi Kivity

On 01/13/2012 11:35 AM, Jan Kiszka wrote:
> The KVM in-kernel APIC model will reuse parts of the user space model
> while providing the same frontend view to guest and most management
> interfaces.
>
> Factor out an APIC base class to encapsulate those parts that will be
> shared by user space and KVM model. This class offers callback hooks for
> init, base/tpr setting, and the external NMI delivery that will be
> set via APICCommonInfo super-structure and implemented specifically in
> the subclasses.
>
> Furthermore, a common vmstate and a common list of qdev properties is
> provided with the base clase. Also the reset handler will be shared.
>
> diff --git a/hw/apic_internal.h b/hw/apic_internal.h
> new file mode 100644
> index 0000000..2ca18d4
> --- /dev/null
> +++ b/hw/apic_internal.h
> @@ -0,0 +1,121 @@
> +/*
> + *  APIC support - internal interfaces
> + *
> + *  Copyright (c) 2004-2005 Fabrice Bellard
> + *  Copyright (c) 2011      Jan Kiszka, Siemens AG
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see<http://www.gnu.org/licenses/>
> + */
> +#ifndef QEMU_APIC_INTERNAL_H
> +#define QEMU_APIC_INTERNAL_H
> +
> +#include "memory.h"
> +#include "sysbus.h"
> +#include "qemu-timer.h"
> +
> +/* APIC Local Vector Table */
> +#define APIC_LVT_TIMER                  0
> +#define APIC_LVT_THERMAL                1
> +#define APIC_LVT_PERFORM                2
> +#define APIC_LVT_LINT0                  3
> +#define APIC_LVT_LINT1                  4
> +#define APIC_LVT_ERROR                  5
> +#define APIC_LVT_NB                     6
> +
> +/* APIC delivery modes */
> +#define APIC_DM_FIXED                   0
> +#define APIC_DM_LOWPRI                  1
> +#define APIC_DM_SMI                     2
> +#define APIC_DM_NMI                     4
> +#define APIC_DM_INIT                    5
> +#define APIC_DM_SIPI                    6
> +#define APIC_DM_EXTINT                  7
> +
> +/* APIC destination mode */
> +#define APIC_DESTMODE_FLAT              0xf
> +#define APIC_DESTMODE_CLUSTER           1
> +
> +#define APIC_TRIGGER_EDGE               0
> +#define APIC_TRIGGER_LEVEL              1
> +
> +#define APIC_LVT_TIMER_PERIODIC         (1<<17)
> +#define APIC_LVT_MASKED                 (1<<16)
> +#define APIC_LVT_LEVEL_TRIGGER          (1<<15)
> +#define APIC_LVT_REMOTE_IRR             (1<<14)
> +#define APIC_INPUT_POLARITY             (1<<13)
> +#define APIC_SEND_PENDING               (1<<12)
> +
> +#define ESR_ILLEGAL_ADDRESS (1<<  7)
> +
> +#define APIC_SV_DIRECTED_IO             (1<<12)
> +#define APIC_SV_ENABLE                  (1<<8)
> +
> +#define MAX_APICS 255
> +
> +#define MSI_SPACE_SIZE                  0x100000
> +
> +typedef struct APICCommonState APICCommonState;
> +
> +struct APICCommonState {
> +    SysBusDevice busdev;
> +    MemoryRegion io_memory;
> +    void *cpu_env;
> +    uint32_t apicbase;
> +    uint8_t id;
> +    uint8_t arb_id;
> +    uint8_t tpr;
> +    uint32_t spurious_vec;
> +    uint8_t log_dest;
> +    uint8_t dest_mode;
> +    uint32_t isr[8];  /* in service register */
> +    uint32_t tmr[8];  /* trigger mode register */
> +    uint32_t irr[8]; /* interrupt request register */
> +    uint32_t lvt[APIC_LVT_NB];
> +    uint32_t esr; /* error register */
> +    uint32_t icr[2];
> +
> +    uint32_t divide_conf;
> +    int count_shift;
> +    uint32_t initial_count;
> +    int64_t initial_count_load_time;
> +    int64_t next_time;
> +    int idx;
> +    QEMUTimer *timer;
> +    int sipi_vector;
> +    int wait_for_sipi;
> +};
> +
> +typedef struct APICCommonInfo APICCommonInfo;
> +
> +struct APICCommonInfo {
> +    SysBusDeviceInfo busdev;
> +    void (*init)(APICCommonState *s);
> +    void (*set_base)(APICCommonState *s, uint64_t val);
> +    void (*set_tpr)(APICCommonState *s, uint8_t val);
> +    void (*external_nmi)(APICCommonState *s);
> +};
> +
> +#define APIC_VMSTATE_VERSION 3
> +
> +extern const VMStateDescription vmstate_apic_common;
> +
> +#define APIC_PROPERTIES_COMMON(cont_type, cont_var)         \
> +    DEFINE_PROP_UINT8("id", cont_type, cont_var.id, -1),    \
> +    DEFINE_PROP_PTR("cpu_env", cont_type, cont_var.cpu_env)
> +
> +void apic_report_irq_delivered(int delivered);
> +void apic_reset_common(DeviceState *d);
> +int apic_init_common(SysBusDevice *d);

I think you want to introduce an apic_qdev_register(APICCommonInfo *).  Then you 
can set info->qdev.vmsd = &vmstate_apic_common and avoid having to make it extern.

Regards,

Anthony Liguori

> +
> +#endif /* !QEMU_APIC_INTERNAL_H */

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v6 09/18] i8259: Factor out base class for KVM reuse
  2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
@ 2012-01-13 21:19     ` Anthony Liguori
  -1 siblings, 0 replies; 49+ messages in thread
From: Anthony Liguori @ 2012-01-13 21:19 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: kvm, Michael S. Tsirkin, Marcelo Tosatti, qemu-devel, Blue Swirl,
	Avi Kivity

On 01/13/2012 11:35 AM, Jan Kiszka wrote:
> Analogously to the APIC, we will reuse some parts of the user space
> i8259 model for KVM. In this case it is a common device state, a common
> vmstate, the property list, a reset core and some init bits.
>
> This also introduces a common helper to instantiate a single i8259 chip
> from the cascade-creating i8259_init function.
>
> Signed-off-by: Jan Kiszka<jan.kiszka@siemens.com>
> ---
> diff --git a/hw/i8259_internal.h b/hw/i8259_internal.h
> new file mode 100644
> index 0000000..aedd55f
> --- /dev/null
> +++ b/hw/i8259_internal.h
> @@ -0,0 +1,76 @@
> +/*
> + * QEMU 8259 - internal interfaces
> + *
> + * Copyright (c) 2011 Jan Kiszka, Siemens AG
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#ifndef QEMU_I8259_INTERNAL_H
> +#define QEMU_I8259_INTERNAL_H
> +
> +#include "hw.h"
> +#include "pc.h"
> +#include "isa.h"
> +
> +typedef struct PICCommonState PICCommonState;
> +
> +struct PICCommonState {
> +    ISADevice dev;
> +    uint8_t last_irr; /* edge detection */
> +    uint8_t irr; /* interrupt request register */
> +    uint8_t imr; /* interrupt mask register */
> +    uint8_t isr; /* interrupt service register */
> +    uint8_t priority_add; /* highest irq priority */
> +    uint8_t irq_base;
> +    uint8_t read_reg_select;
> +    uint8_t poll;
> +    uint8_t special_mask;
> +    uint8_t init_state;
> +    uint8_t auto_eoi;
> +    uint8_t rotate_on_auto_eoi;
> +    uint8_t special_fully_nested_mode;
> +    uint8_t init4; /* true if 4 byte init */
> +    uint8_t single_mode; /* true if slave pic is not initialized */
> +    uint8_t elcr; /* PIIX edge/trigger selection*/
> +    uint8_t elcr_mask;
> +    qemu_irq int_out[1];
> +    uint32_t master; /* reflects /SP input pin */
> +    uint32_t iobase;
> +    uint32_t elcr_addr;
> +    MemoryRegion base_io;
> +    MemoryRegion elcr_io;
> +};
> +
> +#define PIC_VMSTATE_VERSION 1
> +
> +extern const VMStateDescription vmstate_pic_common;
> +
> +#define PIC_PROPERTIES_COMMON(cont_type, cont_var)                      \
> +    DEFINE_PROP_HEX32("iobase", cont_type, cont_var.iobase,  -1),       \
> +    DEFINE_PROP_HEX32("elcr_addr", cont_type, cont_var.elcr_addr,  -1), \
> +    DEFINE_PROP_HEX8("elcr_mask", cont_type, cont_var.elcr_mask,  -1),  \
> +    DEFINE_PROP_BIT("master", cont_type, cont_var.master,  0, false)
> +
> +void pic_init_common(PICCommonState *s);
> +void pic_reset_common(PICCommonState *s);
> +
> +ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master);

Same feedback here re: i8259_qdev_register().

Regards,

Anthony Liguori

> +#endif /* !QEMU_I8259_INTERNAL_H */

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [Qemu-devel] [PATCH v6 09/18] i8259: Factor out base class for KVM reuse
@ 2012-01-13 21:19     ` Anthony Liguori
  0 siblings, 0 replies; 49+ messages in thread
From: Anthony Liguori @ 2012-01-13 21:19 UTC (permalink / raw)
  To: Jan Kiszka
  Cc: kvm, Michael S. Tsirkin, Marcelo Tosatti, qemu-devel, Blue Swirl,
	Avi Kivity

On 01/13/2012 11:35 AM, Jan Kiszka wrote:
> Analogously to the APIC, we will reuse some parts of the user space
> i8259 model for KVM. In this case it is a common device state, a common
> vmstate, the property list, a reset core and some init bits.
>
> This also introduces a common helper to instantiate a single i8259 chip
> from the cascade-creating i8259_init function.
>
> Signed-off-by: Jan Kiszka<jan.kiszka@siemens.com>
> ---
> diff --git a/hw/i8259_internal.h b/hw/i8259_internal.h
> new file mode 100644
> index 0000000..aedd55f
> --- /dev/null
> +++ b/hw/i8259_internal.h
> @@ -0,0 +1,76 @@
> +/*
> + * QEMU 8259 - internal interfaces
> + *
> + * Copyright (c) 2011 Jan Kiszka, Siemens AG
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#ifndef QEMU_I8259_INTERNAL_H
> +#define QEMU_I8259_INTERNAL_H
> +
> +#include "hw.h"
> +#include "pc.h"
> +#include "isa.h"
> +
> +typedef struct PICCommonState PICCommonState;
> +
> +struct PICCommonState {
> +    ISADevice dev;
> +    uint8_t last_irr; /* edge detection */
> +    uint8_t irr; /* interrupt request register */
> +    uint8_t imr; /* interrupt mask register */
> +    uint8_t isr; /* interrupt service register */
> +    uint8_t priority_add; /* highest irq priority */
> +    uint8_t irq_base;
> +    uint8_t read_reg_select;
> +    uint8_t poll;
> +    uint8_t special_mask;
> +    uint8_t init_state;
> +    uint8_t auto_eoi;
> +    uint8_t rotate_on_auto_eoi;
> +    uint8_t special_fully_nested_mode;
> +    uint8_t init4; /* true if 4 byte init */
> +    uint8_t single_mode; /* true if slave pic is not initialized */
> +    uint8_t elcr; /* PIIX edge/trigger selection*/
> +    uint8_t elcr_mask;
> +    qemu_irq int_out[1];
> +    uint32_t master; /* reflects /SP input pin */
> +    uint32_t iobase;
> +    uint32_t elcr_addr;
> +    MemoryRegion base_io;
> +    MemoryRegion elcr_io;
> +};
> +
> +#define PIC_VMSTATE_VERSION 1
> +
> +extern const VMStateDescription vmstate_pic_common;
> +
> +#define PIC_PROPERTIES_COMMON(cont_type, cont_var)                      \
> +    DEFINE_PROP_HEX32("iobase", cont_type, cont_var.iobase,  -1),       \
> +    DEFINE_PROP_HEX32("elcr_addr", cont_type, cont_var.elcr_addr,  -1), \
> +    DEFINE_PROP_HEX8("elcr_mask", cont_type, cont_var.elcr_mask,  -1),  \
> +    DEFINE_PROP_BIT("master", cont_type, cont_var.master,  0, false)
> +
> +void pic_init_common(PICCommonState *s);
> +void pic_reset_common(PICCommonState *s);
> +
> +ISADevice *i8259_init_chip(const char *name, ISABus *bus, bool master);

Same feedback here re: i8259_qdev_register().

Regards,

Anthony Liguori

> +#endif /* !QEMU_I8259_INTERNAL_H */

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v6 06/18] apic: Factor out base class for KVM reuse
  2012-01-13 21:18     ` [Qemu-devel] " Anthony Liguori
@ 2012-01-13 22:19       ` Jan Kiszka
  -1 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 22:19 UTC (permalink / raw)
  To: Anthony Liguori
  Cc: Avi Kivity, Marcelo Tosatti, kvm, qemu-devel, Michael S. Tsirkin,
	Blue Swirl

[-- Attachment #1: Type: text/plain, Size: 5470 bytes --]

On 2012-01-13 22:18, Anthony Liguori wrote:
> On 01/13/2012 11:35 AM, Jan Kiszka wrote:
>> The KVM in-kernel APIC model will reuse parts of the user space model
>> while providing the same frontend view to guest and most management
>> interfaces.
>>
>> Factor out an APIC base class to encapsulate those parts that will be
>> shared by user space and KVM model. This class offers callback hooks for
>> init, base/tpr setting, and the external NMI delivery that will be
>> set via APICCommonInfo super-structure and implemented specifically in
>> the subclasses.
>>
>> Furthermore, a common vmstate and a common list of qdev properties is
>> provided with the base clase. Also the reset handler will be shared.
>>
>> diff --git a/hw/apic_internal.h b/hw/apic_internal.h
>> new file mode 100644
>> index 0000000..2ca18d4
>> --- /dev/null
>> +++ b/hw/apic_internal.h
>> @@ -0,0 +1,121 @@
>> +/*
>> + *  APIC support - internal interfaces
>> + *
>> + *  Copyright (c) 2004-2005 Fabrice Bellard
>> + *  Copyright (c) 2011      Jan Kiszka, Siemens AG
>> + *
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2 of the License, or (at your option) any later version.
>> + *
>> + * This library is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not,
>> see<http://www.gnu.org/licenses/>
>> + */
>> +#ifndef QEMU_APIC_INTERNAL_H
>> +#define QEMU_APIC_INTERNAL_H
>> +
>> +#include "memory.h"
>> +#include "sysbus.h"
>> +#include "qemu-timer.h"
>> +
>> +/* APIC Local Vector Table */
>> +#define APIC_LVT_TIMER                  0
>> +#define APIC_LVT_THERMAL                1
>> +#define APIC_LVT_PERFORM                2
>> +#define APIC_LVT_LINT0                  3
>> +#define APIC_LVT_LINT1                  4
>> +#define APIC_LVT_ERROR                  5
>> +#define APIC_LVT_NB                     6
>> +
>> +/* APIC delivery modes */
>> +#define APIC_DM_FIXED                   0
>> +#define APIC_DM_LOWPRI                  1
>> +#define APIC_DM_SMI                     2
>> +#define APIC_DM_NMI                     4
>> +#define APIC_DM_INIT                    5
>> +#define APIC_DM_SIPI                    6
>> +#define APIC_DM_EXTINT                  7
>> +
>> +/* APIC destination mode */
>> +#define APIC_DESTMODE_FLAT              0xf
>> +#define APIC_DESTMODE_CLUSTER           1
>> +
>> +#define APIC_TRIGGER_EDGE               0
>> +#define APIC_TRIGGER_LEVEL              1
>> +
>> +#define APIC_LVT_TIMER_PERIODIC         (1<<17)
>> +#define APIC_LVT_MASKED                 (1<<16)
>> +#define APIC_LVT_LEVEL_TRIGGER          (1<<15)
>> +#define APIC_LVT_REMOTE_IRR             (1<<14)
>> +#define APIC_INPUT_POLARITY             (1<<13)
>> +#define APIC_SEND_PENDING               (1<<12)
>> +
>> +#define ESR_ILLEGAL_ADDRESS (1<<  7)
>> +
>> +#define APIC_SV_DIRECTED_IO             (1<<12)
>> +#define APIC_SV_ENABLE                  (1<<8)
>> +
>> +#define MAX_APICS 255
>> +
>> +#define MSI_SPACE_SIZE                  0x100000
>> +
>> +typedef struct APICCommonState APICCommonState;
>> +
>> +struct APICCommonState {
>> +    SysBusDevice busdev;
>> +    MemoryRegion io_memory;
>> +    void *cpu_env;
>> +    uint32_t apicbase;
>> +    uint8_t id;
>> +    uint8_t arb_id;
>> +    uint8_t tpr;
>> +    uint32_t spurious_vec;
>> +    uint8_t log_dest;
>> +    uint8_t dest_mode;
>> +    uint32_t isr[8];  /* in service register */
>> +    uint32_t tmr[8];  /* trigger mode register */
>> +    uint32_t irr[8]; /* interrupt request register */
>> +    uint32_t lvt[APIC_LVT_NB];
>> +    uint32_t esr; /* error register */
>> +    uint32_t icr[2];
>> +
>> +    uint32_t divide_conf;
>> +    int count_shift;
>> +    uint32_t initial_count;
>> +    int64_t initial_count_load_time;
>> +    int64_t next_time;
>> +    int idx;
>> +    QEMUTimer *timer;
>> +    int sipi_vector;
>> +    int wait_for_sipi;
>> +};
>> +
>> +typedef struct APICCommonInfo APICCommonInfo;
>> +
>> +struct APICCommonInfo {
>> +    SysBusDeviceInfo busdev;
>> +    void (*init)(APICCommonState *s);
>> +    void (*set_base)(APICCommonState *s, uint64_t val);
>> +    void (*set_tpr)(APICCommonState *s, uint8_t val);
>> +    void (*external_nmi)(APICCommonState *s);
>> +};
>> +
>> +#define APIC_VMSTATE_VERSION 3
>> +
>> +extern const VMStateDescription vmstate_apic_common;
>> +
>> +#define APIC_PROPERTIES_COMMON(cont_type, cont_var)         \
>> +    DEFINE_PROP_UINT8("id", cont_type, cont_var.id, -1),    \
>> +    DEFINE_PROP_PTR("cpu_env", cont_type, cont_var.cpu_env)
>> +
>> +void apic_report_irq_delivered(int delivered);
>> +void apic_reset_common(DeviceState *d);
>> +int apic_init_common(SysBusDevice *d);
> 
> I think you want to introduce an apic_qdev_register(APICCommonInfo *). 
> Then you can set info->qdev.vmsd = &vmstate_apic_common and avoid having
> to make it extern.

Yep. Will also help with other common settings.

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [Qemu-devel] [PATCH v6 06/18] apic: Factor out base class for KVM reuse
@ 2012-01-13 22:19       ` Jan Kiszka
  0 siblings, 0 replies; 49+ messages in thread
From: Jan Kiszka @ 2012-01-13 22:19 UTC (permalink / raw)
  To: Anthony Liguori
  Cc: kvm, Michael S. Tsirkin, Marcelo Tosatti, qemu-devel, Blue Swirl,
	Avi Kivity

[-- Attachment #1: Type: text/plain, Size: 5470 bytes --]

On 2012-01-13 22:18, Anthony Liguori wrote:
> On 01/13/2012 11:35 AM, Jan Kiszka wrote:
>> The KVM in-kernel APIC model will reuse parts of the user space model
>> while providing the same frontend view to guest and most management
>> interfaces.
>>
>> Factor out an APIC base class to encapsulate those parts that will be
>> shared by user space and KVM model. This class offers callback hooks for
>> init, base/tpr setting, and the external NMI delivery that will be
>> set via APICCommonInfo super-structure and implemented specifically in
>> the subclasses.
>>
>> Furthermore, a common vmstate and a common list of qdev properties is
>> provided with the base clase. Also the reset handler will be shared.
>>
>> diff --git a/hw/apic_internal.h b/hw/apic_internal.h
>> new file mode 100644
>> index 0000000..2ca18d4
>> --- /dev/null
>> +++ b/hw/apic_internal.h
>> @@ -0,0 +1,121 @@
>> +/*
>> + *  APIC support - internal interfaces
>> + *
>> + *  Copyright (c) 2004-2005 Fabrice Bellard
>> + *  Copyright (c) 2011      Jan Kiszka, Siemens AG
>> + *
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2 of the License, or (at your option) any later version.
>> + *
>> + * This library is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not,
>> see<http://www.gnu.org/licenses/>
>> + */
>> +#ifndef QEMU_APIC_INTERNAL_H
>> +#define QEMU_APIC_INTERNAL_H
>> +
>> +#include "memory.h"
>> +#include "sysbus.h"
>> +#include "qemu-timer.h"
>> +
>> +/* APIC Local Vector Table */
>> +#define APIC_LVT_TIMER                  0
>> +#define APIC_LVT_THERMAL                1
>> +#define APIC_LVT_PERFORM                2
>> +#define APIC_LVT_LINT0                  3
>> +#define APIC_LVT_LINT1                  4
>> +#define APIC_LVT_ERROR                  5
>> +#define APIC_LVT_NB                     6
>> +
>> +/* APIC delivery modes */
>> +#define APIC_DM_FIXED                   0
>> +#define APIC_DM_LOWPRI                  1
>> +#define APIC_DM_SMI                     2
>> +#define APIC_DM_NMI                     4
>> +#define APIC_DM_INIT                    5
>> +#define APIC_DM_SIPI                    6
>> +#define APIC_DM_EXTINT                  7
>> +
>> +/* APIC destination mode */
>> +#define APIC_DESTMODE_FLAT              0xf
>> +#define APIC_DESTMODE_CLUSTER           1
>> +
>> +#define APIC_TRIGGER_EDGE               0
>> +#define APIC_TRIGGER_LEVEL              1
>> +
>> +#define APIC_LVT_TIMER_PERIODIC         (1<<17)
>> +#define APIC_LVT_MASKED                 (1<<16)
>> +#define APIC_LVT_LEVEL_TRIGGER          (1<<15)
>> +#define APIC_LVT_REMOTE_IRR             (1<<14)
>> +#define APIC_INPUT_POLARITY             (1<<13)
>> +#define APIC_SEND_PENDING               (1<<12)
>> +
>> +#define ESR_ILLEGAL_ADDRESS (1<<  7)
>> +
>> +#define APIC_SV_DIRECTED_IO             (1<<12)
>> +#define APIC_SV_ENABLE                  (1<<8)
>> +
>> +#define MAX_APICS 255
>> +
>> +#define MSI_SPACE_SIZE                  0x100000
>> +
>> +typedef struct APICCommonState APICCommonState;
>> +
>> +struct APICCommonState {
>> +    SysBusDevice busdev;
>> +    MemoryRegion io_memory;
>> +    void *cpu_env;
>> +    uint32_t apicbase;
>> +    uint8_t id;
>> +    uint8_t arb_id;
>> +    uint8_t tpr;
>> +    uint32_t spurious_vec;
>> +    uint8_t log_dest;
>> +    uint8_t dest_mode;
>> +    uint32_t isr[8];  /* in service register */
>> +    uint32_t tmr[8];  /* trigger mode register */
>> +    uint32_t irr[8]; /* interrupt request register */
>> +    uint32_t lvt[APIC_LVT_NB];
>> +    uint32_t esr; /* error register */
>> +    uint32_t icr[2];
>> +
>> +    uint32_t divide_conf;
>> +    int count_shift;
>> +    uint32_t initial_count;
>> +    int64_t initial_count_load_time;
>> +    int64_t next_time;
>> +    int idx;
>> +    QEMUTimer *timer;
>> +    int sipi_vector;
>> +    int wait_for_sipi;
>> +};
>> +
>> +typedef struct APICCommonInfo APICCommonInfo;
>> +
>> +struct APICCommonInfo {
>> +    SysBusDeviceInfo busdev;
>> +    void (*init)(APICCommonState *s);
>> +    void (*set_base)(APICCommonState *s, uint64_t val);
>> +    void (*set_tpr)(APICCommonState *s, uint8_t val);
>> +    void (*external_nmi)(APICCommonState *s);
>> +};
>> +
>> +#define APIC_VMSTATE_VERSION 3
>> +
>> +extern const VMStateDescription vmstate_apic_common;
>> +
>> +#define APIC_PROPERTIES_COMMON(cont_type, cont_var)         \
>> +    DEFINE_PROP_UINT8("id", cont_type, cont_var.id, -1),    \
>> +    DEFINE_PROP_PTR("cpu_env", cont_type, cont_var.cpu_env)
>> +
>> +void apic_report_irq_delivered(int delivered);
>> +void apic_reset_common(DeviceState *d);
>> +int apic_init_common(SysBusDevice *d);
> 
> I think you want to introduce an apic_qdev_register(APICCommonInfo *). 
> Then you can set info->qdev.vmsd = &vmstate_apic_common and avoid having
> to make it extern.

Yep. Will also help with other common settings.

Jan


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 262 bytes --]

^ permalink raw reply	[flat|nested] 49+ messages in thread

end of thread, other threads:[~2012-01-13 22:19 UTC | newest]

Thread overview: 49+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-01-13 17:34 [PATCH v6 00/18] uq/master: Introduce basic irqchip support Jan Kiszka
2012-01-13 17:34 ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:34 ` [PATCH v6 01/18] msi: Generalize msix_supported to msi_supported Jan Kiszka
2012-01-13 17:34   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:34 ` [PATCH v6 02/18] kvm: Move kvmclock into hw/kvm folder Jan Kiszka
2012-01-13 17:34   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:34 ` [PATCH v6 03/18] apic: Stop timer on reset Jan Kiszka
2012-01-13 17:34   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:34 ` [PATCH v6 04/18] apic: Inject external NMI events via LINT1 Jan Kiszka
2012-01-13 17:34   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:35 ` [PATCH v6 05/18] apic: Introduce apic_report_irq_delivered Jan Kiszka
2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:35 ` [PATCH v6 06/18] apic: Factor out base class for KVM reuse Jan Kiszka
2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
2012-01-13 21:18   ` Anthony Liguori
2012-01-13 21:18     ` [Qemu-devel] " Anthony Liguori
2012-01-13 22:19     ` Jan Kiszka
2012-01-13 22:19       ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:35 ` [PATCH v6 07/18] apic: Open-code timer save/restore Jan Kiszka
2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:35 ` [PATCH v6 08/18] i8259: Completely privatize PicState Jan Kiszka
2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:35 ` [PATCH v6 09/18] i8259: Factor out base class for KVM reuse Jan Kiszka
2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
2012-01-13 21:19   ` Anthony Liguori
2012-01-13 21:19     ` [Qemu-devel] " Anthony Liguori
2012-01-13 17:35 ` [PATCH v6 10/18] ioapic: Drop post-load irr initialization Jan Kiszka
2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:35 ` [PATCH v6 11/18] ioapic: Factor out base class for KVM reuse Jan Kiszka
2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:35 ` [PATCH v6 12/18] memory: Introduce memory_region_init_reservation Jan Kiszka
2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:35 ` [PATCH v6 13/18] kvm: Introduce core services for in-kernel irqchip support Jan Kiszka
2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:35 ` [PATCH v6 14/18] kvm: x86: Establish IRQ0 override control Jan Kiszka
2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:35 ` [PATCH v6 15/18] kvm: x86: Add user space part for in-kernel APIC Jan Kiszka
2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:35 ` [PATCH v6 16/18] kvm: x86: Add user space part for in-kernel i8259 Jan Kiszka
2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:35 ` [PATCH v6 17/18] kvm: x86: Add user space part for in-kernel IOAPIC Jan Kiszka
2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
2012-01-13 17:35 ` [PATCH v6 18/18] kvm: Arm in-kernel irqchip support Jan Kiszka
2012-01-13 17:35   ` [Qemu-devel] " Jan Kiszka
2012-01-13 18:49   ` Peter Maydell
2012-01-13 18:49     ` [Qemu-devel] " Peter Maydell
2012-01-13 19:04     ` Jan Kiszka
2012-01-13 19:04       ` [Qemu-devel] " Jan Kiszka
2012-01-13 19:36       ` Andreas Färber

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.