diff options
author | Eddie Dong <eddie.dong@intel.com> | 2007-07-06 05:20:49 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2007-10-13 04:18:24 -0400 |
commit | 85f455f7ddbed403b34b4d54b1eaf0e14126a126 (patch) | |
tree | 1dba7aa8fee3c8f756e12049c496dee5baae752c /drivers/kvm/svm.c | |
parent | 152d3f2f246ce3c2a0cf2fc6c2214663cd99aa83 (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.c | 69 |
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) | |||
1185 | static int interrupt_window_interception(struct vcpu_svm *svm, | 1187 | static 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 | ||
1292 | static inline void inject_irq(struct vcpu_svm *svm) | 1296 | static 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 | ||
1303 | static void reput_irq(struct vcpu_svm *svm) | 1307 | static 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 | |||
1340 | static 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 | ||
1354 | static 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 | |||
1316 | static void do_interrupt_requests(struct vcpu_svm *svm, | 1367 | static 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 | ||