Commit 7837699f authored by Sheng Yang's avatar Sheng Yang Committed by Avi Kivity

KVM: In kernel PIT model

The patch moves the PIT model from userspace to kernel, and increases
the timer accuracy greatly.

[marcelo: make last_injected_time per-guest]
Signed-off-by: default avatarSheng Yang <sheng.yang@intel.com>
Signed-off-by: default avatarMarcelo Tosatti <mtosatti@redhat.com>
Tested-and-Acked-by: default avatarAlex Davis <alex14641@yahoo.com>
Signed-off-by: default avatarAvi Kivity <avi@qumranet.com>
parent 4fcaa982
...@@ -6,7 +6,8 @@ common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o) ...@@ -6,7 +6,8 @@ common-objs = $(addprefix ../../../virt/kvm/, kvm_main.o ioapic.o)
EXTRA_CFLAGS += -Ivirt/kvm -Iarch/x86/kvm EXTRA_CFLAGS += -Ivirt/kvm -Iarch/x86/kvm
kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o \
i8254.o
obj-$(CONFIG_KVM) += kvm.o obj-$(CONFIG_KVM) += kvm.o
kvm-intel-objs = vmx.o kvm-intel-objs = vmx.o
obj-$(CONFIG_KVM_INTEL) += kvm-intel.o obj-$(CONFIG_KVM_INTEL) += kvm-intel.o
......
This diff is collapsed.
#ifndef __I8254_H
#define __I8254_H
#include "iodev.h"
struct kvm_kpit_timer {
struct hrtimer timer;
int irq;
s64 period; /* unit: ns */
s64 scheduled;
ktime_t last_update;
atomic_t pending;
};
struct kvm_kpit_channel_state {
u32 count; /* can be 65536 */
u16 latched_count;
u8 count_latched;
u8 status_latched;
u8 status;
u8 read_state;
u8 write_state;
u8 write_latch;
u8 rw_mode;
u8 mode;
u8 bcd; /* not supported */
u8 gate; /* timer start */
ktime_t count_load_time;
};
struct kvm_kpit_state {
struct kvm_kpit_channel_state channels[3];
struct kvm_kpit_timer pit_timer;
u32 speaker_data_on;
struct mutex lock;
struct kvm_pit *pit;
bool inject_pending; /* if inject pending interrupts */
unsigned long last_injected_time;
};
struct kvm_pit {
unsigned long base_addresss;
struct kvm_io_device dev;
struct kvm_io_device speaker_dev;
struct kvm *kvm;
struct kvm_kpit_state pit_state;
};
#define KVM_PIT_BASE_ADDRESS 0x40
#define KVM_SPEAKER_BASE_ADDRESS 0x61
#define KVM_PIT_MEM_LENGTH 4
#define KVM_PIT_FREQ 1193181
#define KVM_MAX_PIT_INTR_INTERVAL HZ / 100
#define KVM_PIT_CHANNEL_MASK 0x3
void kvm_inject_pit_timer_irqs(struct kvm_vcpu *vcpu);
void kvm_pit_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
struct kvm_pit *kvm_create_pit(struct kvm *kvm);
void kvm_free_pit(struct kvm *kvm);
#endif
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/kvm_host.h> #include <linux/kvm_host.h>
#include "irq.h" #include "irq.h"
#include "i8254.h"
/* /*
* check if there is pending interrupt without * check if there is pending interrupt without
...@@ -66,6 +67,7 @@ EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt); ...@@ -66,6 +67,7 @@ EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
{ {
kvm_inject_apic_timer_irqs(vcpu); kvm_inject_apic_timer_irqs(vcpu);
kvm_inject_pit_timer_irqs(vcpu);
/* TODO: PIT, RTC etc. */ /* TODO: PIT, RTC etc. */
} }
EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
...@@ -73,6 +75,7 @@ EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); ...@@ -73,6 +75,7 @@ EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec) void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
{ {
kvm_apic_timer_intr_post(vcpu, vec); kvm_apic_timer_intr_post(vcpu, vec);
kvm_pit_timer_intr_post(vcpu, vec);
/* TODO: PIT, RTC etc. */ /* TODO: PIT, RTC etc. */
} }
EXPORT_SYMBOL_GPL(kvm_timer_intr_post); EXPORT_SYMBOL_GPL(kvm_timer_intr_post);
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/kvm_host.h> #include <linux/kvm_host.h>
#include "irq.h" #include "irq.h"
#include "mmu.h" #include "mmu.h"
#include "i8254.h"
#include <linux/clocksource.h> #include <linux/clocksource.h>
#include <linux/kvm.h> #include <linux/kvm.h>
...@@ -818,6 +819,7 @@ int kvm_dev_ioctl_check_extension(long ext) ...@@ -818,6 +819,7 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_SET_TSS_ADDR: case KVM_CAP_SET_TSS_ADDR:
case KVM_CAP_EXT_CPUID: case KVM_CAP_EXT_CPUID:
case KVM_CAP_CLOCKSOURCE: case KVM_CAP_CLOCKSOURCE:
case KVM_CAP_PIT:
r = 1; r = 1;
break; break;
case KVM_CAP_VAPIC: case KVM_CAP_VAPIC:
...@@ -1594,6 +1596,12 @@ long kvm_arch_vm_ioctl(struct file *filp, ...@@ -1594,6 +1596,12 @@ long kvm_arch_vm_ioctl(struct file *filp,
} else } else
goto out; goto out;
break; break;
case KVM_CREATE_PIT:
r = -ENOMEM;
kvm->arch.vpit = kvm_create_pit(kvm);
if (kvm->arch.vpit)
r = 0;
break;
case KVM_IRQ_LINE: { case KVM_IRQ_LINE: {
struct kvm_irq_level irq_event; struct kvm_irq_level irq_event;
...@@ -3372,6 +3380,7 @@ static void kvm_free_vcpus(struct kvm *kvm) ...@@ -3372,6 +3380,7 @@ static void kvm_free_vcpus(struct kvm *kvm)
void kvm_arch_destroy_vm(struct kvm *kvm) void kvm_arch_destroy_vm(struct kvm *kvm)
{ {
kvm_free_pit(kvm);
kfree(kvm->arch.vpic); kfree(kvm->arch.vpic);
kfree(kvm->arch.vioapic); kfree(kvm->arch.vioapic);
kvm_free_vcpus(kvm); kvm_free_vcpus(kvm);
......
...@@ -298,6 +298,7 @@ struct kvm_arch{ ...@@ -298,6 +298,7 @@ struct kvm_arch{
struct list_head active_mmu_pages; struct list_head active_mmu_pages;
struct kvm_pic *vpic; struct kvm_pic *vpic;
struct kvm_ioapic *vioapic; struct kvm_ioapic *vioapic;
struct kvm_pit *vpit;
int round_robin_prev_vcpu; int round_robin_prev_vcpu;
unsigned int tss_addr; unsigned int tss_addr;
......
...@@ -236,6 +236,7 @@ struct kvm_vapic_addr { ...@@ -236,6 +236,7 @@ struct kvm_vapic_addr {
#define KVM_CAP_CLOCKSOURCE 8 #define KVM_CAP_CLOCKSOURCE 8
#define KVM_CAP_NR_VCPUS 9 /* returns max vcpus per vm */ #define KVM_CAP_NR_VCPUS 9 /* returns max vcpus per vm */
#define KVM_CAP_NR_MEMSLOTS 10 /* returns max memory slots per vm */ #define KVM_CAP_NR_MEMSLOTS 10 /* returns max memory slots per vm */
#define KVM_CAP_PIT 11
/* /*
* ioctls for VM fds * ioctls for VM fds
...@@ -258,6 +259,7 @@ struct kvm_vapic_addr { ...@@ -258,6 +259,7 @@ struct kvm_vapic_addr {
#define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level) #define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level)
#define KVM_GET_IRQCHIP _IOWR(KVMIO, 0x62, struct kvm_irqchip) #define KVM_GET_IRQCHIP _IOWR(KVMIO, 0x62, struct kvm_irqchip)
#define KVM_SET_IRQCHIP _IOR(KVMIO, 0x63, struct kvm_irqchip) #define KVM_SET_IRQCHIP _IOR(KVMIO, 0x63, struct kvm_irqchip)
#define KVM_CREATE_PIT _IO(KVMIO, 0x64)
/* /*
* ioctls for vcpu fds * ioctls for vcpu fds
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment