From b0fcd903e6f3f47189baddf3fe085bdf78c9644c Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 22 Jul 2007 18:48:54 +0300 Subject: KVM: Correctly handle writes crossing a page boundary Writes that are contiguous in virtual memory may not be contiguous in physical memory; so split writes that straddle a page boundary. Thanks to Aurelien for reporting the bug, patient testing, and a fix to this very patch. Signed-off-by: Aurelien Jarno Signed-off-by: Avi Kivity diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index bcbe683..a0a3fdd 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -1078,10 +1078,10 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, return 1; } -static int emulator_write_emulated(unsigned long addr, - const void *val, - unsigned int bytes, - struct x86_emulate_ctxt *ctxt) +static int emulator_write_emulated_onepage(unsigned long addr, + const void *val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) { struct kvm_vcpu *vcpu = ctxt->vcpu; struct kvm_io_device *mmio_dev; @@ -1113,6 +1113,26 @@ static int emulator_write_emulated(unsigned long addr, return X86EMUL_CONTINUE; } +static int emulator_write_emulated(unsigned long addr, + const void *val, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + /* Crossing a page boundary? */ + if (((addr + bytes - 1) ^ addr) & PAGE_MASK) { + int rc, now; + + now = -addr & ~PAGE_MASK; + rc = emulator_write_emulated_onepage(addr, val, now, ctxt); + if (rc != X86EMUL_CONTINUE) + return rc; + addr += now; + val += now; + bytes -= now; + } + return emulator_write_emulated_onepage(addr, val, bytes, ctxt); +} + static int emulator_cmpxchg_emulated(unsigned long addr, const void *old, const void *new, -- cgit v0.10.2 From 5e58cfe41c7e5902c32bb7f62993d43fb4c48ccf Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Mon, 23 Jul 2007 17:08:21 +1000 Subject: KVM: Fix unlikely kvm_create vs decache_vcpus_on_cpu race We add the kvm to the vm_list before initializing the vcpu mutexes, which can be mutex_trylock()'ed by decache_vcpus_on_cpu(). Signed-off-by: Rusty Russell Signed-off-by: Avi Kivity diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index a0a3fdd..46efbe7 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -297,9 +297,6 @@ static struct kvm *kvm_create_vm(void) kvm_io_bus_init(&kvm->pio_bus); spin_lock_init(&kvm->lock); INIT_LIST_HEAD(&kvm->active_mmu_pages); - spin_lock(&kvm_lock); - list_add(&kvm->vm_list, &vm_list); - spin_unlock(&kvm_lock); kvm_io_bus_init(&kvm->mmio_bus); for (i = 0; i < KVM_MAX_VCPUS; ++i) { struct kvm_vcpu *vcpu = &kvm->vcpus[i]; @@ -309,6 +306,9 @@ static struct kvm *kvm_create_vm(void) vcpu->kvm = kvm; vcpu->mmu.root_hpa = INVALID_PAGE; } + spin_lock(&kvm_lock); + list_add(&kvm->vm_list, &vm_list); + spin_unlock(&kvm_lock); return kvm; } -- cgit v0.10.2 From 7cfa4b0a43286b1da3afa4f5f99d52e65a8f30fc Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Mon, 23 Jul 2007 18:33:14 +0300 Subject: Revert "KVM: Avoid useless memory write when possible" This reverts commit a3c870bdce4d34332ebdba7eb9969592c4c6b243. While it does save useless updates, it (probably) defeats the fork detector, causing a massive performance loss. Signed-off-by: Avi Kivity diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index 46efbe7..a8d8db8 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -1070,10 +1070,8 @@ static int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, return 0; mark_page_dirty(vcpu->kvm, gpa >> PAGE_SHIFT); virt = kmap_atomic(page, KM_USER0); - if (memcmp(virt + offset_in_page(gpa), val, bytes)) { - kvm_mmu_pte_write(vcpu, gpa, virt + offset, val, bytes); - memcpy(virt + offset_in_page(gpa), val, bytes); - } + kvm_mmu_pte_write(vcpu, gpa, virt + offset, val, bytes); + memcpy(virt + offset_in_page(gpa), val, bytes); kunmap_atomic(virt, KM_USER0); return 1; } -- cgit v0.10.2 From 4c981b43d7ec18818754bf85b829865abd0ce340 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 25 Jul 2007 09:22:12 +0300 Subject: KVM: Fix removal of nx capability from guest cpuid Testing the wrong bit caused kvm not to disable nx on the guest when it is disabled on the host (an mmu optimization relies on the nx bits being the same in the guest and host). This allows Windows to boot when nx is disabled on te host (e.g. when host pae is disabled). Signed-off-by: Avi Kivity diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index a8d8db8..9685609 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -2432,9 +2432,9 @@ static void cpuid_fix_nx_cap(struct kvm_vcpu *vcpu) break; } } - if (entry && (entry->edx & EFER_NX) && !(efer & EFER_NX)) { + if (entry && (entry->edx & (1 << 20)) && !(efer & EFER_NX)) { entry->edx &= ~(1 << 20); - printk(KERN_INFO ": guest NX capability removed\n"); + printk(KERN_INFO "kvm: guest NX capability removed\n"); } } -- cgit v0.10.2 From d37c85571904a622cbabc7a2e04b8c919de75ac0 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Wed, 25 Jul 2007 10:19:54 +0200 Subject: KVM: disable writeback for 0x0f 0x01 instructions. 0x0f 0x01 instructions (ie lgdt, lidt, smsw, lmsw and invlpg) does not use writeback. This patch set no_wb=1 when emulating those instructions. This fixes a regression booting the FreeBSD kernel on AMD. Signed-off-by: Aurelien Jarno Signed-off-by: Avi Kivity diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index 1b800fc..1f979cb 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c @@ -1178,6 +1178,8 @@ pop_instruction: twobyte_insn: switch (b) { case 0x01: /* lgdt, lidt, lmsw */ + /* Disable writeback. */ + no_wb = 1; switch (modrm_reg) { u16 size; unsigned long address; -- cgit v0.10.2