From: Marcelo Tosatti <mtosatti@redhat.com>
To: Avi Kivity <avi@qumranet.com>
Cc: Chris Wright <chrisw@redhat.com>,
Glauber Costa <gcosta@redhat.com>,
Anthony Liguori <aliguori@us.ibm.com>,
kvm@vger.kernel.org, Marcelo Tosatti <mtosatti@redhat.com>
Subject: [patch 05/12] KVM: in-kernel ACPI timer emulation
Date: Thu, 29 May 2008 19:22:54 -0300 [thread overview]
Message-ID: <20080529222828.816210417@localhost.localdomain> (raw)
In-Reply-To: 20080529222249.563011248@localhost.localdomain
[-- Attachment #1: acpi-tmr-inkernel --]
[-- Type: text/plain, Size: 6863 bytes --]
C1 emulation reads the pmtimer very often, so move ACPI pmtimer to
kernel space.
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
@@ -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;
--
next prev parent reply other threads:[~2008-05-29 22:29 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-05-29 22:22 [patch 00/12] fake ACPI C2 emulation v2 Marcelo Tosatti
2008-05-29 22:22 ` [patch 01/12] expose ACPI pmtimer to userspace (/dev/pmtimer) Marcelo Tosatti
2008-06-01 16:34 ` Thomas Gleixner
2008-06-01 16:56 ` Anthony Liguori
2008-06-04 9:53 ` Avi Kivity
2008-06-04 10:01 ` Thomas Gleixner
2008-06-04 10:35 ` Avi Kivity
2008-06-01 17:56 ` Marcelo Tosatti
2008-06-01 18:17 ` Thomas Gleixner
2008-06-02 16:43 ` John Stultz
2008-06-03 4:09 ` Marcelo Tosatti
2008-05-29 22:22 ` [patch 02/12] KVM: allow multiple IO bitmap pages, provide userspace interface Marcelo Tosatti
2008-05-29 22:22 ` [patch 03/12] KVM: allow userspace to open access to ACPI pmtimer Marcelo Tosatti
2008-05-29 22:22 ` [patch 04/12] KVM: move muldiv64 to x86.c, export Marcelo Tosatti
2008-05-29 22:22 ` Marcelo Tosatti [this message]
2008-05-29 22:22 ` [patch 06/12] QEMU/KVM: self-disabling C2 emulation Marcelo Tosatti
2008-05-29 22:22 ` [patch 07/12] libkvm: interface to KVM_SET_OPEN_IOPORT Marcelo Tosatti
2008-05-29 22:22 ` [patch 08/12] QEMU/KVM: non-virtualized ACPI PMTimer support Marcelo Tosatti
2008-05-29 22:22 ` [patch 09/12] libkvm: in-kernel ACPI pmtimer interface Marcelo Tosatti
2008-05-29 22:22 ` [patch 10/12] QEMU/KVM: add option to disable in-kernel pmtimer emulation Marcelo Tosatti
2008-05-29 22:23 ` [patch 11/12] libkvm: interface for pmtimer save/restore Marcelo Tosatti
2008-05-29 22:23 ` [patch 12/12] QEMU/KVM: in-kernel pmtimer save/restore support Marcelo Tosatti
2008-06-01 9:21 ` [patch 00/12] fake ACPI C2 emulation v2 Avi Kivity
2008-06-02 16:08 ` Marcelo Tosatti
2008-06-04 10:49 ` Avi Kivity
2008-06-05 3:12 ` Marcelo Tosatti
2008-06-05 7:56 ` Avi Kivity
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=20080529222828.816210417@localhost.localdomain \
--to=mtosatti@redhat.com \
--cc=aliguori@us.ibm.com \
--cc=avi@qumranet.com \
--cc=chrisw@redhat.com \
--cc=gcosta@redhat.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