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