aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2013-09-20 00:52:47 -0400
committerAlexander Graf <agraf@suse.de>2013-10-17 08:45:04 -0400
commit5cd92a9521d35013fff904d3c805323027a33d73 (patch)
tree94037f1b656b8a029749061660a7575a8941dd5e /arch
parent03a9c90334d611c3006ac9569579f25f64812bc1 (diff)
KVM: PPC: Book3S PR: Correct errors in H_ENTER implementation
The implementation of H_ENTER in PR KVM has some errors: * With H_EXACT not set, if the HPTEG is full, we return H_PTEG_FULL as the return value of kvmppc_h_pr_enter, but the caller is expecting one of the EMULATE_* values. The H_PTEG_FULL needs to go in the guest's R3 instead. * With H_EXACT set, if the selected HPTE is already valid, the H_ENTER call should return a H_PTEG_FULL error. This fixes these errors and also makes it write only the selected HPTE, not the whole group, since only the selected HPTE has been modified. This also micro-optimizes the calculations involving pte_index and i. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/kvm/book3s_pr_papr.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/arch/powerpc/kvm/book3s_pr_papr.c b/arch/powerpc/kvm/book3s_pr_papr.c
index da0e0bc268bd..38f189975fe1 100644
--- a/arch/powerpc/kvm/book3s_pr_papr.c
+++ b/arch/powerpc/kvm/book3s_pr_papr.c
@@ -21,6 +21,8 @@
21#include <asm/kvm_ppc.h> 21#include <asm/kvm_ppc.h>
22#include <asm/kvm_book3s.h> 22#include <asm/kvm_book3s.h>
23 23
24#define HPTE_SIZE 16 /* bytes per HPT entry */
25
24static unsigned long get_pteg_addr(struct kvm_vcpu *vcpu, long pte_index) 26static unsigned long get_pteg_addr(struct kvm_vcpu *vcpu, long pte_index)
25{ 27{
26 struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); 28 struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu);
@@ -40,32 +42,39 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu)
40 long pte_index = kvmppc_get_gpr(vcpu, 5); 42 long pte_index = kvmppc_get_gpr(vcpu, 5);
41 unsigned long pteg[2 * 8]; 43 unsigned long pteg[2 * 8];
42 unsigned long pteg_addr, i, *hpte; 44 unsigned long pteg_addr, i, *hpte;
45 long int ret;
43 46
47 i = pte_index & 7;
44 pte_index &= ~7UL; 48 pte_index &= ~7UL;
45 pteg_addr = get_pteg_addr(vcpu, pte_index); 49 pteg_addr = get_pteg_addr(vcpu, pte_index);
46 50
47 copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg)); 51 copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg));
48 hpte = pteg; 52 hpte = pteg;
49 53
54 ret = H_PTEG_FULL;
50 if (likely((flags & H_EXACT) == 0)) { 55 if (likely((flags & H_EXACT) == 0)) {
51 pte_index &= ~7UL;
52 for (i = 0; ; ++i) { 56 for (i = 0; ; ++i) {
53 if (i == 8) 57 if (i == 8)
54 return H_PTEG_FULL; 58 goto done;
55 if ((*hpte & HPTE_V_VALID) == 0) 59 if ((*hpte & HPTE_V_VALID) == 0)
56 break; 60 break;
57 hpte += 2; 61 hpte += 2;
58 } 62 }
59 } else { 63 } else {
60 i = kvmppc_get_gpr(vcpu, 5) & 7UL;
61 hpte += i * 2; 64 hpte += i * 2;
65 if (*hpte & HPTE_V_VALID)
66 goto done;
62 } 67 }
63 68
64 hpte[0] = kvmppc_get_gpr(vcpu, 6); 69 hpte[0] = kvmppc_get_gpr(vcpu, 6);
65 hpte[1] = kvmppc_get_gpr(vcpu, 7); 70 hpte[1] = kvmppc_get_gpr(vcpu, 7);
66 copy_to_user((void __user *)pteg_addr, pteg, sizeof(pteg)); 71 pteg_addr += i * HPTE_SIZE;
67 kvmppc_set_gpr(vcpu, 3, H_SUCCESS); 72 copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE);
68 kvmppc_set_gpr(vcpu, 4, pte_index | i); 73 kvmppc_set_gpr(vcpu, 4, pte_index | i);
74 ret = H_SUCCESS;
75
76 done:
77 kvmppc_set_gpr(vcpu, 3, ret);
69 78
70 return EMULATE_DONE; 79 return EMULATE_DONE;
71} 80}