aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm/svm.c
diff options
context:
space:
mode:
authorEddie Dong <eddie.dong@intel.com>2007-07-06 05:20:49 -0400
committerAvi Kivity <avi@qumranet.com>2007-10-13 04:18:24 -0400
commit85f455f7ddbed403b34b4d54b1eaf0e14126a126 (patch)
tree1dba7aa8fee3c8f756e12049c496dee5baae752c /drivers/kvm/svm.c
parent152d3f2f246ce3c2a0cf2fc6c2214663cd99aa83 (diff)
KVM: Add support for in-kernel PIC emulation
Signed-off-by: Yaozu (Eddie) Dong <eddie.dong@intel.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers/kvm/svm.c')
-rw-r--r--drivers/kvm/svm.c69
1 files changed, 61 insertions, 8 deletions
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c
index cc674bfd31d9..2237a594a8ef 100644
--- a/drivers/kvm/svm.c
+++ b/drivers/kvm/svm.c
@@ -16,6 +16,7 @@
16 16
17#include "kvm_svm.h" 17#include "kvm_svm.h"
18#include "x86_emulate.h" 18#include "x86_emulate.h"
19#include "irq.h"
19 20
20#include <linux/module.h> 21#include <linux/module.h>
21#include <linux/kernel.h> 22#include <linux/kernel.h>
@@ -921,7 +922,8 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
921 enum emulation_result er; 922 enum emulation_result er;
922 int r; 923 int r;
923 924
924 if (is_external_interrupt(exit_int_info)) 925 if (!irqchip_in_kernel(kvm) &&
926 is_external_interrupt(exit_int_info))
925 push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK); 927 push_irq(&svm->vcpu, exit_int_info & SVM_EVTINJ_VEC_MASK);
926 928
927 mutex_lock(&kvm->lock); 929 mutex_lock(&kvm->lock);
@@ -1185,6 +1187,8 @@ static int msr_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run)
1185static int interrupt_window_interception(struct vcpu_svm *svm, 1187static int interrupt_window_interception(struct vcpu_svm *svm,
1186 struct kvm_run *kvm_run) 1188 struct kvm_run *kvm_run)
1187{ 1189{
1190 svm->vmcb->control.intercept &= ~(1ULL << INTERCEPT_VINTR);
1191 svm->vmcb->control.int_ctl &= ~V_IRQ_MASK;
1188 /* 1192 /*
1189 * If the user space waits to inject interrupts, exit as soon as 1193 * If the user space waits to inject interrupts, exit as soon as
1190 * possible 1194 * possible
@@ -1289,22 +1293,56 @@ static void pre_svm_run(struct vcpu_svm *svm)
1289} 1293}
1290 1294
1291 1295
1292static inline void inject_irq(struct vcpu_svm *svm) 1296static inline void svm_inject_irq(struct vcpu_svm *svm, int irq)
1293{ 1297{
1294 struct vmcb_control_area *control; 1298 struct vmcb_control_area *control;
1295 1299
1296 control = &svm->vmcb->control; 1300 control = &svm->vmcb->control;
1297 control->int_vector = pop_irq(&svm->vcpu); 1301 control->int_vector = irq;
1298 control->int_ctl &= ~V_INTR_PRIO_MASK; 1302 control->int_ctl &= ~V_INTR_PRIO_MASK;
1299 control->int_ctl |= V_IRQ_MASK | 1303 control->int_ctl |= V_IRQ_MASK |
1300 ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT); 1304 ((/*control->int_vector >> 4*/ 0xf) << V_INTR_PRIO_SHIFT);
1301} 1305}
1302 1306
1303static void reput_irq(struct vcpu_svm *svm) 1307static void svm_intr_assist(struct vcpu_svm *svm)
1304{ 1308{
1309 struct vmcb *vmcb = svm->vmcb;
1310 int intr_vector = -1;
1311
1312 if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) &&
1313 ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) {
1314 intr_vector = vmcb->control.exit_int_info &
1315 SVM_EVTINJ_VEC_MASK;
1316 vmcb->control.exit_int_info = 0;
1317 svm_inject_irq(svm, intr_vector);
1318 return;
1319 }
1320
1321 if (vmcb->control.int_ctl & V_IRQ_MASK)
1322 return;
1323
1324 if (!kvm_cpu_has_interrupt(&svm->vcpu))
1325 return;
1326
1327 if (!(vmcb->save.rflags & X86_EFLAGS_IF) ||
1328 (vmcb->control.int_state & SVM_INTERRUPT_SHADOW_MASK) ||
1329 (vmcb->control.event_inj & SVM_EVTINJ_VALID)) {
1330 /* unable to deliver irq, set pending irq */
1331 vmcb->control.intercept |= (1ULL << INTERCEPT_VINTR);
1332 svm_inject_irq(svm, 0x0);
1333 return;
1334 }
1335 /* Okay, we can deliver the interrupt: grab it and update PIC state. */
1336 intr_vector = kvm_cpu_get_interrupt(&svm->vcpu);
1337 svm_inject_irq(svm, intr_vector);
1338}
1339
1340static void kvm_reput_irq(struct vcpu_svm *svm)
1341{
1342 struct kvm_vcpu *vcpu = &svm->vcpu;
1305 struct vmcb_control_area *control = &svm->vmcb->control; 1343 struct vmcb_control_area *control = &svm->vmcb->control;
1306 1344
1307 if (control->int_ctl & V_IRQ_MASK) { 1345 if ((control->int_ctl & V_IRQ_MASK) && !irqchip_in_kernel(vcpu->kvm)) {
1308 control->int_ctl &= ~V_IRQ_MASK; 1346 control->int_ctl &= ~V_IRQ_MASK;
1309 push_irq(&svm->vcpu, control->int_vector); 1347 push_irq(&svm->vcpu, control->int_vector);
1310 } 1348 }
@@ -1313,6 +1351,19 @@ static void reput_irq(struct vcpu_svm *svm)
1313 !(control->int_state & SVM_INTERRUPT_SHADOW_MASK); 1351 !(control->int_state & SVM_INTERRUPT_SHADOW_MASK);
1314} 1352}
1315 1353
1354static void svm_do_inject_vector(struct vcpu_svm *svm)
1355{
1356 struct kvm_vcpu *vcpu = &svm->vcpu;
1357 int word_index = __ffs(vcpu->irq_summary);
1358 int bit_index = __ffs(vcpu->irq_pending[word_index]);
1359 int irq = word_index * BITS_PER_LONG + bit_index;
1360
1361 clear_bit(bit_index, &vcpu->irq_pending[word_index]);
1362 if (!vcpu->irq_pending[word_index])
1363 clear_bit(word_index, &vcpu->irq_summary);
1364 svm_inject_irq(svm, irq);
1365}
1366
1316static void do_interrupt_requests(struct vcpu_svm *svm, 1367static void do_interrupt_requests(struct vcpu_svm *svm,
1317 struct kvm_run *kvm_run) 1368 struct kvm_run *kvm_run)
1318{ 1369{
@@ -1326,7 +1377,7 @@ static void do_interrupt_requests(struct vcpu_svm *svm,
1326 /* 1377 /*
1327 * If interrupts enabled, and not blocked by sti or mov ss. Good. 1378 * If interrupts enabled, and not blocked by sti or mov ss. Good.
1328 */ 1379 */
1329 inject_irq(svm); 1380 svm_do_inject_vector(svm);
1330 1381
1331 /* 1382 /*
1332 * Interrupts blocked. Wait for unblock. 1383 * Interrupts blocked. Wait for unblock.
@@ -1408,7 +1459,9 @@ again:
1408 return -EINTR; 1459 return -EINTR;
1409 } 1460 }
1410 1461
1411 if (!vcpu->mmio_read_completed) 1462 if (irqchip_in_kernel(vcpu->kvm))
1463 svm_intr_assist(svm);
1464 else if (!vcpu->mmio_read_completed)
1412 do_interrupt_requests(svm, kvm_run); 1465 do_interrupt_requests(svm, kvm_run);
1413 1466
1414 vcpu->guest_mode = 1; 1467 vcpu->guest_mode = 1;
@@ -1576,7 +1629,7 @@ again:
1576 1629
1577 stgi(); 1630 stgi();
1578 1631
1579 reput_irq(svm); 1632 kvm_reput_irq(svm);
1580 1633
1581 svm->next_rip = 0; 1634 svm->next_rip = 0;
1582 1635