diff options
author | Eddie Dong <eddie.dong@intel.com> | 2007-09-12 03:58:04 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-10-13 04:18:25 -0400 |
commit | 97222cc8316328965851ed28d23f6b64b4c912d2 (patch) | |
tree | 469b2f72e74046a7aec5061df194c3f68812a224 /drivers/kvm/kvm_main.c | |
parent | 7017fc3d1a12e30ea7df4992152978a188433457 (diff) |
KVM: Emulate local APIC in kernel
Because lightweight exits (exits which don't involve userspace) are many
times faster than heavyweight exits, it makes sense to emulate high usage
devices in the kernel. The local APIC is one such device, especially for
Windows and for SMP, so we add an APIC model to kvm.
It also allows in-kernel host-side drivers to inject interrupts without
going through userspace.
[compile fix on i386 from Jindrich Makovicka]
Signed-off-by: Yaozu (Eddie) Dong <Eddie.Dong@intel.com>
Signed-off-by: Qing He <qing.he@intel.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/kvm_main.c')
-rw-r--r-- | drivers/kvm/kvm_main.c | 52 |
1 files changed, 42 insertions, 10 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index f879efbefcdf..401e3cdc4607 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -281,6 +281,7 @@ EXPORT_SYMBOL_GPL(kvm_vcpu_init); | |||
281 | void kvm_vcpu_uninit(struct kvm_vcpu *vcpu) | 281 | void kvm_vcpu_uninit(struct kvm_vcpu *vcpu) |
282 | { | 282 | { |
283 | kvm_mmu_destroy(vcpu); | 283 | kvm_mmu_destroy(vcpu); |
284 | kvm_free_apic(vcpu->apic); | ||
284 | free_page((unsigned long)vcpu->pio_data); | 285 | free_page((unsigned long)vcpu->pio_data); |
285 | free_page((unsigned long)vcpu->run); | 286 | free_page((unsigned long)vcpu->run); |
286 | } | 287 | } |
@@ -598,25 +599,38 @@ void set_cr8(struct kvm_vcpu *vcpu, unsigned long cr8) | |||
598 | inject_gp(vcpu); | 599 | inject_gp(vcpu); |
599 | return; | 600 | return; |
600 | } | 601 | } |
601 | vcpu->cr8 = cr8; | 602 | if (irqchip_in_kernel(vcpu->kvm)) |
603 | kvm_lapic_set_tpr(vcpu, cr8); | ||
604 | else | ||
605 | vcpu->cr8 = cr8; | ||
602 | } | 606 | } |
603 | EXPORT_SYMBOL_GPL(set_cr8); | 607 | EXPORT_SYMBOL_GPL(set_cr8); |
604 | 608 | ||
605 | unsigned long get_cr8(struct kvm_vcpu *vcpu) | 609 | unsigned long get_cr8(struct kvm_vcpu *vcpu) |
606 | { | 610 | { |
607 | return vcpu->cr8; | 611 | if (irqchip_in_kernel(vcpu->kvm)) |
612 | return kvm_lapic_get_cr8(vcpu); | ||
613 | else | ||
614 | return vcpu->cr8; | ||
608 | } | 615 | } |
609 | EXPORT_SYMBOL_GPL(get_cr8); | 616 | EXPORT_SYMBOL_GPL(get_cr8); |
610 | 617 | ||
611 | u64 kvm_get_apic_base(struct kvm_vcpu *vcpu) | 618 | u64 kvm_get_apic_base(struct kvm_vcpu *vcpu) |
612 | { | 619 | { |
613 | return vcpu->apic_base; | 620 | if (irqchip_in_kernel(vcpu->kvm)) |
621 | return vcpu->apic_base; | ||
622 | else | ||
623 | return vcpu->apic_base; | ||
614 | } | 624 | } |
615 | EXPORT_SYMBOL_GPL(kvm_get_apic_base); | 625 | EXPORT_SYMBOL_GPL(kvm_get_apic_base); |
616 | 626 | ||
617 | void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data) | 627 | void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data) |
618 | { | 628 | { |
619 | vcpu->apic_base = data; | 629 | /* TODO: reserve bits check */ |
630 | if (irqchip_in_kernel(vcpu->kvm)) | ||
631 | kvm_lapic_set_base(vcpu, data); | ||
632 | else | ||
633 | vcpu->apic_base = data; | ||
620 | } | 634 | } |
621 | EXPORT_SYMBOL_GPL(kvm_set_apic_base); | 635 | EXPORT_SYMBOL_GPL(kvm_set_apic_base); |
622 | 636 | ||
@@ -986,15 +1000,31 @@ static int emulator_write_std(unsigned long addr, | |||
986 | return X86EMUL_UNHANDLEABLE; | 1000 | return X86EMUL_UNHANDLEABLE; |
987 | } | 1001 | } |
988 | 1002 | ||
1003 | /* | ||
1004 | * Only apic need an MMIO device hook, so shortcut now.. | ||
1005 | */ | ||
1006 | static struct kvm_io_device *vcpu_find_pervcpu_dev(struct kvm_vcpu *vcpu, | ||
1007 | gpa_t addr) | ||
1008 | { | ||
1009 | struct kvm_io_device *dev; | ||
1010 | |||
1011 | if (vcpu->apic) { | ||
1012 | dev = &vcpu->apic->dev; | ||
1013 | if (dev->in_range(dev, addr)) | ||
1014 | return dev; | ||
1015 | } | ||
1016 | return NULL; | ||
1017 | } | ||
1018 | |||
989 | static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, | 1019 | static struct kvm_io_device *vcpu_find_mmio_dev(struct kvm_vcpu *vcpu, |
990 | gpa_t addr) | 1020 | gpa_t addr) |
991 | { | 1021 | { |
992 | /* | 1022 | struct kvm_io_device *dev; |
993 | * Note that its important to have this wrapper function because | 1023 | |
994 | * in the very near future we will be checking for MMIOs against | 1024 | dev = vcpu_find_pervcpu_dev(vcpu, addr); |
995 | * the LAPIC as well as the general MMIO bus | 1025 | if (dev == NULL) |
996 | */ | 1026 | dev = kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); |
997 | return kvm_io_bus_find_dev(&vcpu->kvm->mmio_bus, addr); | 1027 | return dev; |
998 | } | 1028 | } |
999 | 1029 | ||
1000 | static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, | 1030 | static struct kvm_io_device *vcpu_find_pio_dev(struct kvm_vcpu *vcpu, |
@@ -2256,6 +2286,8 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, | |||
2256 | { | 2286 | { |
2257 | if (irq->irq < 0 || irq->irq >= 256) | 2287 | if (irq->irq < 0 || irq->irq >= 256) |
2258 | return -EINVAL; | 2288 | return -EINVAL; |
2289 | if (irqchip_in_kernel(vcpu->kvm)) | ||
2290 | return -ENXIO; | ||
2259 | vcpu_load(vcpu); | 2291 | vcpu_load(vcpu); |
2260 | 2292 | ||
2261 | set_bit(irq->irq, vcpu->irq_pending); | 2293 | set_bit(irq->irq, vcpu->irq_pending); |