public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Marcelo Tosatti <mtosatti@redhat.com>
To: Avi Kivity <avi@qumranet.com>
Cc: kvm@vger.kernel.org, Marcelo Tosatti <mtosatti@redhat.com>
Subject: [patch 7/7] KVM: in-kernel ACPI C2 idle emulation
Date: Wed, 18 Jun 2008 13:42:12 -0300	[thread overview]
Message-ID: <20080618164854.789420485@localhost.localdomain> (raw)
In-Reply-To: 20080618164205.108219607@localhost.localdomain

[-- Attachment #1: acpi-c2-emul --]
[-- Type: text/plain, Size: 11633 bytes --]

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 <mtosatti@redhat.com>

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 =

-- 


  parent reply	other threads:[~2008-06-18 16:52 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-06-18 16:42 [patch 0/7] force the TSC unreliable by reporting C2 state Marcelo Tosatti
2008-06-18 16:42 ` [patch 1/7] kvm: qemu: inform valid C2 state in ACPI table Marcelo Tosatti
2008-06-18 16:42 ` [patch 2/7] kvm: qemu: disable c2 via _CST notification Marcelo Tosatti
2008-06-18 16:42 ` [patch 3/7] libkvm: in-kernel C2 halt interface Marcelo Tosatti
2008-06-18 16:42 ` [patch 4/7] libkvm: handle_io return handler value Marcelo Tosatti
2008-06-18 16:42 ` [patch 5/7] qemu: kvm: unhalt vcpu0 on pit irq Marcelo Tosatti
2008-06-18 16:42 ` [patch 6/7] kvm: qemu: enable in-kernel C2 emulation / userspace emulation Marcelo Tosatti
2008-06-18 16:42 ` Marcelo Tosatti [this message]
2008-06-23  3:01   ` [patch 7/7] KVM: in-kernel ACPI C2 idle emulation Avi Kivity
2008-06-18 20:09 ` [patch 0/7] force the TSC unreliable by reporting C2 state Anthony Liguori
2008-06-18 20:40   ` Marcelo Tosatti
2008-06-18 21:02     ` Anthony Liguori
2008-06-18 21:21       ` Marcelo Tosatti
2008-06-18 21:42         ` Anthony Liguori
2008-06-18 22:41           ` Marcelo Tosatti
2008-06-18 22:57             ` john stultz
2008-06-18 23:08               ` Nakajima, Jun
2008-06-20 14:07             ` Andi Kleen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080618164854.789420485@localhost.localdomain \
    --to=mtosatti@redhat.com \
    --cc=avi@qumranet.com \
    --cc=kvm@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox