kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/5] BIOS changes for irq0->inti2 override (v9)
@ 2009-07-07 15:50 Beth Kon
  2009-07-07 15:50 ` [PATCH 2/5] Userspace changes for irq0->inti2 override support (v9) Beth Kon
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Beth Kon @ 2009-07-07 15:50 UTC (permalink / raw)
  To: avi; +Cc: kvm, Beth Kon

    bios: allow qemu to configure irq0->inti2 override

    Win2k8 expects the HPET interrupt on inti2, regardless of whether
    an override exists in the BIOS. And the HPET spec states that in legacy mode,
    timer interrupt is on inti2.

    The irq0->inti2 override will always be used unless the kernel cannot do irq
    routing (i.e., compatibility with old kernels). So if the kernel is capable,
    userspace sets up irq0->inti2 via the irq routing interface, and adds the
    irq0->inti2 override to the MADT interrupt source override table,
    and the mp table (for the no-acpi case).

    Changes from v8 - Incorporated Gleb's comments to patch 1/5 and 4/5.
                      In 1/5, removed a "return" per Gleb's comment.
                      See 4/5 for v8->v9 change description. 

    Signed-off-by: Beth Kon <eak@us.ibm.com>

---
 kvm/bios/rombios32.c |   66 +++++++++++++++++++++++++++++++++++++------------
 1 files changed, 50 insertions(+), 16 deletions(-)

diff --git a/kvm/bios/rombios32.c b/kvm/bios/rombios32.c
index 0369111..f9e0452 100755
--- a/kvm/bios/rombios32.c
+++ b/kvm/bios/rombios32.c
@@ -446,6 +446,9 @@ uint32_t cpuid_features;
 uint32_t cpuid_ext_features;
 unsigned long ram_size;
 uint64_t ram_end;
+#ifdef BX_QEMU
+uint8_t irq0_override;
+#endif
 #ifdef BX_USE_EBDA_TABLES
 unsigned long ebda_cur_addr;
 #endif
@@ -487,6 +490,7 @@ void wrmsr_smp(uint32_t index, uint64_t val)
 #define QEMU_CFG_ARCH_LOCAL     0x8000
 #define QEMU_CFG_ACPI_TABLES  (QEMU_CFG_ARCH_LOCAL + 0)
 #define QEMU_CFG_SMBIOS_ENTRIES  (QEMU_CFG_ARCH_LOCAL + 1)
+#define QEMU_CFG_IRQ0_OVERRIDE   (QEMU_CFG_ARCH_LOCAL + 2)
 
 int qemu_cfg_port;
 
@@ -555,6 +559,16 @@ uint64_t qemu_cfg_get64 (void)
 }
 #endif
 
+#ifdef BX_QEMU
+void irq0_override_probe(void)
+{
+    if(qemu_cfg_port) {
+        qemu_cfg_select(QEMU_CFG_IRQ0_OVERRIDE);
+        qemu_cfg_read(&irq0_override, 1);
+    }
+}
+#endif
+
 void cpu_probe(void)
 {
     uint32_t eax, ebx, ecx, edx;
@@ -1153,7 +1167,14 @@ static void mptable_init(void)
     putstr(&q, "0.1         "); /* vendor id */
     putle32(&q, 0); /* OEM table ptr */
     putle16(&q, 0); /* OEM table size */
+#ifdef BX_QEMU
+    if (irq0_override)
+        putle16(&q, MAX_CPUS + 17); /* entry count */
+    else
+        putle16(&q, MAX_CPUS + 18); /* entry count */
+#else
     putle16(&q, MAX_CPUS + 18); /* entry count */
+#endif
     putle32(&q, 0xfee00000); /* local APIC addr */
     putle16(&q, 0); /* ext table length */
     putb(&q, 0); /* ext table checksum */
@@ -1197,6 +1218,13 @@ static void mptable_init(void)
 
     /* irqs */
     for(i = 0; i < 16; i++) {
+#ifdef BX_QEMU
+        /* One entry per ioapic interrupt destination. Destination 2 is covered
+         * by irq0->inti2 override (i == 0). Source IRQ 2 is unused
+         */
+        if (irq0_override && i == 2)
+            continue;
+#endif
         putb(&q, 3); /* entry type = I/O interrupt */
         putb(&q, 0); /* interrupt type = vectored interrupt */
         putb(&q, 0); /* flags: po=0, el=0 */
@@ -1204,7 +1232,12 @@ static void mptable_init(void)
         putb(&q, 0); /* source bus ID = ISA */
         putb(&q, i); /* source bus IRQ */
         putb(&q, ioapic_id); /* dest I/O APIC ID */
-        putb(&q, i); /* dest I/O APIC interrupt in */
+#ifdef BX_QEMU
+        if (irq0_override && i == 0)
+            putb(&q, 2); /* dest I/O APIC interrupt in */
+        else
+#endif
+            putb(&q, i); /* dest I/O APIC interrupt in */
     }
     /* patch length */
     len = q - mp_config_table;
@@ -1768,23 +1801,21 @@ void acpi_bios_init(void)
         io_apic->io_apic_id = smp_cpus;
         io_apic->address = cpu_to_le32(0xfec00000);
         io_apic->interrupt = cpu_to_le32(0);
-#ifdef BX_QEMU
-#ifdef HPET_WORKS_IN_KVM
         io_apic++;
-
-        int_override = (void *)io_apic;
-        int_override->type = APIC_XRUPT_OVERRIDE;
-        int_override->length = sizeof(*int_override);
-        int_override->bus = cpu_to_le32(0);
-        int_override->source = cpu_to_le32(0);
-        int_override->gsi = cpu_to_le32(2);
-        int_override->flags = cpu_to_le32(0);
-#endif
+        int_override = (struct madt_int_override*)(io_apic);
+#ifdef BX_QEMU
+        if (irq0_override) {
+            memset(int_override, 0, sizeof(*int_override));
+            int_override->type = APIC_XRUPT_OVERRIDE;
+            int_override->length = sizeof(*int_override);
+            int_override->source = 0;
+            int_override->gsi = 2;
+            int_override->flags = 0; /* conforms to bus specifications */
+            int_override++;
+        }
 #endif
-
-        int_override = (struct madt_int_override*)(io_apic + 1);
-        for ( i = 0; i < 16; i++ ) {
-            if ( PCI_ISA_IRQ_MASK & (1U << i) ) {
+        for (i = 0; i < 16; i++) {
+            if (PCI_ISA_IRQ_MASK & (1U << i)) {
                 memset(int_override, 0, sizeof(*int_override));
                 int_override->type   = APIC_XRUPT_OVERRIDE;
                 int_override->length = sizeof(*int_override);
@@ -2708,6 +2739,9 @@ void rombios32_init(uint32_t *s3_resume_vector, uint8_t *shutdown_flag)
 
     if (bios_table_cur_addr != 0) {
 
+#ifdef BX_QEMU
+        irq0_override_probe();
+#endif
         mptable_init();
 
         smbios_init();

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

* [PATCH 2/5] Userspace changes for irq0->inti2 override support (v9)
  2009-07-07 15:50 [PATCH 1/5] BIOS changes for irq0->inti2 override (v9) Beth Kon
@ 2009-07-07 15:50 ` Beth Kon
  2009-07-07 15:50 ` [PATCH 3/5] BIOS changes for qemu-kvm hpet " Beth Kon
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Beth Kon @ 2009-07-07 15:50 UTC (permalink / raw)
  To: avi; +Cc: kvm, Beth Kon

    Select irq0->irq2 override based on kernel gsi routing availability

    If the kernel does not support gsi routing, we cannot do the irq0->irq2
    override, so disable it in that case.

    Signed-off-by: Beth Kon <eak@us.ibm.com>
    Signed-off-by: Avi Kivity <avi@redhat.com>

---
 hw/ioapic.c    |    6 +++---
 hw/pc.c        |    2 ++
 qemu-kvm-x86.c |    6 +++++-
 qemu-kvm.h     |    2 ++
 sysemu.h       |    1 +
 vl.c           |   11 +++++++++--
 6 files changed, 22 insertions(+), 6 deletions(-)

diff --git a/hw/ioapic.c b/hw/ioapic.c
index a7a5ef9..c894b72 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -23,6 +23,7 @@
 
 #include "hw.h"
 #include "pc.h"
+#include "sysemu.h"
 #include "qemu-timer.h"
 #include "host-utils.h"
 
@@ -95,14 +96,13 @@ void ioapic_set_irq(void *opaque, int vector, int level)
 {
     IOAPICState *s = opaque;
 
-#if 0
     /* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
      * to GSI 2.  GSI maps to ioapic 1-1.  This is not
      * the cleanest way of doing it but it should work. */
 
-    if (vector == 0)
+    if (vector == 0 && irq0override) {
         vector = 2;
-#endif
+    }
 
     if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
         uint32_t mask = 1 << vector;
diff --git a/hw/pc.c b/hw/pc.c
index 05d05e0..043a0da 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -55,6 +55,7 @@
 #define BIOS_CFG_IOPORT 0x510
 #define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
 #define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
+#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
 
 #define MAX_IDE_BUS 2
 
@@ -476,6 +477,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);
 
     smbios_table = smbios_get_table(&smbios_len);
     if (smbios_table)
diff --git a/qemu-kvm-x86.c b/qemu-kvm-x86.c
index a78073e..f7c66d1 100644
--- a/qemu-kvm-x86.c
+++ b/qemu-kvm-x86.c
@@ -1561,7 +1561,11 @@ int kvm_arch_init_irq_routing(void)
                 return r;
         }
         for (i = 0; i < 24; ++i) {
-            r = kvm_add_irq_route(kvm_context, i, KVM_IRQCHIP_IOAPIC, i);
+            if (i == 0) {
+                r = kvm_add_irq_route(kvm_context, i, KVM_IRQCHIP_IOAPIC, 2);
+            } else if (i != 2) {
+                r = kvm_add_irq_route(kvm_context, i, KVM_IRQCHIP_IOAPIC, i);
+            }
             if (r < 0)
                 return r;
         }
diff --git a/qemu-kvm.h b/qemu-kvm.h
index eb99bc4..b044ead 100644
--- a/qemu-kvm.h
+++ b/qemu-kvm.h
@@ -167,6 +167,7 @@ int kvm_has_sync_mmu(void);
 #define kvm_enabled() (kvm_allowed)
 #define qemu_kvm_irqchip_in_kernel() kvm_irqchip_in_kernel(kvm_context)
 #define qemu_kvm_pit_in_kernel() kvm_pit_in_kernel(kvm_context)
+#define qemu_kvm_has_gsi_routing() kvm_has_gsi_routing(kvm_context)
 void kvm_init_vcpu(CPUState *env);
 void kvm_load_tsc(CPUState *env);
 #else
@@ -175,6 +176,7 @@ void kvm_load_tsc(CPUState *env);
 #define kvm_nested 0
 #define qemu_kvm_irqchip_in_kernel() (0)
 #define qemu_kvm_pit_in_kernel() (0)
+#define qemu_kvm_has_gsi_routing() (0)
 #define kvm_load_registers(env) do {} while(0)
 #define kvm_save_registers(env) do {} while(0)
 #define qemu_kvm_cpu_stop(env) do {} while(0)
diff --git a/sysemu.h b/sysemu.h
index 2824b0d..5b42506 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -111,6 +111,7 @@ extern int xenfb_enabled;
 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 df583b7..d8b7198 100644
--- a/vl.c
+++ b/vl.c
@@ -255,6 +255,7 @@ int no_reboot = 0;
 int no_shutdown = 0;
 int cursor_hide = 1;
 int graphic_rotate = 0;
+uint8_t irq0override = 1;
 #ifndef _WIN32
 int daemonize = 0;
 #endif
@@ -6199,8 +6200,14 @@ int main(int argc, char **argv, char **envp)
 
     module_call_init(MODULE_INIT_DEVICE);
 
-    if (kvm_enabled())
-	kvm_init_ap();
+    if (kvm_enabled()) {
+       kvm_init_ap();
+#ifdef USE_KVM
+        if (kvm_irqchip && !qemu_kvm_has_gsi_routing()) {
+            irq0override = 0;
+        }
+#endif
+    }
 
     machine->init(ram_size, boot_devices,
                   kernel_filename, kernel_cmdline, initrd_filename, cpu_model);

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

* [PATCH 3/5] BIOS changes for qemu-kvm hpet support (v9)
  2009-07-07 15:50 [PATCH 1/5] BIOS changes for irq0->inti2 override (v9) Beth Kon
  2009-07-07 15:50 ` [PATCH 2/5] Userspace changes for irq0->inti2 override support (v9) Beth Kon
@ 2009-07-07 15:50 ` Beth Kon
  2009-07-07 15:50 ` [PATCH 4/5] Userspace changes for qemu-kvm HPET support(v9) Beth Kon
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Beth Kon @ 2009-07-07 15:50 UTC (permalink / raw)
  To: avi; +Cc: kvm, Beth Kon

    Advertise HPET in ACPI HPET table

    Signed-off-by: Beth Kon <eak@us.ibm.com>
    Signed-off-by: Avi Kivity <avi@redhat.com>

---
 kvm/bios/acpi-dsdt.dsl |    2 --
 kvm/bios/rombios32.c   |   11 +++--------
 2 files changed, 3 insertions(+), 10 deletions(-)

diff --git a/kvm/bios/acpi-dsdt.dsl b/kvm/bios/acpi-dsdt.dsl
index 3560baa..26fc7ad 100755
--- a/kvm/bios/acpi-dsdt.dsl
+++ b/kvm/bios/acpi-dsdt.dsl
@@ -194,7 +194,6 @@ DefinitionBlock (
             })
         }
 #ifdef BX_QEMU
-#ifdef HPET_WORKS_IN_KVM
         Device(HPET) {
             Name(_HID,  EISAID("PNP0103"))
             Name(_UID, 0)
@@ -214,7 +213,6 @@ DefinitionBlock (
             })
         }
 #endif
-#endif
     }
 
     Scope(\_SB.PCI0) {
diff --git a/kvm/bios/rombios32.c b/kvm/bios/rombios32.c
index f9e0452..28f2b21 100755
--- a/kvm/bios/rombios32.c
+++ b/kvm/bios/rombios32.c
@@ -1526,8 +1526,8 @@ struct acpi_20_generic_address {
 } __attribute__((__packed__));
 
 /*
- *  * HPET Description Table
- *   */
+ *  HPET Description Table
+ */
 struct acpi_20_hpet {
     ACPI_TABLE_HEADER_DEF                           /* ACPI common table header */
     uint32_t           timer_block_id;
@@ -1716,13 +1716,11 @@ void acpi_bios_init(void)
     addr += madt_size;
 
 #ifdef BX_QEMU
-#ifdef HPET_WORKS_IN_KVM
     addr = (addr + 7) & ~7;
     hpet_addr = addr;
     hpet = (void *)(addr);
     addr += sizeof(*hpet);
 #endif
-#endif
 
     /* RSDP */
     memset(rsdp, 0, sizeof(*rsdp));
@@ -1900,7 +1898,6 @@ void acpi_bios_init(void)
     }
 
     /* HPET */
-#ifdef HPET_WORKS_IN_KVM
     memset(hpet, 0, sizeof(*hpet));
     /* Note timer_block_id value must be kept in sync with value advertised by
      * emulated hpet
@@ -1909,7 +1906,6 @@ void acpi_bios_init(void)
     hpet->addr.address = cpu_to_le32(ACPI_HPET_ADDRESS);
     acpi_build_table_header((struct  acpi_table_header *)hpet,
                              "HPET", sizeof(*hpet), 1);
-#endif
 
 #endif
 
@@ -1919,8 +1915,7 @@ void acpi_bios_init(void)
     rsdt->table_offset_entry[nb_rsdt_entries++] = cpu_to_le32(ssdt_addr);
     rsdt->table_offset_entry[nb_rsdt_entries++] = cpu_to_le32(madt_addr);
 #ifdef BX_QEMU
-    /* No HPET (yet) */
-//  rsdt->table_offset_entry[nb_rsdt_entries++] = cpu_to_le32(hpet_addr);
+    rsdt->table_offset_entry[nb_rsdt_entries++] = cpu_to_le32(hpet_addr);
     if (nb_numa_nodes > 0)
         rsdt->table_offset_entry[nb_rsdt_entries++] = cpu_to_le32(srat_addr);
     acpi_additional_tables(); /* resets cfg to required entry */

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

* [PATCH 4/5] Userspace changes for qemu-kvm HPET support(v9)
  2009-07-07 15:50 [PATCH 1/5] BIOS changes for irq0->inti2 override (v9) Beth Kon
  2009-07-07 15:50 ` [PATCH 2/5] Userspace changes for irq0->inti2 override support (v9) Beth Kon
  2009-07-07 15:50 ` [PATCH 3/5] BIOS changes for qemu-kvm hpet " Beth Kon
@ 2009-07-07 15:50 ` Beth Kon
  2009-07-07 15:50 ` [PATCH 5/5] Kernel changes for HPET legacy support(v9) Beth Kon
  2009-07-08 12:01 ` [PATCH 1/5] BIOS changes for irq0->inti2 override (v9) Avi Kivity
  4 siblings, 0 replies; 6+ messages in thread
From: Beth Kon @ 2009-07-07 15:50 UTC (permalink / raw)
  To: avi; +Cc: kvm, Beth Kon

The big change here is handling of enabling/disabling of hpet legacy mode. When hpet enters
legacy mode, the spec says that the pit stops generating interrupts. In practice, we want to
stop the pit periodic timer from running because it is wasteful in a virtual environment.

We also have to worry about the hpet leaving legacy mode (which, at least in linux, happens
only during a shutdown or crash). At this point, according to the hpet spec, PIT interrupts
need to be reenabled. For us, it means the PIT timer needs to be restarted.

This patch handles this situation better than the earlier versions by coming closer to
just disabling PIT interrupts. It allows the PIT state to change if the OS modifies it,
even while PIT is disabled, but does not allow a pit timer to start. Then if HPET
legacy mode is disabled, whatever the PIT state is at that point, the PIT timer is
restarted accordingly.

Changes from v8:
- incremented PIT_SAVEVM_VERSION 
- changed pit_load to check for version_id != PIT_SAVEVM_VERSION
- removed unnecessary return

Changes from v7:
- added flags field to PITState
- added kvm_pit_state2 struct with flags field
- replaced hpet legacy mode ioctl with get/set pit2 ioctl

Changes from v6:

- added ioctl interface for setting hpet legacy mode in kernel pit
- moved check for hpet_legacy_mode in pit_load_count to allow state info
  to be copied before returning if legacy mode is enabled.
- sprinkled in some #ifdef TARGET_I386


Signed-off-by: Beth Kon <eak@us.ibm.com>
---
 hw/hpet.c                 |   16 +++++++--
 hw/i8254-kvm.c            |   25 ++++++++++----
 hw/i8254.c                |   79 ++++++++++++++++++++++++++++++++------------
 hw/i8254.h                |    5 ++-
 hw/pc.h                   |    4 +-
 kvm/include/linux/kvm.h   |    4 ++
 kvm/include/x86/asm/kvm.h |    7 ++++
 libkvm-all.h              |   32 +++++++++++++++++-
 qemu-kvm-x86.c            |   38 +++++++++++++++++++++
 qemu-kvm.c                |   20 +++++++++++
 qemu-kvm.h                |    8 ++++
 vl.c                      |   21 ++++++++++--
 12 files changed, 218 insertions(+), 41 deletions(-)

diff --git a/hw/hpet.c b/hw/hpet.c
index e0be486..462e6db 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -206,6 +206,9 @@ static int hpet_load(QEMUFile *f, void *opaque, int version_id)
             qemu_get_timer(f, s->timer[i].qemu_timer);
         }
     }
+    if (hpet_in_legacy_mode()) {
+        hpet_disable_pit();
+    }
     return 0;
 }
 
@@ -475,9 +478,11 @@ static void hpet_ram_writel(void *opaque, target_phys_addr_t addr,
                 }
                 /* i8254 and RTC are disabled when HPET is in legacy mode */
                 if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
-                    hpet_pit_disable();
+                    hpet_disable_pit();
+                    dprintf("qemu: hpet disabled pit\n");
                 } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
-                    hpet_pit_enable();
+                    hpet_enable_pit();
+                    dprintf("qemu: hpet enabled pit\n");
                 }
                 break;
             case HPET_CFG + 4:
@@ -554,13 +559,16 @@ static void hpet_reset(void *opaque) {
     /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
     s->capability = 0x8086a201ULL;
     s->capability |= ((HPET_CLK_PERIOD) << 32);
-    if (count > 0)
+    s->config = 0ULL;
+    if (count > 0) {
         /* we don't enable pit when hpet_reset is first called (by hpet_init)
          * because hpet is taking over for pit here. On subsequent invocations,
          * hpet_reset is called due to system reset. At this point control must
          * be returned to pit until SW reenables hpet.
          */
-        hpet_pit_enable();
+        hpet_enable_pit();
+        dprintf("qemu: hpet enabled pit\n");
+    }
     count = 1;
 }
 
diff --git a/hw/i8254-kvm.c b/hw/i8254-kvm.c
index 8390d75..af26e4f 100644
--- a/hw/i8254-kvm.c
+++ b/hw/i8254-kvm.c
@@ -33,15 +33,20 @@ static PITState pit_state;
 static void kvm_pit_save(QEMUFile *f, void *opaque)
 {
     PITState *s = opaque;
-    struct kvm_pit_state pit;
+    struct kvm_pit_state2 pit2;
     struct kvm_pit_channel_state *c;
     struct PITChannelState *sc;
     int i;
 
-    kvm_get_pit(kvm_context, &pit);
-
+    if(qemu_kvm_has_pit_state2()) {
+        kvm_get_pit2(kvm_context, &pit2);
+        s->flags = pit2.flags;
+    } else {
+        /* pit2 is superset of pit struct so just cast it and use it */
+        kvm_get_pit(kvm_context, (struct kvm_pit_state *)&pit2);
+    }
     for (i = 0; i < 3; i++) {
-	c = &pit.channels[i];
+	c = &pit2.channels[i];
 	sc = &s->channels[i];
 	sc->count = c->count;
 	sc->latched_count = c->latched_count;
@@ -64,15 +69,16 @@ static void kvm_pit_save(QEMUFile *f, void *opaque)
 static int kvm_pit_load(QEMUFile *f, void *opaque, int version_id)
 {
     PITState *s = opaque;
-    struct kvm_pit_state pit;
+    struct kvm_pit_state2 pit2;
     struct kvm_pit_channel_state *c;
     struct PITChannelState *sc;
     int i;
 
     pit_load(f, s, version_id);
 
+    pit2.flags = s->flags;
     for (i = 0; i < 3; i++) {
-	c = &pit.channels[i];
+	c = &pit2.channels[i];
 	sc = &s->channels[i];
 	c->count = sc->count;
 	c->latched_count = sc->latched_count;
@@ -89,8 +95,11 @@ static int kvm_pit_load(QEMUFile *f, void *opaque, int version_id)
 	c->count_load_time = sc->count_load_time;
     }
 
-    kvm_set_pit(kvm_context, &pit);
-
+    if(qemu_kvm_has_pit_state2()) {
+        kvm_set_pit2(kvm_context, &pit2);
+    } else {
+        kvm_set_pit(kvm_context, (struct kvm_pit_state *)&pit2);
+    }
     return 0;
 }
 
diff --git a/hw/i8254.c b/hw/i8254.c
index 2f229f9..29662bd 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -25,6 +25,7 @@
 #include "pc.h"
 #include "isa.h"
 #include "qemu-timer.h"
+#include "qemu-kvm.h"
 #include "i8254.h"
 
 //#define DEBUG_PIT
@@ -196,13 +197,18 @@ int pit_get_mode(PITState *pit, int channel)
     return s->mode;
 }
 
-static inline void pit_load_count(PITChannelState *s, int val)
+static inline void pit_load_count(PITState *s, int val, int chan)
 {
     if (val == 0)
         val = 0x10000;
-    s->count_load_time = qemu_get_clock(vm_clock);
-    s->count = val;
-    pit_irq_timer_update(s, s->count_load_time);
+    s->channels[chan].count_load_time = qemu_get_clock(vm_clock);
+    s->channels[chan].count = val;
+#ifdef TARGET_I386
+    if (chan == 0 && pit_state.flags & PIT_FLAGS_HPET_LEGACY) {
+        return;
+    }
+#endif
+    pit_irq_timer_update(&s->channels[chan], s->channels[chan].count_load_time);
 }
 
 /* if already latched, do not latch again */
@@ -262,17 +268,17 @@ static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
         switch(s->write_state) {
         default:
         case RW_STATE_LSB:
-            pit_load_count(s, val);
+            pit_load_count(pit, val, addr);
             break;
         case RW_STATE_MSB:
-            pit_load_count(s, val << 8);
+            pit_load_count(pit, val << 8, addr);
             break;
         case RW_STATE_WORD0:
             s->write_latch = val;
             s->write_state = RW_STATE_WORD1;
             break;
         case RW_STATE_WORD1:
-            pit_load_count(s, s->write_latch | (val << 8));
+            pit_load_count(pit, s->write_latch | (val << 8), addr);
             s->write_state = RW_STATE_WORD0;
             break;
         }
@@ -371,10 +377,11 @@ static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
            (double)(expire_time - current_time) / ticks_per_sec);
 #endif
     s->next_transition_time = expire_time;
-    if (expire_time != -1)
+    if (expire_time != -1) {
         qemu_mod_timer(s->irq_timer, expire_time);
-    else
+    } else {
         qemu_del_timer(s->irq_timer);
+    }
 }
 
 static void pit_irq_timer(void *opaque)
@@ -390,6 +397,7 @@ void pit_save(QEMUFile *f, void *opaque)
     PITChannelState *s;
     int i;
 
+    qemu_put_be32(f, pit->flags);
     for(i = 0; i < 3; i++) {
         s = &pit->channels[i];
         qemu_put_be32(f, s->count);
@@ -418,9 +426,10 @@ int pit_load(QEMUFile *f, void *opaque, int version_id)
     PITChannelState *s;
     int i;
 
-    if (version_id != 1)
+    if (version_id != PIT_SAVEVM_VERSION)
         return -EINVAL;
 
+    pit->flags = qemu_get_be32(f);
     for(i = 0; i < 3; i++) {
         s = &pit->channels[i];
         s->count=qemu_get_be32(f);
@@ -451,35 +460,61 @@ void pit_reset(void *opaque)
     PITChannelState *s;
     int i;
 
+#ifdef TARGET_I386
+    pit->flags &= ~PIT_FLAGS_HPET_LEGACY;
+#endif
     for(i = 0;i < 3; i++) {
         s = &pit->channels[i];
         s->mode = 3;
         s->gate = (i != 2);
-        pit_load_count(s, 0);
+        pit_load_count(pit, 0, i);
     }
 }
 
+#ifdef TARGET_I386
 /* When HPET is operating in legacy mode, i8254 timer0 is disabled */
-void hpet_pit_disable(void) {
-    PITChannelState *s;
-    s = &pit_state.channels[0];
-    if (s->irq_timer)
-        qemu_del_timer(s->irq_timer);
+
+void hpet_disable_pit(void)
+{
+    PITChannelState *s = &pit_state.channels[0];
+
+    if (qemu_kvm_pit_in_kernel()) {
+        if (qemu_kvm_has_pit_state2()) {
+            kvm_hpet_disable_kpit();
+        } else {
+             fprintf(stderr, "%s: kvm does not support pit_state2!\n", __FUNCTION__);
+             exit(1);
+        }
+    } else {
+        pit_state.flags |= PIT_FLAGS_HPET_LEGACY;
+        if (s->irq_timer) {
+            qemu_del_timer(s->irq_timer);
+        }
+    }
 }
 
 /* When HPET is reset or leaving legacy mode, it must reenable i8254
  * timer 0
  */
 
-void hpet_pit_enable(void)
+void hpet_enable_pit(void)
 {
     PITState *pit = &pit_state;
-    PITChannelState *s;
-    s = &pit->channels[0];
-    s->mode = 3;
-    s->gate = 1;
-    pit_load_count(s, 0);
+    PITChannelState *s = &pit->channels[0];
+
+    if (qemu_kvm_pit_in_kernel()) {
+        if (qemu_kvm_has_pit_state2()) {
+            kvm_hpet_enable_kpit();
+        } else {
+             fprintf(stderr, "%s: kvm does not support pit_state2!\n", __FUNCTION__);
+             exit(1);
+        }
+    } else {
+        pit_state.flags &= ~PIT_FLAGS_HPET_LEGACY;
+        pit_load_count(pit, s->count, 0);
+    }
 }
+#endif
 
 PITState *pit_init(int base, qemu_irq irq)
 {
diff --git a/hw/i8254.h b/hw/i8254.h
index ee68ab5..d23303a 100644
--- a/hw/i8254.h
+++ b/hw/i8254.h
@@ -26,13 +26,15 @@
 #define QEMU_I8254_H
 
 #define PIT_SAVEVM_NAME "i8254"
-#define PIT_SAVEVM_VERSION 1
+#define PIT_SAVEVM_VERSION 2
 
 #define RW_STATE_LSB 1
 #define RW_STATE_MSB 2
 #define RW_STATE_WORD0 3
 #define RW_STATE_WORD1 4
 
+#define PIT_FLAGS_HPET_LEGACY  1
+
 typedef struct PITChannelState {
     int count; /* can be 65536 */
     uint16_t latched_count;
@@ -55,6 +57,7 @@ typedef struct PITChannelState {
 
 struct PITState {
     PITChannelState channels[3];
+    uint32_t flags;
 };
 
 void pit_save(QEMUFile *f, void *opaque);
diff --git a/hw/pc.h b/hw/pc.h
index 725099c..f333076 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -74,8 +74,8 @@ int pit_get_out(PITState *pit, int channel, int64_t current_time);
 
 PITState *kvm_pit_init(int base, qemu_irq irq);
 
-void hpet_pit_disable(void);
-void hpet_pit_enable(void);
+void hpet_disable_pit(void);
+void hpet_enable_pit(void);
 
 /* vmport.c */
 void vmport_init(void);
diff --git a/kvm/include/linux/kvm.h b/kvm/include/linux/kvm.h
index ca93871..0c6e908 100644
--- a/kvm/include/linux/kvm.h
+++ b/kvm/include/linux/kvm.h
@@ -464,6 +464,7 @@ struct kvm_trace_rec {
 /* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
 #define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
 #define KVM_CAP_PIT2 33
+#define KVM_CAP_PIT_STATE2 35
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -613,6 +614,9 @@ struct kvm_debug_guest {
 #define KVM_IA64_VCPU_GET_STACK   _IOR(KVMIO,  0x9a, void *)
 #define KVM_IA64_VCPU_SET_STACK   _IOW(KVMIO,  0x9b, void *)
 
+#define KVM_GET_PIT2   _IOR(KVMIO,   0x9f, struct kvm_pit_state2)
+#define KVM_SET_PIT2   _IOWR(KVMIO,   0xa0, struct kvm_pit_state2)
+
 #define KVM_TRC_INJ_VIRQ         (KVM_TRC_HANDLER + 0x02)
 #define KVM_TRC_REDELIVER_EVT    (KVM_TRC_HANDLER + 0x03)
 #define KVM_TRC_PEND_INTR        (KVM_TRC_HANDLER + 0x04)
diff --git a/kvm/include/x86/asm/kvm.h b/kvm/include/x86/asm/kvm.h
index dc90c47..3bddac4 100644
--- a/kvm/include/x86/asm/kvm.h
+++ b/kvm/include/x86/asm/kvm.h
@@ -276,6 +276,13 @@ struct kvm_pit_state {
 	struct kvm_pit_channel_state channels[3];
 };
 
+#define KPIT_FLAGS_HPET_LEGACY	0x00000001
+
+struct kvm_pit_state2 {
+	struct kvm_pit_channel_state channels[3];
+	__u32 flags;
+};
+
 struct kvm_reinject_control {
 	__u8 pit_reinject;
 	__u8 reserved[31];
diff --git a/libkvm-all.h b/libkvm-all.h
index ecd3065..e956f20 100644
--- a/libkvm-all.h
+++ b/libkvm-all.h
@@ -719,10 +719,40 @@ int kvm_get_pit(kvm_context_t kvm, struct kvm_pit_state *s);
  * \param s PIT state of the virtual domain
  */
 int kvm_set_pit(kvm_context_t kvm, struct kvm_pit_state *s);
-#endif
 
 int kvm_reinject_control(kvm_context_t kvm, int pit_reinject);
 
+#ifdef KVM_CAP_PIT_STATE2
+/*!
+ * \brief Check for kvm support of kvm_pit_state2
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \return 0 on success
+ */
+int kvm_has_pit_state2(kvm_context_t kvm);
+
+/*!
+ * \brief Set in kernel PIT state2 of the virtual domain
+ *
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param ps2 PIT state2 of the virtual domain
+ * \return 0 on success
+ */
+int kvm_set_pit2(kvm_context_t kvm, struct kvm_pit_state2 *ps2);
+
+/*!
+ * \brief Get in kernel PIT state2 of the virtual domain
+ *
+ *
+ * \param kvm Pointer to the current kvm_context
+ * \param ps2 PIT state2 of the virtual domain
+ * \return 0 on success
+ */
+int kvm_get_pit2(kvm_context_t kvm, struct kvm_pit_state2 *ps2);
+
+#endif
+#endif
 #endif
 
 #ifdef KVM_CAP_VAPIC
diff --git a/qemu-kvm-x86.c b/qemu-kvm-x86.c
index f7c66d1..f90d175 100644
--- a/qemu-kvm-x86.c
+++ b/qemu-kvm-x86.c
@@ -293,8 +293,46 @@ int kvm_set_pit(kvm_context_t kvm, struct kvm_pit_state *s)
 	return r;
 }
 
+#ifdef KVM_CAP_PIT_STATE2
+int kvm_get_pit2(kvm_context_t kvm, struct kvm_pit_state2 *ps2)
+{
+	int r;
+	if (!kvm->pit_in_kernel)
+		return 0;
+	r = ioctl(kvm->vm_fd, KVM_GET_PIT2, ps2);
+	if (r == -1) {
+		r = -errno;
+		perror("kvm_get_pit2");
+	}
+	return r;
+}
+
+int kvm_set_pit2(kvm_context_t kvm, struct kvm_pit_state2 *ps2)
+{
+	int r;
+	if (!kvm->pit_in_kernel)
+		return 0;
+	r = ioctl(kvm->vm_fd, KVM_SET_PIT2, ps2);
+	if (r == -1) {
+		r = -errno;
+		perror("kvm_set_pit2");
+	}
+	return r;
+}
+
+#endif
 #endif
 
+int kvm_has_pit_state2(kvm_context_t kvm)
+{
+	int r = 0;
+
+#ifdef KVM_CAP_PIT_STATE2
+	r = kvm_check_extension(kvm, KVM_CAP_PIT_STATE2);
+#endif
+	return r;
+}
+
 void kvm_show_code(kvm_vcpu_context_t vcpu)
 {
 #define SHOW_CODE_LEN 50
diff --git a/qemu-kvm.c b/qemu-kvm.c
index c5cd038..033d193 100644
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -1965,6 +1965,26 @@ int kvm_vcpu_inited(CPUState *env)
     return env->kvm_cpu_state.created;
 }
 
+#ifdef TARGET_I386
+void kvm_hpet_disable_kpit(void)
+{
+    struct kvm_pit_state2 ps2;
+
+    kvm_get_pit2(kvm_context, &ps2);
+    ps2.flags |= KPIT_FLAGS_HPET_LEGACY;
+    kvm_set_pit2(kvm_context, &ps2);
+}
+
+void kvm_hpet_enable_kpit(void)
+{
+    struct kvm_pit_state2 ps2;
+
+    kvm_get_pit2(kvm_context, &ps2);
+    ps2.flags &= ~KPIT_FLAGS_HPET_LEGACY;
+    kvm_set_pit2(kvm_context, &ps2);
+}
+#endif
+
 int kvm_init_ap(void)
 {
 #ifdef TARGET_I386
diff --git a/qemu-kvm.h b/qemu-kvm.h
index b044ead..5381c3b 100644
--- a/qemu-kvm.h
+++ b/qemu-kvm.h
@@ -35,6 +35,8 @@ void kvm_apic_init(CPUState *env);
 /* called from vcpu initialization */
 void qemu_kvm_load_lapic(CPUState *env);
 
+void kvm_hpet_enable_kpit(void);
+void kvm_hpet_disable_kpit(void);
 int kvm_set_irq(int irq, int level, int *status);
 
 int kvm_physical_memory_set_dirty_tracking(int enable);
@@ -168,6 +170,9 @@ int kvm_has_sync_mmu(void);
 #define qemu_kvm_irqchip_in_kernel() kvm_irqchip_in_kernel(kvm_context)
 #define qemu_kvm_pit_in_kernel() kvm_pit_in_kernel(kvm_context)
 #define qemu_kvm_has_gsi_routing() kvm_has_gsi_routing(kvm_context)
+#ifdef TARGET_I386
+#define qemu_kvm_has_pit_state2() kvm_has_pit_state2(kvm_context)
+#endif
 void kvm_init_vcpu(CPUState *env);
 void kvm_load_tsc(CPUState *env);
 #else
@@ -177,6 +182,9 @@ void kvm_load_tsc(CPUState *env);
 #define qemu_kvm_irqchip_in_kernel() (0)
 #define qemu_kvm_pit_in_kernel() (0)
 #define qemu_kvm_has_gsi_routing() (0)
+#ifdef TARGET_I386
+#define qemu_kvm_has_pit_state2() (0)
+#endif
 #define kvm_load_registers(env) do {} while(0)
 #define kvm_save_registers(env) do {} while(0)
 #define qemu_kvm_cpu_stop(env) do {} while(0)
diff --git a/vl.c b/vl.c
index d8b7198..048e19a 100644
--- a/vl.c
+++ b/vl.c
@@ -248,7 +248,9 @@ int assigned_devices_index;
 int smp_cpus = 1;
 const char *vnc_display;
 int acpi_enabled = 1;
+#ifdef TARGET_I386
 int no_hpet = 0;
+#endif
 int no_virtio_balloon = 0;
 int fd_bootchk = 1;
 int no_reboot = 0;
@@ -6201,10 +6203,23 @@ int main(int argc, char **argv, char **envp)
     module_call_init(MODULE_INIT_DEVICE);
 
     if (kvm_enabled()) {
-       kvm_init_ap();
+        kvm_init_ap();
 #ifdef USE_KVM
-        if (kvm_irqchip && !qemu_kvm_has_gsi_routing()) {
-            irq0override = 0;
+        if (kvm_irqchip) {
+            if (!qemu_kvm_has_gsi_routing()) {
+                irq0override = 0;
+#ifdef TARGET_I386
+                /* if kernel can't do irq routing, interrupt source
+                 * override 0->2 can not be set up as required by hpet,
+                 * so disable hpet.
+                 */
+                no_hpet=1;
+            } else  if (!qemu_kvm_has_pit_state2()) {
+                no_hpet=1;
+            }
+#else
+            }
+#endif
         }
 #endif
     }

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

* [PATCH 5/5] Kernel changes for HPET legacy support(v9)
  2009-07-07 15:50 [PATCH 1/5] BIOS changes for irq0->inti2 override (v9) Beth Kon
                   ` (2 preceding siblings ...)
  2009-07-07 15:50 ` [PATCH 4/5] Userspace changes for qemu-kvm HPET support(v9) Beth Kon
@ 2009-07-07 15:50 ` Beth Kon
  2009-07-08 12:01 ` [PATCH 1/5] BIOS changes for irq0->inti2 override (v9) Avi Kivity
  4 siblings, 0 replies; 6+ messages in thread
From: Beth Kon @ 2009-07-07 15:50 UTC (permalink / raw)
  To: avi; +Cc: kvm, Beth Kon

When kvm is in hpet_legacy_mode, the hpet is providing the 
timer interrupt and the pit should not be. So in legacy mode, the pit timer is
destroyed, but the *state* of the pit is maintained. So if kvm or the guest
tries to modify the state of the pit, this modification is accepted, *except* 
that the timer isn't actually started. When we exit hpet_legacy_mode, 
the current state of the pit (which is up to date since we've been 
accepting modifications) is used to restart the pit timer.

The saved_mode code in kvm_pit_load_count temporarily changes mode to 
0xff in order to destroy the timer, but then restores the actual value,
again maintaining "current" state of the pit for possible later reenablement.

Changes from v7:
- added kvm_pit_state2 struct with flags field
- replaced hpet legacy mode ioctl with get/set pit2 ioctl

changes from v6:

- added ioctl interface for legacy mode in order not to break the abi.


Signed-off-by: Beth Kon <eak@us.ibm.com>

---
 arch/x86/include/asm/kvm.h |    8 ++++++
 arch/x86/kvm/i8254.c       |   22 ++++++++++++++---
 arch/x86/kvm/i8254.h       |    3 +-
 arch/x86/kvm/x86.c         |   55 +++++++++++++++++++++++++++++++++++++++++++-
 include/linux/kvm.h        |    6 ++++
 5 files changed, 88 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
index 708b9c3..f5554dd 100644
--- a/arch/x86/include/asm/kvm.h
+++ b/arch/x86/include/asm/kvm.h
@@ -18,6 +18,7 @@
 #define __KVM_HAVE_GUEST_DEBUG
 #define __KVM_HAVE_MSIX
 #define __KVM_HAVE_MCE
+#define __KVM_HAVE_PIT_STATE2
 
 /* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
@@ -237,6 +238,13 @@ struct kvm_pit_state {
 	struct kvm_pit_channel_state channels[3];
 };
 
+#define KPIT_FLAGS_HPET_LEGACY  0x00000001
+
+struct kvm_pit_state2 {
+	struct kvm_pit_channel_state channels[3];
+	__u32 flags;
+};
+
 struct kvm_reinject_control {
 	__u8 pit_reinject;
 	__u8 reserved[31];
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 6e0a203..0b0a761 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -329,20 +329,33 @@ static void pit_load_count(struct kvm *kvm, int channel, u32 val)
 	case 1:
         /* FIXME: enhance mode 4 precision */
 	case 4:
-		create_pit_timer(ps, val, 0);
+		if (!(ps->flags & KPIT_FLAGS_HPET_LEGACY)) {
+			create_pit_timer(ps, val, 0);
+		}
 		break;
 	case 2:
 	case 3:
-		create_pit_timer(ps, val, 1);
+		if (!(ps->flags & KPIT_FLAGS_HPET_LEGACY)){
+			create_pit_timer(ps, val, 1);
+		}
 		break;
 	default:
 		destroy_pit_timer(&ps->pit_timer);
 	}
 }
 
-void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val)
+void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val, int hpet_legacy_start)
 {
-	pit_load_count(kvm, channel, val);
+	u8 saved_mode;
+	if (hpet_legacy_start) {
+		/* save existing mode for later reenablement */
+		saved_mode = kvm->arch.vpit->pit_state.channels[0].mode;
+		kvm->arch.vpit->pit_state.channels[0].mode = 0xff; /* disable timer */
+		pit_load_count(kvm, channel, val);
+		kvm->arch.vpit->pit_state.channels[0].mode = saved_mode;
+	} else {
+		pit_load_count(kvm, channel, val);
+	}
 }
 
 static inline struct kvm_pit *dev_to_pit(struct kvm_io_device *dev)
@@ -546,6 +559,7 @@ void kvm_pit_reset(struct kvm_pit *pit)
 	struct kvm_kpit_channel_state *c;
 
 	mutex_lock(&pit->pit_state.lock);
+	pit->pit_state.flags = 0;
 	for (i = 0; i < 3; i++) {
 		c = &pit->pit_state.channels[i];
 		c->mode = 0xff;
diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h
index b267018..d4c1c7f 100644
--- a/arch/x86/kvm/i8254.h
+++ b/arch/x86/kvm/i8254.h
@@ -21,6 +21,7 @@ struct kvm_kpit_channel_state {
 
 struct kvm_kpit_state {
 	struct kvm_kpit_channel_state channels[3];
+	u32 flags;
 	struct kvm_timer pit_timer;
 	bool is_periodic;
 	u32    speaker_data_on;
@@ -49,7 +50,7 @@ struct kvm_pit {
 #define KVM_PIT_CHANNEL_MASK	    0x3
 
 void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu);
-void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val);
+void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val, int hpet_legacy_start);
 struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags);
 void kvm_free_pit(struct kvm *kvm);
 void kvm_pit_reset(struct kvm_pit *pit);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index af53f64..aa75466 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1196,6 +1196,7 @@ int kvm_dev_ioctl_check_extension(long ext)
 	case KVM_CAP_ASSIGN_DEV_IRQ:
 	case KVM_CAP_IRQFD:
 	case KVM_CAP_PIT2:
+	case KVM_CAP_PIT_STATE2:
 		r = 1;
 		break;
 	case KVM_CAP_COALESCED_MMIO:
@@ -2057,7 +2058,32 @@ static int kvm_vm_ioctl_set_pit(struct kvm *kvm, struct kvm_pit_state *ps)
 
 	mutex_lock(&kvm->arch.vpit->pit_state.lock);
 	memcpy(&kvm->arch.vpit->pit_state, ps, sizeof(struct kvm_pit_state));
-	kvm_pit_load_count(kvm, 0, ps->channels[0].count);
+	kvm_pit_load_count(kvm, 0, ps->channels[0].count, 0);
+	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
+	return r;
+}
+
+static int kvm_vm_ioctl_get_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
+{
+	int r = 0;
+
+	mutex_lock(&kvm->arch.vpit->pit_state.lock);
+	memcpy(ps, &kvm->arch.vpit->pit_state, sizeof(struct kvm_pit_state2));
+	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
+	return r;
+}
+
+static int kvm_vm_ioctl_set_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
+{
+	int r = 0, start = 0;
+	u32 prev_legacy, cur_legacy;
+	mutex_lock(&kvm->arch.vpit->pit_state.lock);
+	prev_legacy = kvm->arch.vpit->pit_state.flags & KPIT_FLAGS_HPET_LEGACY;
+	cur_legacy = ps->flags & KPIT_FLAGS_HPET_LEGACY;
+	if (!prev_legacy && cur_legacy)
+		start = 1;
+	memcpy(&kvm->arch.vpit->pit_state, ps, sizeof(struct kvm_pit_state2));
+	kvm_pit_load_count(kvm, 0, kvm->arch.vpit->pit_state.channels[0].count, start);
 	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
 	return r;
 }
@@ -2119,6 +2145,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
 	 */
 	union {
 		struct kvm_pit_state ps;
+		struct kvm_pit_state2 ps2;
 		struct kvm_memory_alias alias;
 		struct kvm_pit_config pit_config;
 	} u;
@@ -2301,6 +2328,32 @@ long kvm_arch_vm_ioctl(struct file *filp,
 		r = 0;
 		break;
 	}
+	case KVM_GET_PIT2: {
+		r = -ENXIO;
+		if (!kvm->arch.vpit)
+			goto out;
+		r = kvm_vm_ioctl_get_pit2(kvm, &u.ps2);
+		if (r)
+			goto out;
+		r = -EFAULT;
+		if (copy_to_user(argp, &u.ps2, sizeof(u.ps2)))
+			goto out;
+		r = 0;
+		break;
+	}
+	case KVM_SET_PIT2: {
+		r = -EFAULT;
+		if (copy_from_user(&u.ps2, argp, sizeof(u.ps2)))
+			goto out;
+		r = -ENXIO;
+		if (!kvm->arch.vpit)
+			goto out;
+		r = kvm_vm_ioctl_set_pit2(kvm, &u.ps2);
+		if (r)
+			goto out;
+		r = 0;
+		break;
+	}
 	case KVM_REINJECT_CONTROL: {
 		struct kvm_reinject_control control;
 		r =  -EFAULT;
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 69d3d73..835769a 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -409,6 +409,9 @@ struct kvm_guest_debug {
 #define KVM_CAP_PIT2 33
 #endif
 #define KVM_CAP_SET_BOOT_CPU_ID 34
+#ifdef __KVM_HAVE_PIT_STATE2
+#define KVM_CAP_PIT_STATE2 35
+#endif
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -584,6 +587,9 @@ struct kvm_debug_guest {
 #define KVM_IA64_VCPU_GET_STACK   _IOR(KVMIO,  0x9a, void *)
 #define KVM_IA64_VCPU_SET_STACK   _IOW(KVMIO,  0x9b, void *)
 
+#define KVM_GET_PIT2   _IOR(KVMIO,   0x9f, struct kvm_pit_state2)
+#define KVM_SET_PIT2   _IOWR(KVMIO,   0xa0, struct kvm_pit_state2)
+
 #define KVM_TRC_INJ_VIRQ         (KVM_TRC_HANDLER + 0x02)
 #define KVM_TRC_REDELIVER_EVT    (KVM_TRC_HANDLER + 0x03)
 #define KVM_TRC_PEND_INTR        (KVM_TRC_HANDLER + 0x04)

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

* Re: [PATCH 1/5] BIOS changes for irq0->inti2 override (v9)
  2009-07-07 15:50 [PATCH 1/5] BIOS changes for irq0->inti2 override (v9) Beth Kon
                   ` (3 preceding siblings ...)
  2009-07-07 15:50 ` [PATCH 5/5] Kernel changes for HPET legacy support(v9) Beth Kon
@ 2009-07-08 12:01 ` Avi Kivity
  4 siblings, 0 replies; 6+ messages in thread
From: Avi Kivity @ 2009-07-08 12:01 UTC (permalink / raw)
  To: Beth Kon; +Cc: kvm

On 07/07/2009 06:50 PM, Beth Kon wrote:
>      bios: allow qemu to configure irq0->inti2 override
>
>      Win2k8 expects the HPET interrupt on inti2, regardless of whether
>      an override exists in the BIOS. And the HPET spec states that in legacy mode,
>      timer interrupt is on inti2.
>
>      The irq0->inti2 override will always be used unless the kernel cannot do irq
>      routing (i.e., compatibility with old kernels). So if the kernel is capable,
>      userspace sets up irq0->inti2 via the irq routing interface, and adds the
>      irq0->inti2 override to the MADT interrupt source override table,
>      and the mp table (for the no-acpi case).
>
>      Changes from v8 - Incorporated Gleb's comments to patch 1/5 and 4/5.
>                        In 1/5, removed a "return" per Gleb's comment.
>                        See 4/5 for v8->v9 change description.
>
>    

This series doesn't boot for me - Linux says the 8254 is not connected 
to ioapic.  I pushed it as the 'hpet' branch again, can you take a look?

-- 
error compiling committee.c: too many arguments to function


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

end of thread, other threads:[~2009-07-08 11:59 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-07-07 15:50 [PATCH 1/5] BIOS changes for irq0->inti2 override (v9) Beth Kon
2009-07-07 15:50 ` [PATCH 2/5] Userspace changes for irq0->inti2 override support (v9) Beth Kon
2009-07-07 15:50 ` [PATCH 3/5] BIOS changes for qemu-kvm hpet " Beth Kon
2009-07-07 15:50 ` [PATCH 4/5] Userspace changes for qemu-kvm HPET support(v9) Beth Kon
2009-07-07 15:50 ` [PATCH 5/5] Kernel changes for HPET legacy support(v9) Beth Kon
2009-07-08 12:01 ` [PATCH 1/5] BIOS changes for irq0->inti2 override (v9) Avi Kivity

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).