diff options
Diffstat (limited to 'arch/x86/kvm/x86.c')
-rw-r--r-- | arch/x86/kvm/x86.c | 62 |
1 files changed, 13 insertions, 49 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 67f91764e99b..2a4f3a697343 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -2371,40 +2371,19 @@ int emulate_instruction(struct kvm_vcpu *vcpu, | |||
2371 | } | 2371 | } |
2372 | EXPORT_SYMBOL_GPL(emulate_instruction); | 2372 | EXPORT_SYMBOL_GPL(emulate_instruction); |
2373 | 2373 | ||
2374 | static void free_pio_guest_pages(struct kvm_vcpu *vcpu) | ||
2375 | { | ||
2376 | int i; | ||
2377 | |||
2378 | for (i = 0; i < ARRAY_SIZE(vcpu->arch.pio.guest_pages); ++i) | ||
2379 | if (vcpu->arch.pio.guest_pages[i]) { | ||
2380 | kvm_release_page_dirty(vcpu->arch.pio.guest_pages[i]); | ||
2381 | vcpu->arch.pio.guest_pages[i] = NULL; | ||
2382 | } | ||
2383 | } | ||
2384 | |||
2385 | static int pio_copy_data(struct kvm_vcpu *vcpu) | 2374 | static int pio_copy_data(struct kvm_vcpu *vcpu) |
2386 | { | 2375 | { |
2387 | void *p = vcpu->arch.pio_data; | 2376 | void *p = vcpu->arch.pio_data; |
2388 | void *q; | 2377 | gva_t q = vcpu->arch.pio.guest_gva; |
2389 | unsigned bytes; | 2378 | unsigned bytes; |
2390 | int nr_pages = vcpu->arch.pio.guest_pages[1] ? 2 : 1; | 2379 | int ret; |
2391 | 2380 | ||
2392 | q = vmap(vcpu->arch.pio.guest_pages, nr_pages, VM_READ|VM_WRITE, | ||
2393 | PAGE_KERNEL); | ||
2394 | if (!q) { | ||
2395 | free_pio_guest_pages(vcpu); | ||
2396 | return -ENOMEM; | ||
2397 | } | ||
2398 | q += vcpu->arch.pio.guest_page_offset; | ||
2399 | bytes = vcpu->arch.pio.size * vcpu->arch.pio.cur_count; | 2381 | bytes = vcpu->arch.pio.size * vcpu->arch.pio.cur_count; |
2400 | if (vcpu->arch.pio.in) | 2382 | if (vcpu->arch.pio.in) |
2401 | memcpy(q, p, bytes); | 2383 | ret = kvm_write_guest_virt(q, p, bytes, vcpu); |
2402 | else | 2384 | else |
2403 | memcpy(p, q, bytes); | 2385 | ret = kvm_read_guest_virt(q, p, bytes, vcpu); |
2404 | q -= vcpu->arch.pio.guest_page_offset; | 2386 | return ret; |
2405 | vunmap(q); | ||
2406 | free_pio_guest_pages(vcpu); | ||
2407 | return 0; | ||
2408 | } | 2387 | } |
2409 | 2388 | ||
2410 | int complete_pio(struct kvm_vcpu *vcpu) | 2389 | int complete_pio(struct kvm_vcpu *vcpu) |
@@ -2515,7 +2494,6 @@ int kvm_emulate_pio(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | |||
2515 | vcpu->arch.pio.in = in; | 2494 | vcpu->arch.pio.in = in; |
2516 | vcpu->arch.pio.string = 0; | 2495 | vcpu->arch.pio.string = 0; |
2517 | vcpu->arch.pio.down = 0; | 2496 | vcpu->arch.pio.down = 0; |
2518 | vcpu->arch.pio.guest_page_offset = 0; | ||
2519 | vcpu->arch.pio.rep = 0; | 2497 | vcpu->arch.pio.rep = 0; |
2520 | 2498 | ||
2521 | if (vcpu->run->io.direction == KVM_EXIT_IO_IN) | 2499 | if (vcpu->run->io.direction == KVM_EXIT_IO_IN) |
@@ -2543,9 +2521,7 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | |||
2543 | gva_t address, int rep, unsigned port) | 2521 | gva_t address, int rep, unsigned port) |
2544 | { | 2522 | { |
2545 | unsigned now, in_page; | 2523 | unsigned now, in_page; |
2546 | int i, ret = 0; | 2524 | int ret = 0; |
2547 | int nr_pages = 1; | ||
2548 | struct page *page; | ||
2549 | struct kvm_io_device *pio_dev; | 2525 | struct kvm_io_device *pio_dev; |
2550 | 2526 | ||
2551 | vcpu->run->exit_reason = KVM_EXIT_IO; | 2527 | vcpu->run->exit_reason = KVM_EXIT_IO; |
@@ -2557,7 +2533,6 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | |||
2557 | vcpu->arch.pio.in = in; | 2533 | vcpu->arch.pio.in = in; |
2558 | vcpu->arch.pio.string = 1; | 2534 | vcpu->arch.pio.string = 1; |
2559 | vcpu->arch.pio.down = down; | 2535 | vcpu->arch.pio.down = down; |
2560 | vcpu->arch.pio.guest_page_offset = offset_in_page(address); | ||
2561 | vcpu->arch.pio.rep = rep; | 2536 | vcpu->arch.pio.rep = rep; |
2562 | 2537 | ||
2563 | if (vcpu->run->io.direction == KVM_EXIT_IO_IN) | 2538 | if (vcpu->run->io.direction == KVM_EXIT_IO_IN) |
@@ -2577,15 +2552,8 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | |||
2577 | else | 2552 | else |
2578 | in_page = offset_in_page(address) + size; | 2553 | in_page = offset_in_page(address) + size; |
2579 | now = min(count, (unsigned long)in_page / size); | 2554 | now = min(count, (unsigned long)in_page / size); |
2580 | if (!now) { | 2555 | if (!now) |
2581 | /* | ||
2582 | * String I/O straddles page boundary. Pin two guest pages | ||
2583 | * so that we satisfy atomicity constraints. Do just one | ||
2584 | * transaction to avoid complexity. | ||
2585 | */ | ||
2586 | nr_pages = 2; | ||
2587 | now = 1; | 2556 | now = 1; |
2588 | } | ||
2589 | if (down) { | 2557 | if (down) { |
2590 | /* | 2558 | /* |
2591 | * String I/O in reverse. Yuck. Kill the guest, fix later. | 2559 | * String I/O in reverse. Yuck. Kill the guest, fix later. |
@@ -2600,15 +2568,7 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | |||
2600 | if (vcpu->arch.pio.cur_count == vcpu->arch.pio.count) | 2568 | if (vcpu->arch.pio.cur_count == vcpu->arch.pio.count) |
2601 | kvm_x86_ops->skip_emulated_instruction(vcpu); | 2569 | kvm_x86_ops->skip_emulated_instruction(vcpu); |
2602 | 2570 | ||
2603 | for (i = 0; i < nr_pages; ++i) { | 2571 | vcpu->arch.pio.guest_gva = address; |
2604 | page = gva_to_page(vcpu, address + i * PAGE_SIZE); | ||
2605 | vcpu->arch.pio.guest_pages[i] = page; | ||
2606 | if (!page) { | ||
2607 | kvm_inject_gp(vcpu, 0); | ||
2608 | free_pio_guest_pages(vcpu); | ||
2609 | return 1; | ||
2610 | } | ||
2611 | } | ||
2612 | 2572 | ||
2613 | pio_dev = vcpu_find_pio_dev(vcpu, port, | 2573 | pio_dev = vcpu_find_pio_dev(vcpu, port, |
2614 | vcpu->arch.pio.cur_count, | 2574 | vcpu->arch.pio.cur_count, |
@@ -2616,7 +2576,11 @@ int kvm_emulate_pio_string(struct kvm_vcpu *vcpu, struct kvm_run *run, int in, | |||
2616 | if (!vcpu->arch.pio.in) { | 2576 | if (!vcpu->arch.pio.in) { |
2617 | /* string PIO write */ | 2577 | /* string PIO write */ |
2618 | ret = pio_copy_data(vcpu); | 2578 | ret = pio_copy_data(vcpu); |
2619 | if (ret >= 0 && pio_dev) { | 2579 | if (ret == X86EMUL_PROPAGATE_FAULT) { |
2580 | kvm_inject_gp(vcpu, 0); | ||
2581 | return 1; | ||
2582 | } | ||
2583 | if (ret == 0 && pio_dev) { | ||
2620 | pio_string_write(pio_dev, vcpu); | 2584 | pio_string_write(pio_dev, vcpu); |
2621 | complete_pio(vcpu); | 2585 | complete_pio(vcpu); |
2622 | if (vcpu->arch.pio.count == 0) | 2586 | if (vcpu->arch.pio.count == 0) |