aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2011-12-12 07:28:55 -0500
committerAvi Kivity <avi@redhat.com>2012-03-05 07:52:36 -0500
commit93e602490c1da83162a8b6ba86b4b48a7a0f0c9e (patch)
tree7dd0407af03944cffcfdb7798d0ea6155156700e
parentb2b2f16508de10bb1863bdd4ec1fa212111df5b4 (diff)
KVM: PPC: Add an interface for pinning guest pages in Book3s HV guests
This adds two new functions, kvmppc_pin_guest_page() and kvmppc_unpin_guest_page(), and uses them to pin the guest pages where the guest has registered areas of memory for the hypervisor to update, (i.e. the per-cpu virtual processor areas, SLB shadow buffers and dispatch trace logs) and then unpin them when they are no longer required. Although it is not strictly necessary to pin the pages at this point, since all guest pages are already pinned, later commits in this series will mean that guest pages aren't all pinned. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/powerpc/include/asm/kvm_book3s.h3
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_hv.c38
-rw-r--r--arch/powerpc/kvm/book3s_hv.c67
3 files changed, 78 insertions, 30 deletions
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index c941c21a1893..bcf6f4f52a22 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -138,6 +138,9 @@ extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat,
138extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr); 138extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
139extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu); 139extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu);
140extern pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn); 140extern pfn_t kvmppc_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn);
141extern void *kvmppc_pin_guest_page(struct kvm *kvm, unsigned long addr,
142 unsigned long *nb_ret);
143extern void kvmppc_unpin_guest_page(struct kvm *kvm, void *addr);
141 144
142extern void kvmppc_entry_trampoline(void); 145extern void kvmppc_entry_trampoline(void);
143extern void kvmppc_hv_entry_trampoline(void); 146extern void kvmppc_hv_entry_trampoline(void);
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index e4c60698f41a..dcd39dc64f07 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -184,6 +184,44 @@ static int kvmppc_mmu_book3s_64_hv_xlate(struct kvm_vcpu *vcpu, gva_t eaddr,
184 return -ENOENT; 184 return -ENOENT;
185} 185}
186 186
187void *kvmppc_pin_guest_page(struct kvm *kvm, unsigned long gpa,
188 unsigned long *nb_ret)
189{
190 struct kvm_memory_slot *memslot;
191 unsigned long gfn = gpa >> PAGE_SHIFT;
192 struct page *page;
193 unsigned long offset;
194 unsigned long pfn, pa;
195 unsigned long *physp;
196
197 memslot = gfn_to_memslot(kvm, gfn);
198 if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID))
199 return NULL;
200 physp = kvm->arch.slot_phys[memslot->id];
201 if (!physp)
202 return NULL;
203 physp += (gfn - memslot->base_gfn) >>
204 (kvm->arch.ram_porder - PAGE_SHIFT);
205 pa = *physp;
206 if (!pa)
207 return NULL;
208 pfn = pa >> PAGE_SHIFT;
209 page = pfn_to_page(pfn);
210 get_page(page);
211 offset = gpa & (kvm->arch.ram_psize - 1);
212 if (nb_ret)
213 *nb_ret = kvm->arch.ram_psize - offset;
214 return page_address(page) + offset;
215}
216
217void kvmppc_unpin_guest_page(struct kvm *kvm, void *va)
218{
219 struct page *page = virt_to_page(va);
220
221 page = compound_head(page);
222 put_page(page);
223}
224
187void kvmppc_mmu_book3s_hv_init(struct kvm_vcpu *vcpu) 225void kvmppc_mmu_book3s_hv_init(struct kvm_vcpu *vcpu)
188{ 226{
189 struct kvmppc_mmu *mmu = &vcpu->arch.mmu; 227 struct kvmppc_mmu *mmu = &vcpu->arch.mmu;
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index a84fedc48d99..82d71388eace 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -139,12 +139,10 @@ static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu,
139 unsigned long vcpuid, unsigned long vpa) 139 unsigned long vcpuid, unsigned long vpa)
140{ 140{
141 struct kvm *kvm = vcpu->kvm; 141 struct kvm *kvm = vcpu->kvm;
142 unsigned long gfn, pg_index, ra, len; 142 unsigned long len, nb;
143 unsigned long pg_offset;
144 void *va; 143 void *va;
145 struct kvm_vcpu *tvcpu; 144 struct kvm_vcpu *tvcpu;
146 struct kvm_memory_slot *memslot; 145 int err = H_PARAMETER;
147 unsigned long *physp;
148 146
149 tvcpu = kvmppc_find_vcpu(kvm, vcpuid); 147 tvcpu = kvmppc_find_vcpu(kvm, vcpuid);
150 if (!tvcpu) 148 if (!tvcpu)
@@ -157,51 +155,41 @@ static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu,
157 if (flags < 4) { 155 if (flags < 4) {
158 if (vpa & 0x7f) 156 if (vpa & 0x7f)
159 return H_PARAMETER; 157 return H_PARAMETER;
158 if (flags >= 2 && !tvcpu->arch.vpa)
159 return H_RESOURCE;
160 /* registering new area; convert logical addr to real */ 160 /* registering new area; convert logical addr to real */
161 gfn = vpa >> PAGE_SHIFT; 161 va = kvmppc_pin_guest_page(kvm, vpa, &nb);
162 memslot = gfn_to_memslot(kvm, gfn); 162 if (va == NULL)
163 if (!memslot || !(memslot->flags & KVM_MEMSLOT_INVALID))
164 return H_PARAMETER;
165 physp = kvm->arch.slot_phys[memslot->id];
166 if (!physp)
167 return H_PARAMETER;
168 pg_index = (gfn - memslot->base_gfn) >>
169 (kvm->arch.ram_porder - PAGE_SHIFT);
170 pg_offset = vpa & (kvm->arch.ram_psize - 1);
171 ra = physp[pg_index];
172 if (!ra)
173 return H_PARAMETER; 163 return H_PARAMETER;
174 ra = (ra & PAGE_MASK) | pg_offset;
175 va = __va(ra);
176 if (flags <= 1) 164 if (flags <= 1)
177 len = *(unsigned short *)(va + 4); 165 len = *(unsigned short *)(va + 4);
178 else 166 else
179 len = *(unsigned int *)(va + 4); 167 len = *(unsigned int *)(va + 4);
180 if (pg_offset + len > kvm->arch.ram_psize) 168 if (len > nb)
181 return H_PARAMETER; 169 goto out_unpin;
182 switch (flags) { 170 switch (flags) {
183 case 1: /* register VPA */ 171 case 1: /* register VPA */
184 if (len < 640) 172 if (len < 640)
185 return H_PARAMETER; 173 goto out_unpin;
174 if (tvcpu->arch.vpa)
175 kvmppc_unpin_guest_page(kvm, vcpu->arch.vpa);
186 tvcpu->arch.vpa = va; 176 tvcpu->arch.vpa = va;
187 init_vpa(vcpu, va); 177 init_vpa(vcpu, va);
188 break; 178 break;
189 case 2: /* register DTL */ 179 case 2: /* register DTL */
190 if (len < 48) 180 if (len < 48)
191 return H_PARAMETER; 181 goto out_unpin;
192 if (!tvcpu->arch.vpa)
193 return H_RESOURCE;
194 len -= len % 48; 182 len -= len % 48;
183 if (tvcpu->arch.dtl)
184 kvmppc_unpin_guest_page(kvm, vcpu->arch.dtl);
195 tvcpu->arch.dtl = va; 185 tvcpu->arch.dtl = va;
196 tvcpu->arch.dtl_end = va + len; 186 tvcpu->arch.dtl_end = va + len;
197 break; 187 break;
198 case 3: /* register SLB shadow buffer */ 188 case 3: /* register SLB shadow buffer */
199 if (len < 8) 189 if (len < 16)
200 return H_PARAMETER; 190 goto out_unpin;
201 if (!tvcpu->arch.vpa) 191 if (tvcpu->arch.slb_shadow)
202 return H_RESOURCE; 192 kvmppc_unpin_guest_page(kvm, vcpu->arch.slb_shadow);
203 tvcpu->arch.slb_shadow = va;
204 len = (len - 16) / 16;
205 tvcpu->arch.slb_shadow = va; 193 tvcpu->arch.slb_shadow = va;
206 break; 194 break;
207 } 195 }
@@ -210,17 +198,30 @@ static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu,
210 case 5: /* unregister VPA */ 198 case 5: /* unregister VPA */
211 if (tvcpu->arch.slb_shadow || tvcpu->arch.dtl) 199 if (tvcpu->arch.slb_shadow || tvcpu->arch.dtl)
212 return H_RESOURCE; 200 return H_RESOURCE;
201 if (!tvcpu->arch.vpa)
202 break;
203 kvmppc_unpin_guest_page(kvm, tvcpu->arch.vpa);
213 tvcpu->arch.vpa = NULL; 204 tvcpu->arch.vpa = NULL;
214 break; 205 break;
215 case 6: /* unregister DTL */ 206 case 6: /* unregister DTL */
207 if (!tvcpu->arch.dtl)
208 break;
209 kvmppc_unpin_guest_page(kvm, tvcpu->arch.dtl);
216 tvcpu->arch.dtl = NULL; 210 tvcpu->arch.dtl = NULL;
217 break; 211 break;
218 case 7: /* unregister SLB shadow buffer */ 212 case 7: /* unregister SLB shadow buffer */
213 if (!tvcpu->arch.slb_shadow)
214 break;
215 kvmppc_unpin_guest_page(kvm, tvcpu->arch.slb_shadow);
219 tvcpu->arch.slb_shadow = NULL; 216 tvcpu->arch.slb_shadow = NULL;
220 break; 217 break;
221 } 218 }
222 } 219 }
223 return H_SUCCESS; 220 return H_SUCCESS;
221
222 out_unpin:
223 kvmppc_unpin_guest_page(kvm, va);
224 return err;
224} 225}
225 226
226int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) 227int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
@@ -470,6 +471,12 @@ out:
470 471
471void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) 472void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
472{ 473{
474 if (vcpu->arch.dtl)
475 kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.dtl);
476 if (vcpu->arch.slb_shadow)
477 kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.slb_shadow);
478 if (vcpu->arch.vpa)
479 kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.vpa);
473 kvm_vcpu_uninit(vcpu); 480 kvm_vcpu_uninit(vcpu);
474 kfree(vcpu); 481 kfree(vcpu);
475} 482}