[COMMIT master] KVM: x86: ignore access permissions for hypercall patching
From: Marcelo Tosatti mtosa...@redhat.com Ignore access permissions while patching hypercall instructions. Otherwise KVM injects a page fault when trying to patch vmcall on read-only text regions: Freeing initrd memory: 8843k freed Freeing unused kernel memory: 660k freed Write protecting the kernel text: 4780k Write protecting the kernel read-only data: 1912k BUG: unable to handle kernel paging request at c01292e3 IP: [c01292e3] kvm_leave_lazy_mmu+0x43/0x70 *pde = 00910067 *pte = 00129161 Oops: 0003 [#1] SMP CC: sta...@kernel.org Reported-and-Tested-by: Stefan Bader stefan.ba...@canonical.com Signed-off-by: Marcelo Tosatti mtosa...@redhat.com diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index bcf52d1..9d02cc7 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3226,12 +3226,17 @@ int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, static int emulator_write_emulated_onepage(unsigned long addr, const void *val, unsigned int bytes, - struct kvm_vcpu *vcpu) + struct kvm_vcpu *vcpu, + bool guest_initiated) { gpa_t gpa; u32 error_code; - gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error_code); + + if (guest_initiated) + gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error_code); + else + gpa = kvm_mmu_gva_to_gpa_system(vcpu, addr, error_code); if (gpa == UNMAPPED_GVA) { kvm_inject_page_fault(vcpu, addr, error_code); @@ -3262,24 +3267,35 @@ mmio: return X86EMUL_CONTINUE; } -int emulator_write_emulated(unsigned long addr, +int __emulator_write_emulated(unsigned long addr, const void *val, unsigned int bytes, - struct kvm_vcpu *vcpu) + struct kvm_vcpu *vcpu, + bool guest_initiated) { /* 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, vcpu); + rc = emulator_write_emulated_onepage(addr, val, now, vcpu, +guest_initiated); if (rc != X86EMUL_CONTINUE) return rc; addr += now; val += now; bytes -= now; } - return emulator_write_emulated_onepage(addr, val, bytes, vcpu); + return emulator_write_emulated_onepage(addr, val, bytes, vcpu, + guest_initiated); +} + +int emulator_write_emulated(unsigned long addr, + const void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu) +{ + return __emulator_write_emulated(addr, val, bytes, vcpu, true); } EXPORT_SYMBOL_GPL(emulator_write_emulated); @@ -3970,7 +3986,7 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu) kvm_x86_ops-patch_hypercall(vcpu, instruction); - return emulator_write_emulated(rip, instruction, 3, vcpu); + return __emulator_write_emulated(rip, instruction, 3, vcpu, false); } static u64 mk_cr_64(u64 curr_cr, u32 new_val) -- To unsubscribe from this list: send the line unsubscribe kvm-commits in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[COMMIT master] Revert KVM: x86: ignore access permissions for hypercall patching
From: Marcelo Tosatti mtosa...@redhat.com Its safer to disable the only problematic user of hypercall patching, pvmmu. Signed-off-by: Marcelo Tosatti mtosa...@redhat.com diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 68e8c89..bb9a24a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3243,17 +3243,12 @@ static int emulator_write_emulated_onepage(unsigned long addr, const void *val, unsigned int bytes, struct kvm_vcpu *vcpu, - bool guest_initiated, bool mmu_only) { gpa_t gpa; u32 error_code; - - if (guest_initiated) - gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error_code); - else - gpa = kvm_mmu_gva_to_gpa_system(vcpu, addr, error_code); + gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error_code); if (gpa == UNMAPPED_GVA) { kvm_inject_page_fault(vcpu, addr, error_code); @@ -3292,7 +3287,6 @@ int __emulator_write_emulated(unsigned long addr, const void *val, unsigned int bytes, struct kvm_vcpu *vcpu, - bool guest_initiated, bool mmu_only) { /* Crossing a page boundary? */ @@ -3301,7 +3295,7 @@ int __emulator_write_emulated(unsigned long addr, now = -addr ~PAGE_MASK; rc = emulator_write_emulated_onepage(addr, val, now, vcpu, -guest_initiated, mmu_only); +mmu_only); if (rc != X86EMUL_CONTINUE) return rc; addr += now; @@ -3309,7 +3303,7 @@ int __emulator_write_emulated(unsigned long addr, bytes -= now; } return emulator_write_emulated_onepage(addr, val, bytes, vcpu, - guest_initiated, mmu_only); + mmu_only); } int emulator_write_emulated(unsigned long addr, @@ -3317,7 +3311,7 @@ int emulator_write_emulated(unsigned long addr, unsigned int bytes, struct kvm_vcpu *vcpu) { - return __emulator_write_emulated(addr, val, bytes, vcpu, true, false); + return __emulator_write_emulated(addr, val, bytes, vcpu, false); } EXPORT_SYMBOL_GPL(emulator_write_emulated); @@ -3381,7 +3375,7 @@ static int emulator_cmpxchg_emulated(unsigned long addr, if (!exchanged) return X86EMUL_CMPXCHG_FAILED; - return __emulator_write_emulated(addr, new, bytes, vcpu, true, true); + return __emulator_write_emulated(addr, new, bytes, vcpu, true); emul_write: printk_once(KERN_WARNING kvm: emulating exchange as write\n); @@ -4083,8 +4077,7 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu) kvm_x86_ops-patch_hypercall(vcpu, instruction); - return __emulator_write_emulated(rip, instruction, 3, vcpu, -false, false); + return __emulator_write_emulated(rip, instruction, 3, vcpu, false); } void realmode_lgdt(struct kvm_vcpu *vcpu, u16 limit, unsigned long base) -- To unsubscribe from this list: send the line unsubscribe kvm-commits in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
KVM: x86: ignore access permissions for hypercall patching
Ignore access permissions while patching hypercall instructions. Otherwise KVM injects a page fault when trying to patch vmcall on read-only text regions: Freeing initrd memory: 8843k freed Freeing unused kernel memory: 660k freed Write protecting the kernel text: 4780k Write protecting the kernel read-only data: 1912k BUG: unable to handle kernel paging request at c01292e3 IP: [c01292e3] kvm_leave_lazy_mmu+0x43/0x70 *pde = 00910067 *pte = 00129161 Oops: 0003 [#1] SMP CC: sta...@kernel.org Reported-by: Stefan Bader stefan.ba...@canonical.com Signed-off-by: Marcelo Tosatti mtosa...@redhat.com diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 703f637..bf5c83f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3253,12 +3253,17 @@ int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, static int emulator_write_emulated_onepage(unsigned long addr, const void *val, unsigned int bytes, - struct kvm_vcpu *vcpu) + struct kvm_vcpu *vcpu, + bool guest_initiated) { gpa_t gpa; u32 error_code; - gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error_code); + + if (guest_initiated) + gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error_code); + else + gpa = kvm_mmu_gva_to_gpa_system(vcpu, addr, error_code); if (gpa == UNMAPPED_GVA) { kvm_inject_page_fault(vcpu, addr, error_code); @@ -3289,24 +3294,35 @@ mmio: return X86EMUL_CONTINUE; } -int emulator_write_emulated(unsigned long addr, +int __emulator_write_emulated(unsigned long addr, const void *val, unsigned int bytes, - struct kvm_vcpu *vcpu) + struct kvm_vcpu *vcpu, + bool guest_initiated) { /* 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, vcpu); + rc = emulator_write_emulated_onepage(addr, val, now, vcpu, +guest_initiated); if (rc != X86EMUL_CONTINUE) return rc; addr += now; val += now; bytes -= now; } - return emulator_write_emulated_onepage(addr, val, bytes, vcpu); + return emulator_write_emulated_onepage(addr, val, bytes, vcpu, + guest_initiated); +} + +int emulator_write_emulated(unsigned long addr, + const void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu) +{ + return __emulator_write_emulated(addr, val, bytes, vcpu, true); } EXPORT_SYMBOL_GPL(emulator_write_emulated); @@ -3997,7 +4013,7 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu) kvm_x86_ops-patch_hypercall(vcpu, instruction); - return emulator_write_emulated(rip, instruction, 3, vcpu); + return __emulator_write_emulated(rip, instruction, 3, vcpu, false); } static u64 mk_cr_64(u64 curr_cr, u32 new_val) -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: KVM: x86: ignore access permissions for hypercall patching
With this patch applied on top, I was able to boot my guest on a AMD host system. Marcelo Tosatti wrote: Ignore access permissions while patching hypercall instructions. Otherwise KVM injects a page fault when trying to patch vmcall on read-only text regions: Freeing initrd memory: 8843k freed Freeing unused kernel memory: 660k freed Write protecting the kernel text: 4780k Write protecting the kernel read-only data: 1912k BUG: unable to handle kernel paging request at c01292e3 IP: [c01292e3] kvm_leave_lazy_mmu+0x43/0x70 *pde = 00910067 *pte = 00129161 Oops: 0003 [#1] SMP CC: sta...@kernel.org Reported-by: Stefan Bader stefan.ba...@canonical.com Signed-off-by: Marcelo Tosatti mtosa...@redhat.com Tested-by: Stefan Bader stefan.ba...@canonical.com diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 703f637..bf5c83f 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3253,12 +3253,17 @@ int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, static int emulator_write_emulated_onepage(unsigned long addr, const void *val, unsigned int bytes, -struct kvm_vcpu *vcpu) +struct kvm_vcpu *vcpu, +bool guest_initiated) { gpa_t gpa; u32 error_code; - gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error_code); + + if (guest_initiated) + gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error_code); + else + gpa = kvm_mmu_gva_to_gpa_system(vcpu, addr, error_code); if (gpa == UNMAPPED_GVA) { kvm_inject_page_fault(vcpu, addr, error_code); @@ -3289,24 +3294,35 @@ mmio: return X86EMUL_CONTINUE; } -int emulator_write_emulated(unsigned long addr, +int __emulator_write_emulated(unsigned long addr, const void *val, unsigned int bytes, -struct kvm_vcpu *vcpu) +struct kvm_vcpu *vcpu, +bool guest_initiated) { /* 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, vcpu); + rc = emulator_write_emulated_onepage(addr, val, now, vcpu, + guest_initiated); if (rc != X86EMUL_CONTINUE) return rc; addr += now; val += now; bytes -= now; } - return emulator_write_emulated_onepage(addr, val, bytes, vcpu); + return emulator_write_emulated_onepage(addr, val, bytes, vcpu, +guest_initiated); +} + +int emulator_write_emulated(unsigned long addr, +const void *val, +unsigned int bytes, +struct kvm_vcpu *vcpu) +{ + return __emulator_write_emulated(addr, val, bytes, vcpu, true); } EXPORT_SYMBOL_GPL(emulator_write_emulated); @@ -3997,7 +4013,7 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu) kvm_x86_ops-patch_hypercall(vcpu, instruction); - return emulator_write_emulated(rip, instruction, 3, vcpu); + return __emulator_write_emulated(rip, instruction, 3, vcpu, false); } static u64 mk_cr_64(u64 curr_cr, u32 new_val) -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: KVM: x86: ignore access permissions for hypercall patching
On Thu, Mar 11, 2010 at 06:16:05PM -0300, Marcelo Tosatti wrote: Ignore access permissions while patching hypercall instructions. Otherwise KVM injects a page fault when trying to patch vmcall on read-only text regions: Freeing initrd memory: 8843k freed Freeing unused kernel memory: 660k freed Write protecting the kernel text: 4780k Write protecting the kernel read-only data: 1912k BUG: unable to handle kernel paging request at c01292e3 IP: [c01292e3] kvm_leave_lazy_mmu+0x43/0x70 *pde = 00910067 *pte = 00129161 Oops: 0003 [#1] SMP CC: sta...@kernel.org Reported-by: Stefan Bader stefan.ba...@canonical.com Signed-off-by: Marcelo Tosatti mtosa...@redhat.com My emulator patch series introduce kvm_write_guest_virt_system(). May be used it here (only compile tested). diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3753c11..9833c25 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3157,14 +3157,18 @@ static int kvm_read_guest_virt_system(gva_t addr, void *val, unsigned int bytes, return kvm_read_guest_virt_helper(addr, val, bytes, vcpu, 0, error); } -static int kvm_write_guest_virt(gva_t addr, void *val, unsigned int bytes, - struct kvm_vcpu *vcpu, u32 *error) +static int kvm_write_guest_virt_helper(gva_t addr, void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu, u32 access, + u32 *error) { void *data = val; int r = X86EMUL_CONTINUE; + access |= PFERR_WRITE_MASK; + while (bytes) { - gpa_t gpa = kvm_mmu_gva_to_gpa_write(vcpu, addr, error); + gpa_t gpa = vcpu-arch.mmu.gva_to_gpa(vcpu, addr, access, error); unsigned offset = addr (PAGE_SIZE-1); unsigned towrite = min(bytes, (unsigned)PAGE_SIZE - offset); int ret; @@ -3187,6 +3191,19 @@ out: return r; } +static int kvm_write_guest_virt(gva_t addr, void *val, unsigned int bytes, + struct kvm_vcpu *vcpu, u32 *error) +{ + u32 access = (kvm_x86_ops-get_cpl(vcpu) == 3) ? PFERR_USER_MASK : 0; + return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, access, error); +} + +static int kvm_write_guest_virt_system(gva_t addr, void *val, + unsigned int bytes, + struct kvm_vcpu *vcpu, u32 *error) +{ + return kvm_write_guest_virt_helper(addr, val, bytes, vcpu, 0, error); +} static int emulator_read_emulated(unsigned long addr, void *val, @@ -3997,7 +4014,7 @@ int kvm_fix_hypercall(struct kvm_vcpu *vcpu) kvm_x86_ops-patch_hypercall(vcpu, instruction); - return emulator_write_emulated(rip, instruction, 3, vcpu); + return kvm_write_guest_virt_system(rip, instruction, 3, vcpu, NULL); } static u64 mk_cr_64(u64 curr_cr, u32 new_val) -- Gleb. -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: KVM: x86: ignore access permissions for hypercall patching
On Fri, Mar 12, 2010 at 07:56:00AM +0200, Gleb Natapov wrote: On Thu, Mar 11, 2010 at 06:16:05PM -0300, Marcelo Tosatti wrote: Ignore access permissions while patching hypercall instructions. Otherwise KVM injects a page fault when trying to patch vmcall on read-only text regions: Freeing initrd memory: 8843k freed Freeing unused kernel memory: 660k freed Write protecting the kernel text: 4780k Write protecting the kernel read-only data: 1912k BUG: unable to handle kernel paging request at c01292e3 IP: [c01292e3] kvm_leave_lazy_mmu+0x43/0x70 *pde = 00910067 *pte = 00129161 Oops: 0003 [#1] SMP CC: sta...@kernel.org Reported-by: Stefan Bader stefan.ba...@canonical.com Signed-off-by: Marcelo Tosatti mtosa...@redhat.com My emulator patch series introduce kvm_write_guest_virt_system(). May be used it here (only compile tested). Ignore that, it will not work. -- Gleb. -- To unsubscribe from this list: send the line unsubscribe kvm in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html