From mboxrd@z Thu Jan 1 00:00:00 1970 From: Marcelo Tosatti Subject: [patch 05/12] KVM: in-kernel ACPI timer emulation Date: Thu, 29 May 2008 19:22:54 -0300 Message-ID: <20080529222828.816210417@localhost.localdomain> References: <20080529222249.563011248@localhost.localdomain> Cc: Chris Wright , Glauber Costa , Anthony Liguori , kvm@vger.kernel.org, Marcelo Tosatti To: Avi Kivity Return-path: Received: from mx1.redhat.com ([66.187.233.31]:52647 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753240AbYE2W3q (ORCPT ); Thu, 29 May 2008 18:29:46 -0400 Content-Disposition: inline; filename=acpi-tmr-inkernel Sender: kvm-owner@vger.kernel.org List-ID: C1 emulation reads the pmtimer very often, so move ACPI pmtimer to kernel space. Signed-off-by: Marcelo Tosatti Index: kvm/arch/x86/kvm/Makefile =================================================================== --- kvm.orig/arch/x86/kvm/Makefile +++ kvm/arch/x86/kvm/Makefile @@ -10,7 +10,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,103 @@ +#include +#include +#include +#include "iodev.h" +#include "irq.h" +#include "acpi.h" + +static void get_pmtmr(int pmtmr_offset, void *data) +{ + u32 d; + d = muldiv64(ktime_to_ns(ktime_get()), PMTMR_TICKS_PER_SEC, NSEC_PER_SEC); + d &= ACPI_PM_MASK; + d += pmtmr_offset; + d &= ACPI_PM_MASK; + memcpy(data, &d, sizeof d); +} + +static void acpi_ioport_read(struct kvm_io_device *this, gpa_t addr, int len, + void *data) +{ + struct kvm_acpi_timer *acpi = (struct kvm_acpi_timer *)this->private; + + if (len == 4) + get_pmtmr(acpi->pmtmr_offset, data); + + return; +} + +static void acpi_ioport_write(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) +{ + struct kvm_acpi_timer *acpi = (struct kvm_acpi_timer *)this->private; + struct kvm *kvm = acpi->kvm; + + if (!kvm->arch.vacpi_timer) + return 0; + + return (addr == kvm->arch.vacpi_timer->pmtmr_state.base_address); +} + +void kvm_acpi_free(struct kvm_io_device *this) +{ + struct kvm_acpi_timer *acpi = (struct kvm_acpi_timer *)this->private; + + kfree(acpi); +} + +int kvm_vm_ioctl_get_acpi_timer(struct kvm *kvm, + struct kvm_acpi_timer_state *pmtmr) +{ + if (!kvm->arch.vacpi_timer) + return -EINVAL; + + get_pmtmr(kvm->arch.vacpi_timer->pmtmr_offset, &pmtmr->timer_val); + pmtmr->base_address = kvm->arch.vacpi_timer->pmtmr_state.base_address; + return 0; +} + +int kvm_vm_ioctl_set_acpi_timer(struct kvm *kvm, + struct kvm_acpi_timer_state *pmtmr) +{ + u32 d; + + if (!kvm->arch.vacpi_timer) + return -EINVAL; + kvm->arch.vacpi_timer->pmtmr_state.base_address = pmtmr->base_address; + + d = muldiv64(ktime_to_ns(ktime_get()), PMTMR_TICKS_PER_SEC, NSEC_PER_SEC); + d &= ACPI_PM_MASK; + kvm->arch.vacpi_timer->pmtmr_offset = (pmtmr->timer_val - d) & ACPI_PM_MASK; + return 0; +} + +/* + * Note: matches BIOS (currently hardcoded) definition. + */ +#define ACPI_PMTMR_BASE 0xb008 + +int kvm_acpi_init(struct kvm *kvm) +{ + struct kvm_acpi_timer *acpi; + + acpi = kzalloc(sizeof(struct kvm_acpi_timer), 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; + acpi->pmtmr_state.base_address = ACPI_PMTMR_BASE; + kvm->arch.vacpi_timer = acpi; + kvm_io_bus_register_dev(&kvm->pio_bus, &acpi->dev); + + return 0; +} Index: kvm/arch/x86/kvm/acpi.h =================================================================== --- /dev/null +++ kvm/arch/x86/kvm/acpi.h @@ -0,0 +1,19 @@ +#ifndef __KVM_ACPI_H +#define __KVM_ACPI_H + +struct kvm_acpi_timer { + struct kvm_io_device dev; + struct kvm *kvm; + int pmtmr_offset; + struct kvm_acpi_timer_state pmtmr_state; +}; + +int kvm_acpi_init(struct kvm *kvm); + +int kvm_vm_ioctl_get_acpi_timer(struct kvm *kvm, + struct kvm_acpi_timer_state *pmtmr); + +int kvm_vm_ioctl_set_acpi_timer(struct kvm *kvm, + struct kvm_acpi_timer_state *pmtmr); + +#endif 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 @@ -794,6 +795,7 @@ int kvm_dev_ioctl_check_extension(long e case KVM_CAP_NOP_IO_DELAY: case KVM_CAP_MP_STATE: case KVM_CAP_OPEN_IOPORT: + case KVM_CAP_ACPI_TIMER: r = 1; break; case KVM_CAP_VAPIC: @@ -1742,6 +1744,31 @@ long kvm_arch_vm_ioctl(struct file *filp goto out; break; } + case KVM_CREATE_ACPI_TIMER: { + r = kvm_acpi_init(kvm); + break; + } + case KVM_GET_ACPI_TIMER: { + struct kvm_acpi_timer_state acpi_timer; + r = kvm_vm_ioctl_get_acpi_timer(kvm, &acpi_timer); + if (r) + goto out; + r = -EFAULT; + if (copy_to_user(argp, &acpi_timer, sizeof acpi_timer)) + goto out; + r = 0; + break; + } + case KVM_SET_ACPI_TIMER: { + struct kvm_acpi_timer_state acpi_timer; + r = -EFAULT; + if (copy_from_user(&acpi_timer, argp, sizeof acpi_timer)) + goto out; + r = kvm_vm_ioctl_set_acpi_timer(kvm, &acpi_timer); + if (r) + goto out; + break; + } default: ; } Index: kvm/include/linux/kvm.h =================================================================== --- kvm.orig/include/linux/kvm.h +++ kvm/include/linux/kvm.h @@ -347,6 +347,7 @@ struct kvm_trace_rec { #define KVM_CAP_PV_MMU 13 #define KVM_CAP_MP_STATE 14 #define KVM_CAP_OPEN_IOPORT 15 +#define KVM_CAP_ACPI_TIMER 16 /* * ioctls for VM fds @@ -373,6 +374,9 @@ struct kvm_trace_rec { #define KVM_GET_PIT _IOWR(KVMIO, 0x65, struct kvm_pit_state) #define KVM_SET_PIT _IOR(KVMIO, 0x66, struct kvm_pit_state) #define KVM_SET_OPEN_IOPORT _IOR(KVMIO, 0x67, struct kvm_ioport_list) +#define KVM_CREATE_ACPI_TIMER _IO(KVMIO, 0x68) +#define KVM_GET_ACPI_TIMER _IOWR(KVMIO, 0x69, struct kvm_acpi_timer_state) +#define KVM_SET_ACPI_TIMER _IOR(KVMIO, 0x70, struct kvm_acpi_timer_state) /* * ioctls for vcpu fds Index: kvm/include/asm-x86/kvm.h =================================================================== --- kvm.orig/include/asm-x86/kvm.h +++ kvm/include/asm-x86/kvm.h @@ -220,6 +220,12 @@ struct kvm_ioport_list { struct kvm_ioport ioports[0]; }; +/* for KVM_GET_ACPI_TIMER and KVM_SET_ACPI_TIMER */ +struct kvm_acpi_timer_state { + __u32 base_address; + __u32 timer_val; +}; + #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) Index: kvm/include/asm-x86/kvm_host.h =================================================================== --- kvm.orig/include/asm-x86/kvm_host.h +++ kvm/include/asm-x86/kvm_host.h @@ -318,6 +318,7 @@ struct kvm_arch{ struct kvm_pic *vpic; struct kvm_ioapic *vioapic; struct kvm_pit *vpit; + struct kvm_acpi_timer *vacpi_timer; int round_robin_prev_vcpu; unsigned int tss_addr; --