aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2010-03-24 16:48:32 -0400
committerAvi Kivity <avi@redhat.com>2010-05-17 05:17:14 -0400
commit9fb244a2c215d1e16ee92cb164b7b61c8dfa3909 (patch)
treec214f99be6740fe53d57a652b1b0fce6d7ba5d35
parenta2b07664f6cd14836ff84a77f48566673dca00bb (diff)
KVM: PPC: Fix dcbz emulation
On most systems we need to emulate dcbz when running 32 bit guests. So far we've been rather slack, not giving correct DSISR values to the guest. This patch makes the emulation more accurate, introducing a difference between "page not mapped" and "write protection fault". While at it, it also speeds up dcbz emulation by an order of magnitude by using kmap. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/powerpc/kvm/book3s.c56
-rw-r--r--arch/powerpc/kvm/book3s_64_emulate.c19
2 files changed, 37 insertions, 38 deletions
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index d2b3dabe2dc3..ed5758496372 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -29,6 +29,7 @@
29#include <linux/gfp.h> 29#include <linux/gfp.h>
30#include <linux/sched.h> 30#include <linux/sched.h>
31#include <linux/vmalloc.h> 31#include <linux/vmalloc.h>
32#include <linux/highmem.h>
32 33
33#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU 34#define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
34 35
@@ -369,34 +370,29 @@ void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr)
369 */ 370 */
370static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) 371static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
371{ 372{
372 bool touched = false; 373 struct page *hpage;
373 hva_t hpage; 374 u64 hpage_offset;
374 u32 *page; 375 u32 *page;
375 int i; 376 int i;
376 377
377 hpage = gfn_to_hva(vcpu->kvm, pte->raddr >> PAGE_SHIFT); 378 hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT);
378 if (kvm_is_error_hva(hpage)) 379 if (is_error_page(hpage))
379 return; 380 return;
380 381
381 hpage |= pte->raddr & ~PAGE_MASK; 382 hpage_offset = pte->raddr & ~PAGE_MASK;
382 hpage &= ~0xFFFULL; 383 hpage_offset &= ~0xFFFULL;
383 384 hpage_offset /= 4;
384 page = vmalloc(HW_PAGE_SIZE);
385
386 if (copy_from_user(page, (void __user *)hpage, HW_PAGE_SIZE))
387 goto out;
388 385
389 for (i=0; i < HW_PAGE_SIZE / 4; i++) 386 get_page(hpage);
390 if ((page[i] & 0xff0007ff) == INS_DCBZ) { 387 page = kmap_atomic(hpage, KM_USER0);
391 page[i] &= 0xfffffff7; // reserved instruction, so we trap
392 touched = true;
393 }
394 388
395 if (touched) 389 /* patch dcbz into reserved instruction, so we trap */
396 copy_to_user((void __user *)hpage, page, HW_PAGE_SIZE); 390 for (i=hpage_offset; i < hpage_offset + (HW_PAGE_SIZE / 4); i++)
391 if ((page[i] & 0xff0007ff) == INS_DCBZ)
392 page[i] &= 0xfffffff7;
397 393
398out: 394 kunmap_atomic(page, KM_USER0);
399 vfree(page); 395 put_page(hpage);
400} 396}
401 397
402static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data, 398static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data,
@@ -449,30 +445,21 @@ int kvmppc_st(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
449 bool data) 445 bool data)
450{ 446{
451 struct kvmppc_pte pte; 447 struct kvmppc_pte pte;
452 hva_t hva = *eaddr;
453 448
454 vcpu->stat.st++; 449 vcpu->stat.st++;
455 450
456 if (kvmppc_xlate(vcpu, *eaddr, data, &pte)) 451 if (kvmppc_xlate(vcpu, *eaddr, data, &pte))
457 goto nopte; 452 return -ENOENT;
458 453
459 *eaddr = pte.raddr; 454 *eaddr = pte.raddr;
460 455
461 hva = kvmppc_pte_to_hva(vcpu, &pte, false); 456 if (!pte.may_write)
462 if (kvm_is_error_hva(hva)) 457 return -EPERM;
463 goto mmio;
464 458
465 if (copy_to_user((void __user *)hva, ptr, size)) { 459 if (kvm_write_guest(vcpu->kvm, pte.raddr, ptr, size))
466 printk(KERN_INFO "kvmppc_st at 0x%lx failed\n", hva); 460 return EMULATE_DO_MMIO;
467 goto mmio;
468 }
469 461
470 return EMULATE_DONE; 462 return EMULATE_DONE;
471
472nopte:
473 return -ENOENT;
474mmio:
475 return EMULATE_DO_MMIO;
476} 463}
477 464
478int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr, 465int kvmppc_ld(struct kvm_vcpu *vcpu, ulong *eaddr, int size, void *ptr,
@@ -787,6 +774,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
787 * that no guest that needs the dcbz hack does NX. 774 * that no guest that needs the dcbz hack does NX.
788 */ 775 */
789 kvmppc_mmu_pte_flush(vcpu, vcpu->arch.pc, ~0xFFFULL); 776 kvmppc_mmu_pte_flush(vcpu, vcpu->arch.pc, ~0xFFFULL);
777 r = RESUME_GUEST;
790 } else { 778 } else {
791 vcpu->arch.msr |= vcpu->arch.shadow_srr1 & 0x58000000; 779 vcpu->arch.msr |= vcpu->arch.shadow_srr1 & 0x58000000;
792 kvmppc_book3s_queue_irqprio(vcpu, exit_nr); 780 kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
diff --git a/arch/powerpc/kvm/book3s_64_emulate.c b/arch/powerpc/kvm/book3s_64_emulate.c
index 1e5cf8d594ea..bbd15906900d 100644
--- a/arch/powerpc/kvm/book3s_64_emulate.c
+++ b/arch/powerpc/kvm/book3s_64_emulate.c
@@ -189,6 +189,8 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
189 ulong ra = 0; 189 ulong ra = 0;
190 ulong addr, vaddr; 190 ulong addr, vaddr;
191 u32 zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 191 u32 zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
192 u32 dsisr;
193 int r;
192 194
193 if (get_ra(inst)) 195 if (get_ra(inst))
194 ra = kvmppc_get_gpr(vcpu, get_ra(inst)); 196 ra = kvmppc_get_gpr(vcpu, get_ra(inst));
@@ -198,14 +200,23 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
198 addr &= 0xffffffff; 200 addr &= 0xffffffff;
199 vaddr = addr; 201 vaddr = addr;
200 202
201 if (kvmppc_st(vcpu, &addr, 32, zeros, true)) { 203 r = kvmppc_st(vcpu, &addr, 32, zeros, true);
204 if ((r == -ENOENT) || (r == -EPERM)) {
205 *advance = 0;
202 vcpu->arch.dear = vaddr; 206 vcpu->arch.dear = vaddr;
203 vcpu->arch.fault_dear = vaddr; 207 vcpu->arch.fault_dear = vaddr;
204 to_book3s(vcpu)->dsisr = DSISR_PROTFAULT | 208
205 DSISR_ISSTORE; 209 dsisr = DSISR_ISSTORE;
210 if (r == -ENOENT)
211 dsisr |= DSISR_NOHPTE;
212 else if (r == -EPERM)
213 dsisr |= DSISR_PROTFAULT;
214
215 to_book3s(vcpu)->dsisr = dsisr;
216 vcpu->arch.fault_dsisr = dsisr;
217
206 kvmppc_book3s_queue_irqprio(vcpu, 218 kvmppc_book3s_queue_irqprio(vcpu,
207 BOOK3S_INTERRUPT_DATA_STORAGE); 219 BOOK3S_INTERRUPT_DATA_STORAGE);
208 kvmppc_mmu_pte_flush(vcpu, vaddr, ~0xFFFULL);
209 } 220 }
210 221
211 break; 222 break;