C1 emulation reads the pmtimer very often, so move ACPI pmtimer to
kernel space.
Signed-off-by: Marcelo Tosatti <[EMAIL PROTECTED]>
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 <linux/kvm_host.h>
+#include <linux/kvm.h>
+#include <linux/acpi_pmtmr.h>
+#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 <linux/clocksource.h>
#include <linux/kvm.h>
@@ -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;
--
--
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