aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2012-02-19 12:46:32 -0500
committerAvi Kivity <avi@redhat.com>2012-04-08 07:01:27 -0400
commit2e25aa5f64b18a97f35266e51c71ff4dc644db0c (patch)
tree7b26cf15534d54bc2c370f1e5393cd9e58eb7141 /arch/powerpc
parentf0888f70151c7f53de2b45ee20ff1905837943e8 (diff)
KVM: PPC: Book3S HV: Make virtual processor area registration more robust
The PAPR API allows three sorts of per-virtual-processor areas to be registered (VPA, SLB shadow buffer, and dispatch trace log), and furthermore, these can be registered and unregistered for another virtual CPU. Currently we just update the vcpu fields pointing to these areas at the time of registration or unregistration. If this is done on another vcpu, there is the possibility that the target vcpu is using those fields at the time and could end up using a bogus pointer and corrupting memory. This fixes the race by making the target cpu itself do the update, so we can be sure that the update happens at a time when the fields aren't being used. Each area now has a struct kvmppc_vpa which is used to manage these updates. There is also a spinlock which protects access to all of the kvmppc_vpa structs, other than to the pinned_addr fields. (We could have just taken the spinlock when using the vpa, slb_shadow or dtl fields, but that would mean taking the spinlock on every guest entry and exit.) This also changes 'struct dtl' (which was undefined) to 'struct dtl_entry', which is what the rest of the kernel uses. Thanks to Michael Ellerman <michael@ellerman.id.au> for pointing out the need to initialize vcpu->arch.vpa_update_lock. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/hvcall.h10
-rw-r--r--arch/powerpc/include/asm/kvm_host.h27
-rw-r--r--arch/powerpc/kernel/asm-offsets.c2
-rw-r--r--arch/powerpc/kvm/book3s_hv.c227
4 files changed, 190 insertions, 76 deletions
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h
index 1c324ff55ea8..318bac9f8752 100644
--- a/arch/powerpc/include/asm/hvcall.h
+++ b/arch/powerpc/include/asm/hvcall.h
@@ -114,6 +114,16 @@
114#define H_PP1 (1UL<<(63-62)) 114#define H_PP1 (1UL<<(63-62))
115#define H_PP2 (1UL<<(63-63)) 115#define H_PP2 (1UL<<(63-63))
116 116
117/* Flags for H_REGISTER_VPA subfunction field */
118#define H_VPA_FUNC_SHIFT (63-18) /* Bit posn of subfunction code */
119#define H_VPA_FUNC_MASK 7UL
120#define H_VPA_REG_VPA 1UL /* Register Virtual Processor Area */
121#define H_VPA_REG_DTL 2UL /* Register Dispatch Trace Log */
122#define H_VPA_REG_SLB 3UL /* Register SLB shadow buffer */
123#define H_VPA_DEREG_VPA 5UL /* Deregister Virtual Processor Area */
124#define H_VPA_DEREG_DTL 6UL /* Deregister Dispatch Trace Log */
125#define H_VPA_DEREG_SLB 7UL /* Deregister SLB shadow buffer */
126
117/* VASI States */ 127/* VASI States */
118#define H_VASI_INVALID 0 128#define H_VASI_INVALID 0
119#define H_VASI_ENABLED 1 129#define H_VASI_ENABLED 1
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 97ecdaf82956..93ffd8dd8554 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -82,7 +82,7 @@ struct kvm_vcpu;
82 82
83struct lppaca; 83struct lppaca;
84struct slb_shadow; 84struct slb_shadow;
85struct dtl; 85struct dtl_entry;
86 86
87struct kvm_vm_stat { 87struct kvm_vm_stat {
88 u32 remote_tlb_flush; 88 u32 remote_tlb_flush;
@@ -279,6 +279,19 @@ struct kvmppc_vcore {
279#define VCORE_EXITING 2 279#define VCORE_EXITING 2
280#define VCORE_SLEEPING 3 280#define VCORE_SLEEPING 3
281 281
282/*
283 * Struct used to manage memory for a virtual processor area
284 * registered by a PAPR guest. There are three types of area
285 * that a guest can register.
286 */
287struct kvmppc_vpa {
288 void *pinned_addr; /* Address in kernel linear mapping */
289 void *pinned_end; /* End of region */
290 unsigned long next_gpa; /* Guest phys addr for update */
291 unsigned long len; /* Number of bytes required */
292 u8 update_pending; /* 1 => update pinned_addr from next_gpa */
293};
294
282struct kvmppc_pte { 295struct kvmppc_pte {
283 ulong eaddr; 296 ulong eaddr;
284 u64 vpage; 297 u64 vpage;
@@ -473,11 +486,6 @@ struct kvm_vcpu_arch {
473 u8 prodded; 486 u8 prodded;
474 u32 last_inst; 487 u32 last_inst;
475 488
476 struct lppaca *vpa;
477 struct slb_shadow *slb_shadow;
478 struct dtl *dtl;
479 struct dtl *dtl_end;
480
481 wait_queue_head_t *wqp; 489 wait_queue_head_t *wqp;
482 struct kvmppc_vcore *vcore; 490 struct kvmppc_vcore *vcore;
483 int ret; 491 int ret;
@@ -502,6 +510,13 @@ struct kvm_vcpu_arch {
502 struct task_struct *run_task; 510 struct task_struct *run_task;
503 struct kvm_run *kvm_run; 511 struct kvm_run *kvm_run;
504 pgd_t *pgdir; 512 pgd_t *pgdir;
513
514 spinlock_t vpa_update_lock;
515 struct kvmppc_vpa vpa;
516 struct kvmppc_vpa dtl;
517 struct dtl_entry *dtl_ptr;
518 unsigned long dtl_index;
519 struct kvmppc_vpa slb_shadow;
505#endif 520#endif
506}; 521};
507 522
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 2abcf7d4b29c..502e038f8c8a 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -466,7 +466,7 @@ int main(void)
466 DEFINE(VCPU_PENDING_EXC, offsetof(struct kvm_vcpu, arch.pending_exceptions)); 466 DEFINE(VCPU_PENDING_EXC, offsetof(struct kvm_vcpu, arch.pending_exceptions));
467 DEFINE(VCPU_CEDED, offsetof(struct kvm_vcpu, arch.ceded)); 467 DEFINE(VCPU_CEDED, offsetof(struct kvm_vcpu, arch.ceded));
468 DEFINE(VCPU_PRODDED, offsetof(struct kvm_vcpu, arch.prodded)); 468 DEFINE(VCPU_PRODDED, offsetof(struct kvm_vcpu, arch.prodded));
469 DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa)); 469 DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa.pinned_addr));
470 DEFINE(VCPU_MMCR, offsetof(struct kvm_vcpu, arch.mmcr)); 470 DEFINE(VCPU_MMCR, offsetof(struct kvm_vcpu, arch.mmcr));
471 DEFINE(VCPU_PMC, offsetof(struct kvm_vcpu, arch.pmc)); 471 DEFINE(VCPU_PMC, offsetof(struct kvm_vcpu, arch.pmc));
472 DEFINE(VCPU_SLB, offsetof(struct kvm_vcpu, arch.slb)); 472 DEFINE(VCPU_SLB, offsetof(struct kvm_vcpu, arch.slb));
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index e87f6196d222..2444a9ce781f 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -134,6 +134,22 @@ static void init_vpa(struct kvm_vcpu *vcpu, struct lppaca *vpa)
134 vpa->yield_count = 1; 134 vpa->yield_count = 1;
135} 135}
136 136
137/* Length for a per-processor buffer is passed in at offset 4 in the buffer */
138struct reg_vpa {
139 u32 dummy;
140 union {
141 u16 hword;
142 u32 word;
143 } length;
144};
145
146static int vpa_is_registered(struct kvmppc_vpa *vpap)
147{
148 if (vpap->update_pending)
149 return vpap->next_gpa != 0;
150 return vpap->pinned_addr != NULL;
151}
152
137static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu, 153static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu,
138 unsigned long flags, 154 unsigned long flags,
139 unsigned long vcpuid, unsigned long vpa) 155 unsigned long vcpuid, unsigned long vpa)
@@ -142,88 +158,153 @@ static unsigned long do_h_register_vpa(struct kvm_vcpu *vcpu,
142 unsigned long len, nb; 158 unsigned long len, nb;
143 void *va; 159 void *va;
144 struct kvm_vcpu *tvcpu; 160 struct kvm_vcpu *tvcpu;
145 int err = H_PARAMETER; 161 int err;
162 int subfunc;
163 struct kvmppc_vpa *vpap;
146 164
147 tvcpu = kvmppc_find_vcpu(kvm, vcpuid); 165 tvcpu = kvmppc_find_vcpu(kvm, vcpuid);
148 if (!tvcpu) 166 if (!tvcpu)
149 return H_PARAMETER; 167 return H_PARAMETER;
150 168
151 flags >>= 63 - 18; 169 subfunc = (flags >> H_VPA_FUNC_SHIFT) & H_VPA_FUNC_MASK;
152 flags &= 7; 170 if (subfunc == H_VPA_REG_VPA || subfunc == H_VPA_REG_DTL ||
153 if (flags == 0 || flags == 4) 171 subfunc == H_VPA_REG_SLB) {
154 return H_PARAMETER; 172 /* Registering new area - address must be cache-line aligned */
155 if (flags < 4) { 173 if ((vpa & (L1_CACHE_BYTES - 1)) || !vpa)
156 if (vpa & 0x7f)
157 return H_PARAMETER; 174 return H_PARAMETER;
158 if (flags >= 2 && !tvcpu->arch.vpa) 175
159 return H_RESOURCE; 176 /* convert logical addr to kernel addr and read length */
160 /* registering new area; convert logical addr to real */
161 va = kvmppc_pin_guest_page(kvm, vpa, &nb); 177 va = kvmppc_pin_guest_page(kvm, vpa, &nb);
162 if (va == NULL) 178 if (va == NULL)
163 return H_PARAMETER; 179 return H_PARAMETER;
164 if (flags <= 1) 180 if (subfunc == H_VPA_REG_VPA)
165 len = *(unsigned short *)(va + 4); 181 len = ((struct reg_vpa *)va)->length.hword;
166 else 182 else
167 len = *(unsigned int *)(va + 4); 183 len = ((struct reg_vpa *)va)->length.word;
168 if (len > nb) 184 kvmppc_unpin_guest_page(kvm, va);
169 goto out_unpin; 185
170 switch (flags) { 186 /* Check length */
171 case 1: /* register VPA */ 187 if (len > nb || len < sizeof(struct reg_vpa))
172 if (len < 640) 188 return H_PARAMETER;
173 goto out_unpin; 189 } else {
174 if (tvcpu->arch.vpa) 190 vpa = 0;
175 kvmppc_unpin_guest_page(kvm, vcpu->arch.vpa); 191 len = 0;
176 tvcpu->arch.vpa = va; 192 }
177 init_vpa(vcpu, va); 193
178 break; 194 err = H_PARAMETER;
179 case 2: /* register DTL */ 195 vpap = NULL;
180 if (len < 48) 196 spin_lock(&tvcpu->arch.vpa_update_lock);
181 goto out_unpin; 197
182 len -= len % 48; 198 switch (subfunc) {
183 if (tvcpu->arch.dtl) 199 case H_VPA_REG_VPA: /* register VPA */
184 kvmppc_unpin_guest_page(kvm, vcpu->arch.dtl); 200 if (len < sizeof(struct lppaca))
185 tvcpu->arch.dtl = va;
186 tvcpu->arch.dtl_end = va + len;
187 break; 201 break;
188 case 3: /* register SLB shadow buffer */ 202 vpap = &tvcpu->arch.vpa;
189 if (len < 16) 203 err = 0;
190 goto out_unpin; 204 break;
191 if (tvcpu->arch.slb_shadow) 205
192 kvmppc_unpin_guest_page(kvm, vcpu->arch.slb_shadow); 206 case H_VPA_REG_DTL: /* register DTL */
193 tvcpu->arch.slb_shadow = va; 207 if (len < sizeof(struct dtl_entry))
194 break; 208 break;
195 } 209 len -= len % sizeof(struct dtl_entry);
196 } else { 210
197 switch (flags) { 211 /* Check that they have previously registered a VPA */
198 case 5: /* unregister VPA */ 212 err = H_RESOURCE;
199 if (tvcpu->arch.slb_shadow || tvcpu->arch.dtl) 213 if (!vpa_is_registered(&tvcpu->arch.vpa))
200 return H_RESOURCE;
201 if (!tvcpu->arch.vpa)
202 break;
203 kvmppc_unpin_guest_page(kvm, tvcpu->arch.vpa);
204 tvcpu->arch.vpa = NULL;
205 break; 214 break;
206 case 6: /* unregister DTL */ 215
207 if (!tvcpu->arch.dtl) 216 vpap = &tvcpu->arch.dtl;
208 break; 217 err = 0;
209 kvmppc_unpin_guest_page(kvm, tvcpu->arch.dtl); 218 break;
210 tvcpu->arch.dtl = NULL; 219
220 case H_VPA_REG_SLB: /* register SLB shadow buffer */
221 /* Check that they have previously registered a VPA */
222 err = H_RESOURCE;
223 if (!vpa_is_registered(&tvcpu->arch.vpa))
211 break; 224 break;
212 case 7: /* unregister SLB shadow buffer */ 225
213 if (!tvcpu->arch.slb_shadow) 226 vpap = &tvcpu->arch.slb_shadow;
214 break; 227 err = 0;
215 kvmppc_unpin_guest_page(kvm, tvcpu->arch.slb_shadow); 228 break;
216 tvcpu->arch.slb_shadow = NULL; 229
230 case H_VPA_DEREG_VPA: /* deregister VPA */
231 /* Check they don't still have a DTL or SLB buf registered */
232 err = H_RESOURCE;
233 if (vpa_is_registered(&tvcpu->arch.dtl) ||
234 vpa_is_registered(&tvcpu->arch.slb_shadow))
217 break; 235 break;
218 } 236
237 vpap = &tvcpu->arch.vpa;
238 err = 0;
239 break;
240
241 case H_VPA_DEREG_DTL: /* deregister DTL */
242 vpap = &tvcpu->arch.dtl;
243 err = 0;
244 break;
245
246 case H_VPA_DEREG_SLB: /* deregister SLB shadow buffer */
247 vpap = &tvcpu->arch.slb_shadow;
248 err = 0;
249 break;
219 } 250 }
220 return H_SUCCESS;
221 251
222 out_unpin: 252 if (vpap) {
223 kvmppc_unpin_guest_page(kvm, va); 253 vpap->next_gpa = vpa;
254 vpap->len = len;
255 vpap->update_pending = 1;
256 }
257
258 spin_unlock(&tvcpu->arch.vpa_update_lock);
259
224 return err; 260 return err;
225} 261}
226 262
263static void kvmppc_update_vpa(struct kvm *kvm, struct kvmppc_vpa *vpap)
264{
265 void *va;
266 unsigned long nb;
267
268 vpap->update_pending = 0;
269 va = NULL;
270 if (vpap->next_gpa) {
271 va = kvmppc_pin_guest_page(kvm, vpap->next_gpa, &nb);
272 if (nb < vpap->len) {
273 /*
274 * If it's now too short, it must be that userspace
275 * has changed the mappings underlying guest memory,
276 * so unregister the region.
277 */
278 kvmppc_unpin_guest_page(kvm, va);
279 va = NULL;
280 }
281 }
282 if (vpap->pinned_addr)
283 kvmppc_unpin_guest_page(kvm, vpap->pinned_addr);
284 vpap->pinned_addr = va;
285 if (va)
286 vpap->pinned_end = va + vpap->len;
287}
288
289static void kvmppc_update_vpas(struct kvm_vcpu *vcpu)
290{
291 struct kvm *kvm = vcpu->kvm;
292
293 spin_lock(&vcpu->arch.vpa_update_lock);
294 if (vcpu->arch.vpa.update_pending) {
295 kvmppc_update_vpa(kvm, &vcpu->arch.vpa);
296 init_vpa(vcpu, vcpu->arch.vpa.pinned_addr);
297 }
298 if (vcpu->arch.dtl.update_pending) {
299 kvmppc_update_vpa(kvm, &vcpu->arch.dtl);
300 vcpu->arch.dtl_ptr = vcpu->arch.dtl.pinned_addr;
301 vcpu->arch.dtl_index = 0;
302 }
303 if (vcpu->arch.slb_shadow.update_pending)
304 kvmppc_update_vpa(kvm, &vcpu->arch.slb_shadow);
305 spin_unlock(&vcpu->arch.vpa_update_lock);
306}
307
227int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu) 308int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
228{ 309{
229 unsigned long req = kvmppc_get_gpr(vcpu, 3); 310 unsigned long req = kvmppc_get_gpr(vcpu, 3);
@@ -468,6 +549,7 @@ struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id)
468 /* default to host PVR, since we can't spoof it */ 549 /* default to host PVR, since we can't spoof it */
469 vcpu->arch.pvr = mfspr(SPRN_PVR); 550 vcpu->arch.pvr = mfspr(SPRN_PVR);
470 kvmppc_set_pvr(vcpu, vcpu->arch.pvr); 551 kvmppc_set_pvr(vcpu, vcpu->arch.pvr);
552 spin_lock_init(&vcpu->arch.vpa_update_lock);
471 553
472 kvmppc_mmu_book3s_hv_init(vcpu); 554 kvmppc_mmu_book3s_hv_init(vcpu);
473 555
@@ -512,12 +594,14 @@ out:
512 594
513void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) 595void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu)
514{ 596{
515 if (vcpu->arch.dtl) 597 spin_lock(&vcpu->arch.vpa_update_lock);
516 kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.dtl); 598 if (vcpu->arch.dtl.pinned_addr)
517 if (vcpu->arch.slb_shadow) 599 kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.dtl.pinned_addr);
518 kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.slb_shadow); 600 if (vcpu->arch.slb_shadow.pinned_addr)
519 if (vcpu->arch.vpa) 601 kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.slb_shadow.pinned_addr);
520 kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.vpa); 602 if (vcpu->arch.vpa.pinned_addr)
603 kvmppc_unpin_guest_page(vcpu->kvm, vcpu->arch.vpa.pinned_addr);
604 spin_unlock(&vcpu->arch.vpa_update_lock);
521 kvm_vcpu_uninit(vcpu); 605 kvm_vcpu_uninit(vcpu);
522 kmem_cache_free(kvm_vcpu_cache, vcpu); 606 kmem_cache_free(kvm_vcpu_cache, vcpu);
523} 607}
@@ -722,8 +806,13 @@ static int kvmppc_run_core(struct kvmppc_vcore *vc)
722 vc->in_guest = 0; 806 vc->in_guest = 0;
723 vc->pcpu = smp_processor_id(); 807 vc->pcpu = smp_processor_id();
724 vc->napping_threads = 0; 808 vc->napping_threads = 0;
725 list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) 809 list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) {
726 kvmppc_start_thread(vcpu); 810 kvmppc_start_thread(vcpu);
811 if (vcpu->arch.vpa.update_pending ||
812 vcpu->arch.slb_shadow.update_pending ||
813 vcpu->arch.dtl.update_pending)
814 kvmppc_update_vpas(vcpu);
815 }
727 /* Grab any remaining hw threads so they can't go into the kernel */ 816 /* Grab any remaining hw threads so they can't go into the kernel */
728 for (i = ptid; i < threads_per_core; ++i) 817 for (i = ptid; i < threads_per_core; ++i)
729 kvmppc_grab_hwthread(vc->pcpu + i); 818 kvmppc_grab_hwthread(vc->pcpu + i);