From mboxrd@z Thu Jan 1 00:00:00 1970 From: Marcelo Tosatti Subject: [patch 7/7] KVM: in-kernel ACPI C2 idle emulation Date: Wed, 18 Jun 2008 13:42:12 -0300 Message-ID: <20080618164854.789420485@localhost.localdomain> References: <20080618164205.108219607@localhost.localdomain> Cc: kvm@vger.kernel.org, Marcelo Tosatti To: Avi Kivity Return-path: Received: from mx1.redhat.com ([66.187.233.31]:60254 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752889AbYFRQwl (ORCPT ); Wed, 18 Jun 2008 12:52:41 -0400 Content-Disposition: inline; filename=acpi-c2-emul Sender: kvm-owner@vger.kernel.org List-ID: 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 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 +#include +#include +#include +#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 #include @@ -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 #include 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 = --