Some guests fail to process the _CST notification which invalidates the C2 
state.

Emulate C2 similarly to HLT for those cases.

Signed-off-by: Marcelo Tosatti <[EMAIL PROTECTED]>

Index: kvm/arch/x86/kvm/Makefile
===================================================================
--- kvm.orig/arch/x86/kvm/Makefile
+++ kvm/arch/x86/kvm/Makefile
@@ -11,7 +11,7 @@ endif
 EXTRA_CFLAGS += -Ivirt/kvm -Iarch/x86/kvm
 
 kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o \
-       i8254.o
+       i8254.o acpi.o
 obj-$(CONFIG_KVM) += kvm.o
 kvm-intel-objs = vmx.o
 obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
Index: kvm/arch/x86/kvm/acpi.c
===================================================================
--- /dev/null
+++ kvm/arch/x86/kvm/acpi.c
@@ -0,0 +1,82 @@
+#include <linux/kvm_host.h>
+#include <linux/kvm.h>
+#include <linux/acpi_pmtmr.h>
+#include <asm/io.h>
+#include "iodev.h"
+#include "irq.h"
+
+/*
+ * P_LVL2 = PBLK + 4h
+ *
+ * Note: matches BIOS (currently hardcoded) definition.
+ */
+#define ACPI_PBLK 0xb010
+
+struct kvm_acpi {
+       struct kvm_io_device dev;
+       struct kvm *kvm;
+};
+
+static void acpi_cstate_halt(struct kvm_vcpu *vcpu)
+{
+       vcpu->arch.mp_state = KVM_MP_STATE_HALTED;
+       mutex_unlock(&vcpu->kvm->lock);
+       up_read(&vcpu->kvm->slots_lock);
+       kvm_vcpu_block(vcpu);
+       down_read(&vcpu->kvm->slots_lock);
+       mutex_lock(&vcpu->kvm->lock);
+       vcpu->arch.pio.size = 0;
+}
+
+static void acpi_ioport_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
+                            gpa_t addr, int len, void *data)
+{
+
+       if (addr == ACPI_PBLK + 0x4)
+               acpi_cstate_halt(vcpu);
+
+       return;
+}
+
+static void acpi_ioport_write(struct kvm_vcpu *vcpu, struct kvm_io_device 
*this,
+                             gpa_t addr, int len, const void *data)
+{
+       return;
+}
+
+static int acpi_in_range(struct kvm_io_device *this, gpa_t addr, int len,
+                        int is_write)
+{
+       struct kvm_acpi *acpi = (struct kvm_acpi *)this->private;
+
+       if (!irqchip_in_kernel(acpi->kvm))
+               return 0;
+
+       return (addr == ACPI_PBLK + 0x4);
+}
+
+void kvm_acpi_free(struct kvm_io_device *this)
+{
+       struct kvm_acpi *acpi = (struct kvm_acpi *)this->private;
+
+       kfree(acpi);
+}
+
+int kvm_acpi_init(struct kvm *kvm)
+{
+       struct kvm_acpi *acpi;
+
+       acpi = kzalloc(sizeof(struct kvm_acpi), GFP_KERNEL);
+       if (!acpi)
+               return -ENOMEM;
+
+       acpi->dev.read = acpi_ioport_read;
+       acpi->dev.write = acpi_ioport_write;
+       acpi->dev.in_range = acpi_in_range;
+       acpi->dev.private = acpi;
+       acpi->kvm = kvm;
+       acpi->dev.destructor = kvm_acpi_free;
+       kvm_io_bus_register_dev(&kvm->pio_bus, &acpi->dev);
+
+       return 0;
+}
Index: kvm/arch/x86/kvm/i8254.c
===================================================================
--- kvm.orig/arch/x86/kvm/i8254.c
+++ kvm/arch/x86/kvm/i8254.c
@@ -320,7 +320,7 @@ void kvm_pit_load_count(struct kvm *kvm,
        mutex_unlock(&kvm->arch.vpit->pit_state.lock);
 }
 
-static void pit_ioport_write(struct kvm_io_device *this,
+static void pit_ioport_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
                             gpa_t addr, int len, const void *data)
 {
        struct kvm_pit *pit = (struct kvm_pit *)this->private;
@@ -393,7 +393,7 @@ static void pit_ioport_write(struct kvm_
        mutex_unlock(&pit_state->lock);
 }
 
-static void pit_ioport_read(struct kvm_io_device *this,
+static void pit_ioport_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
                            gpa_t addr, int len, void *data)
 {
        struct kvm_pit *pit = (struct kvm_pit *)this->private;
@@ -464,8 +464,9 @@ static int pit_in_range(struct kvm_io_de
                (addr < KVM_PIT_BASE_ADDRESS + KVM_PIT_MEM_LENGTH));
 }
 
-static void speaker_ioport_write(struct kvm_io_device *this,
-                                gpa_t addr, int len, const void *data)
+static void speaker_ioport_write(struct kvm_vcpu *vcpu,
+                                struct kvm_io_device *this, gpa_t addr,
+                                int len, const void *data)
 {
        struct kvm_pit *pit = (struct kvm_pit *)this->private;
        struct kvm_kpit_state *pit_state = &pit->pit_state;
@@ -478,7 +479,8 @@ static void speaker_ioport_write(struct 
        mutex_unlock(&pit_state->lock);
 }
 
-static void speaker_ioport_read(struct kvm_io_device *this,
+static void speaker_ioport_read(struct kvm_vcpu *vcpu,
+                               struct kvm_io_device *this,
                                gpa_t addr, int len, void *data)
 {
        struct kvm_pit *pit = (struct kvm_pit *)this->private;
Index: kvm/arch/x86/kvm/i8259.c
===================================================================
--- kvm.orig/arch/x86/kvm/i8259.c
+++ kvm/arch/x86/kvm/i8259.c
@@ -362,7 +362,7 @@ static int picdev_in_range(struct kvm_io
        }
 }
 
-static void picdev_write(struct kvm_io_device *this,
+static void picdev_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
                         gpa_t addr, int len, const void *val)
 {
        struct kvm_pic *s = this->private;
@@ -387,7 +387,7 @@ static void picdev_write(struct kvm_io_d
        }
 }
 
-static void picdev_read(struct kvm_io_device *this,
+static void picdev_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
                        gpa_t addr, int len, void *val)
 {
        struct kvm_pic *s = this->private;
Index: kvm/arch/x86/kvm/lapic.c
===================================================================
--- kvm.orig/arch/x86/kvm/lapic.c
+++ kvm/arch/x86/kvm/lapic.c
@@ -600,7 +600,7 @@ static u32 __apic_read(struct kvm_lapic 
        return val;
 }
 
-static void apic_mmio_read(struct kvm_io_device *this,
+static void apic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
                           gpa_t address, int len, void *data)
 {
        struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
@@ -669,7 +669,7 @@ static void start_apic_timer(struct kvm_
                                        apic->timer.period)));
 }
 
-static void apic_mmio_write(struct kvm_io_device *this,
+static void apic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
                            gpa_t address, int len, const void *data)
 {
        struct kvm_lapic *apic = (struct kvm_lapic *)this->private;
Index: kvm/arch/x86/kvm/x86.c
===================================================================
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -19,6 +19,7 @@
 #include "mmu.h"
 #include "i8254.h"
 #include "tss.h"
+#include "acpi.h"
 
 #include <linux/clocksource.h>
 #include <linux/kvm.h>
@@ -834,6 +835,7 @@ int kvm_dev_ioctl_check_extension(long e
        case KVM_CAP_PIT:
        case KVM_CAP_NOP_IO_DELAY:
        case KVM_CAP_MP_STATE:
+       case KVM_CAP_ACPI_C2:
                r = 1;
                break;
        case KVM_CAP_COALESCED_MMIO:
@@ -1725,6 +1727,10 @@ long kvm_arch_vm_ioctl(struct file *filp
                r = 0;
                break;
        }
+       case KVM_ENABLE_ACPI_C2: {
+               r = kvm_acpi_init(kvm);
+               break;
+       }
        default:
                ;
        }
@@ -1844,7 +1850,7 @@ mmio:
        mutex_lock(&vcpu->kvm->lock);
        mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 0);
        if (mmio_dev) {
-               kvm_iodevice_read(mmio_dev, gpa, bytes, val);
+               kvm_iodevice_read(vcpu, mmio_dev, gpa, bytes, val);
                mutex_unlock(&vcpu->kvm->lock);
                return X86EMUL_CONTINUE;
        }
@@ -1899,7 +1905,7 @@ mmio:
        mutex_lock(&vcpu->kvm->lock);
        mmio_dev = vcpu_find_mmio_dev(vcpu, gpa, bytes, 1);
        if (mmio_dev) {
-               kvm_iodevice_write(mmio_dev, gpa, bytes, val);
+               kvm_iodevice_write(vcpu, mmio_dev, gpa, bytes, val);
                mutex_unlock(&vcpu->kvm->lock);
                return X86EMUL_CONTINUE;
        }
@@ -2244,11 +2250,11 @@ static void kernel_pio(struct kvm_io_dev
 
        mutex_lock(&vcpu->kvm->lock);
        if (vcpu->arch.pio.in)
-               kvm_iodevice_read(pio_dev, vcpu->arch.pio.port,
+               kvm_iodevice_read(vcpu, pio_dev, vcpu->arch.pio.port,
                                  vcpu->arch.pio.size,
                                  pd);
        else
-               kvm_iodevice_write(pio_dev, vcpu->arch.pio.port,
+               kvm_iodevice_write(vcpu, pio_dev, vcpu->arch.pio.port,
                                   vcpu->arch.pio.size,
                                   pd);
        mutex_unlock(&vcpu->kvm->lock);
@@ -2263,7 +2269,7 @@ static void pio_string_write(struct kvm_
 
        mutex_lock(&vcpu->kvm->lock);
        for (i = 0; i < io->cur_count; i++) {
-               kvm_iodevice_write(pio_dev, io->port,
+               kvm_iodevice_write(vcpu, pio_dev, io->port,
                                   io->size,
                                   pd);
                pd += io->size;
Index: kvm/include/linux/kvm.h
===================================================================
--- kvm.orig/include/linux/kvm.h
+++ kvm/include/linux/kvm.h
@@ -371,6 +371,7 @@ struct kvm_trace_rec {
 #define KVM_CAP_PV_MMU 13
 #define KVM_CAP_MP_STATE 14
 #define KVM_CAP_COALESCED_MMIO 15
+#define KVM_CAP_ACPI_C2 16
 
 /*
  * ioctls for VM fds
@@ -400,6 +401,7 @@ struct kvm_trace_rec {
                        _IOW(KVMIO,  0x67, struct kvm_coalesced_mmio_zone)
 #define KVM_UNREGISTER_COALESCED_MMIO \
                        _IOW(KVMIO,  0x68, struct kvm_coalesced_mmio_zone)
+#define KVM_ENABLE_ACPI_C2       _IO(KVMIO, 0x69)
 
 /*
  * ioctls for vcpu fds
Index: kvm/virt/kvm/iodev.h
===================================================================
--- kvm.orig/virt/kvm/iodev.h
+++ kvm/virt/kvm/iodev.h
@@ -16,14 +16,17 @@
 #ifndef __KVM_IODEV_H__
 #define __KVM_IODEV_H__
 
+#include <linux/kvm_host.h>
 #include <linux/kvm_types.h>
 
 struct kvm_io_device {
-       void (*read)(struct kvm_io_device *this,
+       void (*read)(struct kvm_vcpu *vcpu,
+                    struct kvm_io_device *this,
                     gpa_t addr,
                     int len,
                     void *val);
-       void (*write)(struct kvm_io_device *this,
+       void (*write)(struct kvm_vcpu *vcpu,
+                     struct kvm_io_device *this,
                      gpa_t addr,
                      int len,
                      const void *val);
@@ -34,20 +37,22 @@ struct kvm_io_device {
        void             *private;
 };
 
-static inline void kvm_iodevice_read(struct kvm_io_device *dev,
+static inline void kvm_iodevice_read(struct kvm_vcpu *vcpu,
+                                    struct kvm_io_device *dev,
                                     gpa_t addr,
                                     int len,
                                     void *val)
 {
-       dev->read(dev, addr, len, val);
+       dev->read(vcpu, dev, addr, len, val);
 }
 
-static inline void kvm_iodevice_write(struct kvm_io_device *dev,
+static inline void kvm_iodevice_write(struct kvm_vcpu *vcpu,
+                                     struct kvm_io_device *dev,
                                      gpa_t addr,
                                      int len,
                                      const void *val)
 {
-       dev->write(dev, addr, len, val);
+       dev->write(vcpu, dev, addr, len, val);
 }
 
 static inline int kvm_iodevice_inrange(struct kvm_io_device *dev,
Index: kvm/arch/x86/kvm/acpi.h
===================================================================
--- /dev/null
+++ kvm/arch/x86/kvm/acpi.h
@@ -0,0 +1,6 @@
+#ifndef __KVM_ACPI_H
+#define __KVM_ACPI_H
+
+int kvm_acpi_init(struct kvm *kvm);
+
+#endif
Index: kvm/virt/kvm/ioapic.c
===================================================================
--- kvm.orig/virt/kvm/ioapic.c
+++ kvm/virt/kvm/ioapic.c
@@ -325,8 +325,8 @@ static int ioapic_in_range(struct kvm_io
                 (addr < ioapic->base_address + IOAPIC_MEM_LENGTH)));
 }
 
-static void ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,
-                            void *val)
+static void ioapic_mmio_read(struct kvm_vcpu *vcpu, struct kvm_io_device *this,
+                            gpa_t addr, int len, void *val)
 {
        struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
        u32 result;
@@ -362,8 +362,8 @@ static void ioapic_mmio_read(struct kvm_
        }
 }
 
-static void ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,
-                             const void *val)
+static void ioapic_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device 
*this,
+                             gpa_t addr, int len, const void *val)
 {
        struct kvm_ioapic *ioapic = (struct kvm_ioapic *)this->private;
        u32 data;
Index: kvm/virt/kvm/coalesced_mmio.c
===================================================================
--- kvm.orig/virt/kvm/coalesced_mmio.c
+++ kvm/virt/kvm/coalesced_mmio.c
@@ -60,7 +60,7 @@ static int coalesced_mmio_in_range(struc
        return 0;
 }
 
-static void coalesced_mmio_write(struct kvm_io_device *this,
+static void coalesced_mmio_write(struct kvm_vcpu *vcpu, struct kvm_io_device 
*this,
                                 gpa_t addr, int len, const void *val)
 {
        struct kvm_coalesced_mmio_dev *dev =

-- 

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to