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

Reply via email to