diff options
Diffstat (limited to 'arch/powerpc/kvm/book3s_hv_rm_mmu.c')
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_rm_mmu.c | 45 |
1 files changed, 26 insertions, 19 deletions
diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c index ba4a1376b331..91b45a03f438 100644 --- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c +++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c | |||
@@ -87,15 +87,17 @@ EXPORT_SYMBOL_GPL(kvmppc_add_revmap_chain); | |||
87 | 87 | ||
88 | /* Remove this HPTE from the chain for a real page */ | 88 | /* Remove this HPTE from the chain for a real page */ |
89 | static void remove_revmap_chain(struct kvm *kvm, long pte_index, | 89 | static void remove_revmap_chain(struct kvm *kvm, long pte_index, |
90 | unsigned long hpte_v) | 90 | struct revmap_entry *rev, |
91 | unsigned long hpte_v, unsigned long hpte_r) | ||
91 | { | 92 | { |
92 | struct revmap_entry *rev, *next, *prev; | 93 | struct revmap_entry *next, *prev; |
93 | unsigned long gfn, ptel, head; | 94 | unsigned long gfn, ptel, head; |
94 | struct kvm_memory_slot *memslot; | 95 | struct kvm_memory_slot *memslot; |
95 | unsigned long *rmap; | 96 | unsigned long *rmap; |
97 | unsigned long rcbits; | ||
96 | 98 | ||
97 | rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]); | 99 | rcbits = hpte_r & (HPTE_R_R | HPTE_R_C); |
98 | ptel = rev->guest_rpte; | 100 | ptel = rev->guest_rpte |= rcbits; |
99 | gfn = hpte_rpn(ptel, hpte_page_size(hpte_v, ptel)); | 101 | gfn = hpte_rpn(ptel, hpte_page_size(hpte_v, ptel)); |
100 | memslot = builtin_gfn_to_memslot(kvm, gfn); | 102 | memslot = builtin_gfn_to_memslot(kvm, gfn); |
101 | if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID)) | 103 | if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID)) |
@@ -116,6 +118,7 @@ static void remove_revmap_chain(struct kvm *kvm, long pte_index, | |||
116 | else | 118 | else |
117 | *rmap = (*rmap & ~KVMPPC_RMAP_INDEX) | head; | 119 | *rmap = (*rmap & ~KVMPPC_RMAP_INDEX) | head; |
118 | } | 120 | } |
121 | *rmap |= rcbits << KVMPPC_RMAP_RC_SHIFT; | ||
119 | unlock_rmap(rmap); | 122 | unlock_rmap(rmap); |
120 | } | 123 | } |
121 | 124 | ||
@@ -162,6 +165,7 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags, | |||
162 | pte_t pte; | 165 | pte_t pte; |
163 | unsigned int writing; | 166 | unsigned int writing; |
164 | unsigned long mmu_seq; | 167 | unsigned long mmu_seq; |
168 | unsigned long rcbits; | ||
165 | bool realmode = vcpu->arch.vcore->vcore_state == VCORE_RUNNING; | 169 | bool realmode = vcpu->arch.vcore->vcore_state == VCORE_RUNNING; |
166 | 170 | ||
167 | psize = hpte_page_size(pteh, ptel); | 171 | psize = hpte_page_size(pteh, ptel); |
@@ -320,6 +324,9 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags, | |||
320 | } else { | 324 | } else { |
321 | kvmppc_add_revmap_chain(kvm, rev, rmap, pte_index, | 325 | kvmppc_add_revmap_chain(kvm, rev, rmap, pte_index, |
322 | realmode); | 326 | realmode); |
327 | /* Only set R/C in real HPTE if already set in *rmap */ | ||
328 | rcbits = *rmap >> KVMPPC_RMAP_RC_SHIFT; | ||
329 | ptel &= rcbits | ~(HPTE_R_R | HPTE_R_C); | ||
323 | } | 330 | } |
324 | } | 331 | } |
325 | 332 | ||
@@ -394,7 +401,8 @@ long kvmppc_h_remove(struct kvm_vcpu *vcpu, unsigned long flags, | |||
394 | asm volatile("tlbiel %0" : : "r" (rb)); | 401 | asm volatile("tlbiel %0" : : "r" (rb)); |
395 | asm volatile("ptesync" : : : "memory"); | 402 | asm volatile("ptesync" : : : "memory"); |
396 | } | 403 | } |
397 | remove_revmap_chain(kvm, pte_index, v); | 404 | /* Read PTE low word after tlbie to get final R/C values */ |
405 | remove_revmap_chain(kvm, pte_index, rev, v, hpte[1]); | ||
398 | } | 406 | } |
399 | r = rev->guest_rpte; | 407 | r = rev->guest_rpte; |
400 | unlock_hpte(hpte, 0); | 408 | unlock_hpte(hpte, 0); |
@@ -469,12 +477,13 @@ long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu) | |||
469 | 477 | ||
470 | args[j] = ((0x80 | flags) << 56) + pte_index; | 478 | args[j] = ((0x80 | flags) << 56) + pte_index; |
471 | rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]); | 479 | rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]); |
472 | /* insert R and C bits from guest PTE */ | ||
473 | rcbits = rev->guest_rpte & (HPTE_R_R|HPTE_R_C); | ||
474 | args[j] |= rcbits << (56 - 5); | ||
475 | 480 | ||
476 | if (!(hp[0] & HPTE_V_VALID)) | 481 | if (!(hp[0] & HPTE_V_VALID)) { |
482 | /* insert R and C bits from PTE */ | ||
483 | rcbits = rev->guest_rpte & (HPTE_R_R|HPTE_R_C); | ||
484 | args[j] |= rcbits << (56 - 5); | ||
477 | continue; | 485 | continue; |
486 | } | ||
478 | 487 | ||
479 | hp[0] &= ~HPTE_V_VALID; /* leave it locked */ | 488 | hp[0] &= ~HPTE_V_VALID; /* leave it locked */ |
480 | tlbrb[n] = compute_tlbie_rb(hp[0], hp[1], pte_index); | 489 | tlbrb[n] = compute_tlbie_rb(hp[0], hp[1], pte_index); |
@@ -505,13 +514,16 @@ long kvmppc_h_bulk_remove(struct kvm_vcpu *vcpu) | |||
505 | asm volatile("ptesync" : : : "memory"); | 514 | asm volatile("ptesync" : : : "memory"); |
506 | } | 515 | } |
507 | 516 | ||
517 | /* Read PTE low words after tlbie to get final R/C values */ | ||
508 | for (k = 0; k < n; ++k) { | 518 | for (k = 0; k < n; ++k) { |
509 | j = indexes[k]; | 519 | j = indexes[k]; |
510 | pte_index = args[j] & ((1ul << 56) - 1); | 520 | pte_index = args[j] & ((1ul << 56) - 1); |
511 | hp = hptes[k]; | 521 | hp = hptes[k]; |
512 | rev = revs[k]; | 522 | rev = revs[k]; |
513 | remove_revmap_chain(kvm, pte_index, hp[0]); | 523 | remove_revmap_chain(kvm, pte_index, rev, hp[0], hp[1]); |
514 | unlock_hpte(hp, 0); | 524 | rcbits = rev->guest_rpte & (HPTE_R_R|HPTE_R_C); |
525 | args[j] |= rcbits << (56 - 5); | ||
526 | hp[0] = 0; | ||
515 | } | 527 | } |
516 | } | 528 | } |
517 | 529 | ||
@@ -595,8 +607,7 @@ long kvmppc_h_read(struct kvm_vcpu *vcpu, unsigned long flags, | |||
595 | pte_index &= ~3; | 607 | pte_index &= ~3; |
596 | n = 4; | 608 | n = 4; |
597 | } | 609 | } |
598 | if (flags & H_R_XLATE) | 610 | rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]); |
599 | rev = real_vmalloc_addr(&kvm->arch.revmap[pte_index]); | ||
600 | for (i = 0; i < n; ++i, ++pte_index) { | 611 | for (i = 0; i < n; ++i, ++pte_index) { |
601 | hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4)); | 612 | hpte = (unsigned long *)(kvm->arch.hpt_virt + (pte_index << 4)); |
602 | v = hpte[0] & ~HPTE_V_HVLOCK; | 613 | v = hpte[0] & ~HPTE_V_HVLOCK; |
@@ -605,12 +616,8 @@ long kvmppc_h_read(struct kvm_vcpu *vcpu, unsigned long flags, | |||
605 | v &= ~HPTE_V_ABSENT; | 616 | v &= ~HPTE_V_ABSENT; |
606 | v |= HPTE_V_VALID; | 617 | v |= HPTE_V_VALID; |
607 | } | 618 | } |
608 | if (v & HPTE_V_VALID) { | 619 | if (v & HPTE_V_VALID) |
609 | if (rev) | 620 | r = rev[i].guest_rpte | (r & (HPTE_R_R | HPTE_R_C)); |
610 | r = rev[i].guest_rpte; | ||
611 | else | ||
612 | r = hpte[1] | HPTE_R_RPN; | ||
613 | } | ||
614 | vcpu->arch.gpr[4 + i * 2] = v; | 621 | vcpu->arch.gpr[4 + i * 2] = v; |
615 | vcpu->arch.gpr[5 + i * 2] = r; | 622 | vcpu->arch.gpr[5 + i * 2] = r; |
616 | } | 623 | } |