aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorEddie Dong <eddie.dong@intel.com>2007-07-18 05:15:21 -0400
committerAvi Kivity <avi@qumranet.com>2007-10-13 04:18:25 -0400
commitb6958ce44a11a9e9425d2b67a653b1ca2a27796f (patch)
tree503478ef27254df9b6ea21d2a6a279a7dfe2ef04 /drivers
parent1fd4f2a5ed8f80cf6e23d2bdf78554f6a1ac7997 (diff)
KVM: Emulate hlt in the kernel
By sleeping in the kernel when hlt is executed, we simplify the in-kernel guest interrupt path considerably. Signed-off-by: Gregory Haskins <ghaskins@novell.com> Signed-off-by: Yaozu (Eddie) Dong <eddie.dong@intel.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/kvm/i8259.c3
-rw-r--r--drivers/kvm/irq.c4
-rw-r--r--drivers/kvm/kvm.h2
-rw-r--r--drivers/kvm/kvm_main.c41
-rw-r--r--drivers/kvm/svm.c9
-rw-r--r--drivers/kvm/vmx.c8
6 files changed, 56 insertions, 11 deletions
diff --git a/drivers/kvm/i8259.c b/drivers/kvm/i8259.c
index 40ad10462238..ee6030dc5c04 100644
--- a/drivers/kvm/i8259.c
+++ b/drivers/kvm/i8259.c
@@ -413,8 +413,11 @@ static void picdev_read(struct kvm_io_device *this,
413static void pic_irq_request(void *opaque, int level) 413static void pic_irq_request(void *opaque, int level)
414{ 414{
415 struct kvm *kvm = opaque; 415 struct kvm *kvm = opaque;
416 struct kvm_vcpu *vcpu = kvm->vcpus[0];
416 417
417 pic_irqchip(kvm)->output = level; 418 pic_irqchip(kvm)->output = level;
419 if (vcpu)
420 kvm_vcpu_kick(vcpu);
418} 421}
419 422
420struct kvm_pic *kvm_create_pic(struct kvm *kvm) 423struct kvm_pic *kvm_create_pic(struct kvm *kvm)
diff --git a/drivers/kvm/irq.c b/drivers/kvm/irq.c
index 5265f8267b3b..e09cd65925d6 100644
--- a/drivers/kvm/irq.c
+++ b/drivers/kvm/irq.c
@@ -70,6 +70,10 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu)
70{ 70{
71 int ipi_pcpu = vcpu->cpu; 71 int ipi_pcpu = vcpu->cpu;
72 72
73 if (waitqueue_active(&vcpu->wq)) {
74 wake_up_interruptible(&vcpu->wq);
75 ++vcpu->stat.halt_wakeup;
76 }
73 if (vcpu->guest_mode) 77 if (vcpu->guest_mode)
74 smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0); 78 smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0);
75} 79}
diff --git a/drivers/kvm/kvm.h b/drivers/kvm/kvm.h
index 8d07a993af94..bb506b71797d 100644
--- a/drivers/kvm/kvm.h
+++ b/drivers/kvm/kvm.h
@@ -231,6 +231,7 @@ struct kvm_stat {
231 u32 signal_exits; 231 u32 signal_exits;
232 u32 irq_window_exits; 232 u32 irq_window_exits;
233 u32 halt_exits; 233 u32 halt_exits;
234 u32 halt_wakeup;
234 u32 request_irq_exits; 235 u32 request_irq_exits;
235 u32 irq_exits; 236 u32 irq_exits;
236 u32 light_exits; 237 u32 light_exits;
@@ -353,6 +354,7 @@ struct kvm_vcpu {
353 gva_t mmio_fault_cr2; 354 gva_t mmio_fault_cr2;
354 struct kvm_pio_request pio; 355 struct kvm_pio_request pio;
355 void *pio_data; 356 void *pio_data;
357 wait_queue_head_t wq;
356 358
357 int sigset_active; 359 int sigset_active;
358 sigset_t sigset; 360 sigset_t sigset;
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index ffbdadd87971..4384364fc0c8 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -76,6 +76,7 @@ static struct kvm_stats_debugfs_item {
76 { "signal_exits", STAT_OFFSET(signal_exits) }, 76 { "signal_exits", STAT_OFFSET(signal_exits) },
77 { "irq_window", STAT_OFFSET(irq_window_exits) }, 77 { "irq_window", STAT_OFFSET(irq_window_exits) },
78 { "halt_exits", STAT_OFFSET(halt_exits) }, 78 { "halt_exits", STAT_OFFSET(halt_exits) },
79 { "halt_wakeup", STAT_OFFSET(halt_wakeup) },
79 { "request_irq", STAT_OFFSET(request_irq_exits) }, 80 { "request_irq", STAT_OFFSET(request_irq_exits) },
80 { "irq_exits", STAT_OFFSET(irq_exits) }, 81 { "irq_exits", STAT_OFFSET(irq_exits) },
81 { "light_exits", STAT_OFFSET(light_exits) }, 82 { "light_exits", STAT_OFFSET(light_exits) },
@@ -248,6 +249,7 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
248 vcpu->mmu.root_hpa = INVALID_PAGE; 249 vcpu->mmu.root_hpa = INVALID_PAGE;
249 vcpu->kvm = kvm; 250 vcpu->kvm = kvm;
250 vcpu->vcpu_id = id; 251 vcpu->vcpu_id = id;
252 init_waitqueue_head(&vcpu->wq);
251 253
252 page = alloc_page(GFP_KERNEL | __GFP_ZERO); 254 page = alloc_page(GFP_KERNEL | __GFP_ZERO);
253 if (!page) { 255 if (!page) {
@@ -1307,15 +1309,41 @@ int emulate_instruction(struct kvm_vcpu *vcpu,
1307} 1309}
1308EXPORT_SYMBOL_GPL(emulate_instruction); 1310EXPORT_SYMBOL_GPL(emulate_instruction);
1309 1311
1310int kvm_emulate_halt(struct kvm_vcpu *vcpu) 1312/*
1313 * The vCPU has executed a HLT instruction with in-kernel mode enabled.
1314 */
1315static void kvm_vcpu_kernel_halt(struct kvm_vcpu *vcpu)
1311{ 1316{
1312 if (vcpu->irq_summary || 1317 DECLARE_WAITQUEUE(wait, current);
1313 (irqchip_in_kernel(vcpu->kvm) && kvm_cpu_has_interrupt(vcpu))) 1318
1314 return 1; 1319 add_wait_queue(&vcpu->wq, &wait);
1320
1321 /*
1322 * We will block until either an interrupt or a signal wakes us up
1323 */
1324 while(!(irqchip_in_kernel(vcpu->kvm) && kvm_cpu_has_interrupt(vcpu))
1325 && !vcpu->irq_summary
1326 && !signal_pending(current)) {
1327 set_current_state(TASK_INTERRUPTIBLE);
1328 vcpu_put(vcpu);
1329 schedule();
1330 vcpu_load(vcpu);
1331 }
1315 1332
1316 vcpu->run->exit_reason = KVM_EXIT_HLT; 1333 remove_wait_queue(&vcpu->wq, &wait);
1334 set_current_state(TASK_RUNNING);
1335}
1336
1337int kvm_emulate_halt(struct kvm_vcpu *vcpu)
1338{
1317 ++vcpu->stat.halt_exits; 1339 ++vcpu->stat.halt_exits;
1318 return 0; 1340 if (irqchip_in_kernel(vcpu->kvm)) {
1341 kvm_vcpu_kernel_halt(vcpu);
1342 return 1;
1343 } else {
1344 vcpu->run->exit_reason = KVM_EXIT_HLT;
1345 return 0;
1346 }
1319} 1347}
1320EXPORT_SYMBOL_GPL(kvm_emulate_halt); 1348EXPORT_SYMBOL_GPL(kvm_emulate_halt);
1321 1349
@@ -2916,6 +2944,7 @@ static long kvm_dev_ioctl(struct file *filp,
2916 2944
2917 switch (ext) { 2945 switch (ext) {
2918 case KVM_CAP_IRQCHIP: 2946 case KVM_CAP_IRQCHIP:
2947 case KVM_CAP_HLT:
2919 r = 1; 2948 r = 1;
2920 break; 2949 break;
2921 default: 2950 default:
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index d576451827e7..a347b61644cd 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -1398,9 +1398,12 @@ static void do_interrupt_requests(struct vcpu_svm *svm,
1398static void post_kvm_run_save(struct vcpu_svm *svm, 1398static void post_kvm_run_save(struct vcpu_svm *svm,
1399 struct kvm_run *kvm_run) 1399 struct kvm_run *kvm_run)
1400{ 1400{
1401 kvm_run->ready_for_interrupt_injection 1401 if (irqchip_in_kernel(svm->vcpu.kvm))
1402 = (svm->vcpu.interrupt_window_open && 1402 kvm_run->ready_for_interrupt_injection = 1;
1403 svm->vcpu.irq_summary == 0); 1403 else
1404 kvm_run->ready_for_interrupt_injection =
1405 (svm->vcpu.interrupt_window_open &&
1406 svm->vcpu.irq_summary == 0);
1404 kvm_run->if_flag = (svm->vmcb->save.rflags & X86_EFLAGS_IF) != 0; 1407 kvm_run->if_flag = (svm->vmcb->save.rflags & X86_EFLAGS_IF) != 0;
1405 kvm_run->cr8 = get_cr8(&svm->vcpu); 1408 kvm_run->cr8 = get_cr8(&svm->vcpu);
1406 kvm_run->apic_base = kvm_get_apic_base(&svm->vcpu); 1409 kvm_run->apic_base = kvm_get_apic_base(&svm->vcpu);
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c
index c4cc17cc00f7..7ec8cf84e6ea 100644
--- a/drivers/kvm/vmx.c
+++ b/drivers/kvm/vmx.c
@@ -1961,8 +1961,12 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu,
1961 kvm_run->if_flag = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) != 0; 1961 kvm_run->if_flag = (vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) != 0;
1962 kvm_run->cr8 = get_cr8(vcpu); 1962 kvm_run->cr8 = get_cr8(vcpu);
1963 kvm_run->apic_base = kvm_get_apic_base(vcpu); 1963 kvm_run->apic_base = kvm_get_apic_base(vcpu);
1964 kvm_run->ready_for_interrupt_injection = (vcpu->interrupt_window_open && 1964 if (irqchip_in_kernel(vcpu->kvm))
1965 vcpu->irq_summary == 0); 1965 kvm_run->ready_for_interrupt_injection = 1;
1966 else
1967 kvm_run->ready_for_interrupt_injection =
1968 (vcpu->interrupt_window_open &&
1969 vcpu->irq_summary == 0);
1966} 1970}
1967 1971
1968static int handle_interrupt_window(struct kvm_vcpu *vcpu, 1972static int handle_interrupt_window(struct kvm_vcpu *vcpu,