1 /******************************************************************************
2 * vm_event.c
3 *
4 * VM event support.
5 *
6 * Copyright (c) 2009 Citrix Systems, Inc. (Patrick Colp)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; If not, see <http://www.gnu.org/licenses/>.
20 */
21
22
23 #include <xen/sched.h>
24 #include <xen/event.h>
25 #include <xen/wait.h>
26 #include <xen/vm_event.h>
27 #include <xen/mem_access.h>
28 #include <asm/p2m.h>
29 #include <asm/monitor.h>
30 #include <asm/vm_event.h>
31 #include <xsm/xsm.h>
32 #include <public/hvm/params.h>
33
34 /* for public/io/ring.h macros */
35 #define xen_mb() smp_mb()
36 #define xen_rmb() smp_rmb()
37 #define xen_wmb() smp_wmb()
38
vm_event_enable(struct domain * d,struct xen_domctl_vm_event_op * vec,struct vm_event_domain ** p_ved,int pause_flag,int param,xen_event_channel_notification_t notification_fn)39 static int vm_event_enable(
40 struct domain *d,
41 struct xen_domctl_vm_event_op *vec,
42 struct vm_event_domain **p_ved,
43 int pause_flag,
44 int param,
45 xen_event_channel_notification_t notification_fn)
46 {
47 int rc;
48 unsigned long ring_gfn = d->arch.hvm.params[param];
49 struct vm_event_domain *ved;
50
51 /*
52 * Only one connected agent at a time. If the helper crashed, the ring is
53 * in an undefined state, and the guest is most likely unrecoverable.
54 */
55 if ( *p_ved != NULL )
56 return -EBUSY;
57
58 /* No chosen ring GFN? Nothing we can do. */
59 if ( ring_gfn == 0 )
60 return -EOPNOTSUPP;
61
62 ved = xzalloc(struct vm_event_domain);
63 if ( !ved )
64 return -ENOMEM;
65
66 /* Trivial setup. */
67 spin_lock_init(&ved->lock);
68 init_waitqueue_head(&ved->wq);
69 ved->pause_flag = pause_flag;
70
71 rc = vm_event_init_domain(d);
72 if ( rc < 0 )
73 goto err;
74
75 rc = prepare_ring_for_helper(d, ring_gfn, &ved->ring_pg_struct,
76 &ved->ring_page);
77 if ( rc < 0 )
78 goto err;
79
80 FRONT_RING_INIT(&ved->front_ring,
81 (vm_event_sring_t *)ved->ring_page,
82 PAGE_SIZE);
83
84 rc = alloc_unbound_xen_event_channel(d, 0, current->domain->domain_id,
85 notification_fn);
86 if ( rc < 0 )
87 goto err;
88
89 ved->xen_port = vec->u.enable.port = rc;
90
91 /* Success. Fill in the domain's appropriate ved. */
92 *p_ved = ved;
93
94 return 0;
95
96 err:
97 destroy_ring_for_helper(&ved->ring_page, ved->ring_pg_struct);
98 xfree(ved);
99
100 return rc;
101 }
102
vm_event_ring_available(struct vm_event_domain * ved)103 static unsigned int vm_event_ring_available(struct vm_event_domain *ved)
104 {
105 int avail_req = RING_FREE_REQUESTS(&ved->front_ring);
106
107 avail_req -= ved->target_producers;
108 avail_req -= ved->foreign_producers;
109
110 BUG_ON(avail_req < 0);
111
112 return avail_req;
113 }
114
115 /*
116 * vm_event_wake_blocked() will wakeup vcpus waiting for room in the
117 * ring. These vCPUs were paused on their way out after placing an event,
118 * but need to be resumed where the ring is capable of processing at least
119 * one event from them.
120 */
vm_event_wake_blocked(struct domain * d,struct vm_event_domain * ved)121 static void vm_event_wake_blocked(struct domain *d, struct vm_event_domain *ved)
122 {
123 struct vcpu *v;
124 unsigned int i, j, k, avail_req = vm_event_ring_available(ved);
125
126 if ( avail_req == 0 || ved->blocked == 0 )
127 return;
128
129 /* We remember which vcpu last woke up to avoid scanning always linearly
130 * from zero and starving higher-numbered vcpus under high load */
131 for ( i = ved->last_vcpu_wake_up + 1, j = 0; j < d->max_vcpus; i++, j++ )
132 {
133 k = i % d->max_vcpus;
134 v = d->vcpu[k];
135 if ( !v )
136 continue;
137
138 if ( !ved->blocked || avail_req == 0 )
139 break;
140
141 if ( test_and_clear_bit(ved->pause_flag, &v->pause_flags) )
142 {
143 vcpu_unpause(v);
144 avail_req--;
145 ved->blocked--;
146 ved->last_vcpu_wake_up = k;
147 }
148 }
149 }
150
151 /*
152 * In the event that a vCPU attempted to place an event in the ring and
153 * was unable to do so, it is queued on a wait queue. These are woken as
154 * needed, and take precedence over the blocked vCPUs.
155 */
vm_event_wake_queued(struct domain * d,struct vm_event_domain * ved)156 static void vm_event_wake_queued(struct domain *d, struct vm_event_domain *ved)
157 {
158 unsigned int avail_req = vm_event_ring_available(ved);
159
160 if ( avail_req > 0 )
161 wake_up_nr(&ved->wq, avail_req);
162 }
163
164 /*
165 * vm_event_wake() will wakeup all vcpus waiting for the ring to
166 * become available. If we have queued vCPUs, they get top priority. We
167 * are guaranteed that they will go through code paths that will eventually
168 * call vm_event_wake() again, ensuring that any blocked vCPUs will get
169 * unpaused once all the queued vCPUs have made it through.
170 */
vm_event_wake(struct domain * d,struct vm_event_domain * ved)171 void vm_event_wake(struct domain *d, struct vm_event_domain *ved)
172 {
173 if ( !list_empty(&ved->wq.list) )
174 vm_event_wake_queued(d, ved);
175 else
176 vm_event_wake_blocked(d, ved);
177 }
178
vm_event_disable(struct domain * d,struct vm_event_domain ** p_ved)179 static int vm_event_disable(struct domain *d, struct vm_event_domain **p_ved)
180 {
181 struct vm_event_domain *ved = *p_ved;
182
183 if ( vm_event_check_ring(ved) )
184 {
185 struct vcpu *v;
186
187 spin_lock(&ved->lock);
188
189 if ( !list_empty(&ved->wq.list) )
190 {
191 spin_unlock(&ved->lock);
192 return -EBUSY;
193 }
194
195 /* Free domU's event channel and leave the other one unbound */
196 free_xen_event_channel(d, ved->xen_port);
197
198 /* Unblock all vCPUs */
199 for_each_vcpu ( d, v )
200 {
201 if ( test_and_clear_bit(ved->pause_flag, &v->pause_flags) )
202 {
203 vcpu_unpause(v);
204 ved->blocked--;
205 }
206 }
207
208 destroy_ring_for_helper(&ved->ring_page, ved->ring_pg_struct);
209
210 vm_event_cleanup_domain(d);
211
212 spin_unlock(&ved->lock);
213 }
214
215 xfree(ved);
216 *p_ved = NULL;
217
218 return 0;
219 }
220
vm_event_release_slot(struct domain * d,struct vm_event_domain * ved)221 static void vm_event_release_slot(struct domain *d,
222 struct vm_event_domain *ved)
223 {
224 /* Update the accounting */
225 if ( current->domain == d )
226 ved->target_producers--;
227 else
228 ved->foreign_producers--;
229
230 /* Kick any waiters */
231 vm_event_wake(d, ved);
232 }
233
234 /*
235 * vm_event_mark_and_pause() tags vcpu and put it to sleep.
236 * The vcpu will resume execution in vm_event_wake_blocked().
237 */
vm_event_mark_and_pause(struct vcpu * v,struct vm_event_domain * ved)238 static void vm_event_mark_and_pause(struct vcpu *v, struct vm_event_domain *ved)
239 {
240 if ( !test_and_set_bit(ved->pause_flag, &v->pause_flags) )
241 {
242 vcpu_pause_nosync(v);
243 ved->blocked++;
244 }
245 }
246
247 /*
248 * This must be preceded by a call to claim_slot(), and is guaranteed to
249 * succeed. As a side-effect however, the vCPU may be paused if the ring is
250 * overly full and its continued execution would cause stalling and excessive
251 * waiting. The vCPU will be automatically unpaused when the ring clears.
252 */
vm_event_put_request(struct domain * d,struct vm_event_domain * ved,vm_event_request_t * req)253 void vm_event_put_request(struct domain *d,
254 struct vm_event_domain *ved,
255 vm_event_request_t *req)
256 {
257 vm_event_front_ring_t *front_ring;
258 int free_req;
259 unsigned int avail_req;
260 RING_IDX req_prod;
261 struct vcpu *curr = current;
262
263 if( !vm_event_check_ring(ved) )
264 return;
265
266 if ( curr->domain != d )
267 {
268 req->flags |= VM_EVENT_FLAG_FOREIGN;
269
270 if ( !(req->flags & VM_EVENT_FLAG_VCPU_PAUSED) )
271 gdprintk(XENLOG_WARNING, "d%dv%d was not paused.\n",
272 d->domain_id, req->vcpu_id);
273 }
274
275 req->version = VM_EVENT_INTERFACE_VERSION;
276
277 spin_lock(&ved->lock);
278
279 /* Due to the reservations, this step must succeed. */
280 front_ring = &ved->front_ring;
281 free_req = RING_FREE_REQUESTS(front_ring);
282 ASSERT(free_req > 0);
283
284 /* Copy request */
285 req_prod = front_ring->req_prod_pvt;
286 memcpy(RING_GET_REQUEST(front_ring, req_prod), req, sizeof(*req));
287 req_prod++;
288
289 /* Update ring */
290 front_ring->req_prod_pvt = req_prod;
291 RING_PUSH_REQUESTS(front_ring);
292
293 /* We've actually *used* our reservation, so release the slot. */
294 vm_event_release_slot(d, ved);
295
296 /* Give this vCPU a black eye if necessary, on the way out.
297 * See the comments above wake_blocked() for more information
298 * on how this mechanism works to avoid waiting. */
299 avail_req = vm_event_ring_available(ved);
300 if( curr->domain == d && avail_req < d->max_vcpus &&
301 !atomic_read(&curr->vm_event_pause_count) )
302 vm_event_mark_and_pause(curr, ved);
303
304 spin_unlock(&ved->lock);
305
306 notify_via_xen_event_channel(d, ved->xen_port);
307 }
308
vm_event_get_response(struct domain * d,struct vm_event_domain * ved,vm_event_response_t * rsp)309 static int vm_event_get_response(struct domain *d, struct vm_event_domain *ved,
310 vm_event_response_t *rsp)
311 {
312 vm_event_front_ring_t *front_ring;
313 RING_IDX rsp_cons;
314 int rc = 0;
315
316 spin_lock(&ved->lock);
317
318 front_ring = &ved->front_ring;
319 rsp_cons = front_ring->rsp_cons;
320
321 if ( !RING_HAS_UNCONSUMED_RESPONSES(front_ring) )
322 goto out;
323
324 /* Copy response */
325 memcpy(rsp, RING_GET_RESPONSE(front_ring, rsp_cons), sizeof(*rsp));
326 rsp_cons++;
327
328 /* Update ring */
329 front_ring->rsp_cons = rsp_cons;
330 front_ring->sring->rsp_event = rsp_cons + 1;
331
332 /* Kick any waiters -- since we've just consumed an event,
333 * there may be additional space available in the ring. */
334 vm_event_wake(d, ved);
335
336 rc = 1;
337
338 out:
339 spin_unlock(&ved->lock);
340
341 return rc;
342 }
343
344 /*
345 * Pull all responses from the given ring and unpause the corresponding vCPU
346 * if required. Based on the response type, here we can also call custom
347 * handlers.
348 *
349 * Note: responses are handled the same way regardless of which ring they
350 * arrive on.
351 */
vm_event_resume(struct domain * d,struct vm_event_domain * ved)352 static int vm_event_resume(struct domain *d, struct vm_event_domain *ved)
353 {
354 vm_event_response_t rsp;
355
356 /*
357 * vm_event_resume() runs in either XEN_DOMCTL_VM_EVENT_OP_*, or
358 * EVTCHN_send context from the introspection consumer. Both contexts
359 * are guaranteed not to be the subject of vm_event responses.
360 * While we could ASSERT(v != current) for each VCPU in d in the loop
361 * below, this covers the case where we would need to iterate over all
362 * of them more succintly.
363 */
364 ASSERT(d != current->domain);
365
366 if ( unlikely(!vm_event_check_ring(ved)) )
367 return -ENODEV;
368
369 /* Pull all responses off the ring. */
370 while ( vm_event_get_response(d, ved, &rsp) )
371 {
372 struct vcpu *v;
373
374 if ( rsp.version != VM_EVENT_INTERFACE_VERSION )
375 {
376 printk(XENLOG_G_WARNING "vm_event interface version mismatch\n");
377 continue;
378 }
379
380 /* Validate the vcpu_id in the response. */
381 v = domain_vcpu(d, rsp.vcpu_id);
382 if ( !v )
383 continue;
384
385 /*
386 * In some cases the response type needs extra handling, so here
387 * we call the appropriate handlers.
388 */
389
390 /* Check flags which apply only when the vCPU is paused */
391 if ( atomic_read(&v->vm_event_pause_count) )
392 {
393 #ifdef CONFIG_HAS_MEM_PAGING
394 if ( rsp.reason == VM_EVENT_REASON_MEM_PAGING )
395 p2m_mem_paging_resume(d, &rsp);
396 #endif
397
398 /*
399 * Check emulation flags in the arch-specific handler only, as it
400 * has to set arch-specific flags when supported, and to avoid
401 * bitmask overhead when it isn't supported.
402 */
403 vm_event_emulate_check(v, &rsp);
404
405 /*
406 * Check in arch-specific handler to avoid bitmask overhead when
407 * not supported.
408 */
409 vm_event_register_write_resume(v, &rsp);
410
411 /*
412 * Check in arch-specific handler to avoid bitmask overhead when
413 * not supported.
414 */
415 vm_event_toggle_singlestep(d, v, &rsp);
416
417 /* Check for altp2m switch */
418 if ( rsp.flags & VM_EVENT_FLAG_ALTERNATE_P2M )
419 p2m_altp2m_check(v, rsp.altp2m_idx);
420
421 if ( rsp.flags & VM_EVENT_FLAG_SET_REGISTERS )
422 vm_event_set_registers(v, &rsp);
423
424 if ( rsp.flags & VM_EVENT_FLAG_GET_NEXT_INTERRUPT )
425 vm_event_monitor_next_interrupt(v);
426
427 if ( rsp.flags & VM_EVENT_FLAG_VCPU_PAUSED )
428 vm_event_vcpu_unpause(v);
429 }
430 }
431
432 return 0;
433 }
434
vm_event_cancel_slot(struct domain * d,struct vm_event_domain * ved)435 void vm_event_cancel_slot(struct domain *d, struct vm_event_domain *ved)
436 {
437 if( !vm_event_check_ring(ved) )
438 return;
439
440 spin_lock(&ved->lock);
441 vm_event_release_slot(d, ved);
442 spin_unlock(&ved->lock);
443 }
444
vm_event_grab_slot(struct vm_event_domain * ved,int foreign)445 static int vm_event_grab_slot(struct vm_event_domain *ved, int foreign)
446 {
447 unsigned int avail_req;
448 int rc;
449
450 if ( !ved->ring_page )
451 return -EOPNOTSUPP;
452
453 spin_lock(&ved->lock);
454
455 avail_req = vm_event_ring_available(ved);
456
457 rc = -EBUSY;
458 if ( avail_req == 0 )
459 goto out;
460
461 if ( !foreign )
462 ved->target_producers++;
463 else
464 ved->foreign_producers++;
465
466 rc = 0;
467
468 out:
469 spin_unlock(&ved->lock);
470
471 return rc;
472 }
473
474 /* Simple try_grab wrapper for use in the wait_event() macro. */
vm_event_wait_try_grab(struct vm_event_domain * ved,int * rc)475 static int vm_event_wait_try_grab(struct vm_event_domain *ved, int *rc)
476 {
477 *rc = vm_event_grab_slot(ved, 0);
478
479 return *rc;
480 }
481
482 /* Call vm_event_grab_slot() until the ring doesn't exist, or is available. */
vm_event_wait_slot(struct vm_event_domain * ved)483 static int vm_event_wait_slot(struct vm_event_domain *ved)
484 {
485 int rc = -EBUSY;
486
487 wait_event(ved->wq, vm_event_wait_try_grab(ved, &rc) != -EBUSY);
488
489 return rc;
490 }
491
vm_event_check_ring(struct vm_event_domain * ved)492 bool vm_event_check_ring(struct vm_event_domain *ved)
493 {
494 return ved && ved->ring_page;
495 }
496
497 /*
498 * Determines whether or not the current vCPU belongs to the target domain,
499 * and calls the appropriate wait function. If it is a guest vCPU, then we
500 * use vm_event_wait_slot() to reserve a slot. As long as there is a ring,
501 * this function will always return 0 for a guest. For a non-guest, we check
502 * for space and return -EBUSY if the ring is not available.
503 *
504 * Return codes: -EOPNOTSUPP: the ring is not yet configured
505 * -EBUSY: the ring is busy
506 * 0: a spot has been reserved
507 *
508 */
__vm_event_claim_slot(struct domain * d,struct vm_event_domain * ved,bool allow_sleep)509 int __vm_event_claim_slot(struct domain *d, struct vm_event_domain *ved,
510 bool allow_sleep)
511 {
512 if ( !vm_event_check_ring(ved) )
513 return -EOPNOTSUPP;
514
515 if ( (current->domain == d) && allow_sleep )
516 return vm_event_wait_slot(ved);
517 else
518 return vm_event_grab_slot(ved, current->domain != d);
519 }
520
521 #ifdef CONFIG_HAS_MEM_PAGING
522 /* Registered with Xen-bound event channel for incoming notifications. */
mem_paging_notification(struct vcpu * v,unsigned int port)523 static void mem_paging_notification(struct vcpu *v, unsigned int port)
524 {
525 vm_event_resume(v->domain, v->domain->vm_event_paging);
526 }
527 #endif
528
529 /* Registered with Xen-bound event channel for incoming notifications. */
monitor_notification(struct vcpu * v,unsigned int port)530 static void monitor_notification(struct vcpu *v, unsigned int port)
531 {
532 vm_event_resume(v->domain, v->domain->vm_event_monitor);
533 }
534
535 #ifdef CONFIG_MEM_SHARING
536 /* Registered with Xen-bound event channel for incoming notifications. */
mem_sharing_notification(struct vcpu * v,unsigned int port)537 static void mem_sharing_notification(struct vcpu *v, unsigned int port)
538 {
539 vm_event_resume(v->domain, v->domain->vm_event_share);
540 }
541 #endif
542
543 /* Clean up on domain destruction */
vm_event_cleanup(struct domain * d)544 void vm_event_cleanup(struct domain *d)
545 {
546 #ifdef CONFIG_HAS_MEM_PAGING
547 if ( vm_event_check_ring(d->vm_event_paging) )
548 {
549 /* Destroying the wait queue head means waking up all
550 * queued vcpus. This will drain the list, allowing
551 * the disable routine to complete. It will also drop
552 * all domain refs the wait-queued vcpus are holding.
553 * Finally, because this code path involves previously
554 * pausing the domain (domain_kill), unpausing the
555 * vcpus causes no harm. */
556 destroy_waitqueue_head(&d->vm_event_paging->wq);
557 (void)vm_event_disable(d, &d->vm_event_paging);
558 }
559 #endif
560 if ( vm_event_check_ring(d->vm_event_monitor) )
561 {
562 destroy_waitqueue_head(&d->vm_event_monitor->wq);
563 (void)vm_event_disable(d, &d->vm_event_monitor);
564 }
565 #ifdef CONFIG_MEM_SHARING
566 if ( vm_event_check_ring(d->vm_event_share) )
567 {
568 destroy_waitqueue_head(&d->vm_event_share->wq);
569 (void)vm_event_disable(d, &d->vm_event_share);
570 }
571 #endif
572 }
573
vm_event_domctl(struct domain * d,struct xen_domctl_vm_event_op * vec)574 int vm_event_domctl(struct domain *d, struct xen_domctl_vm_event_op *vec)
575 {
576 int rc;
577
578 if ( vec->op == XEN_VM_EVENT_GET_VERSION )
579 {
580 vec->u.version = VM_EVENT_INTERFACE_VERSION;
581 return 0;
582 }
583
584 rc = xsm_vm_event_control(XSM_PRIV, d, vec->mode, vec->op);
585 if ( rc )
586 return rc;
587
588 if ( unlikely(d == current->domain) ) /* no domain_pause() */
589 {
590 gdprintk(XENLOG_INFO, "Tried to do a memory event op on itself.\n");
591 return -EINVAL;
592 }
593
594 if ( unlikely(d->is_dying) )
595 {
596 gdprintk(XENLOG_INFO, "Ignoring memory event op on dying domain %u\n",
597 d->domain_id);
598 return 0;
599 }
600
601 if ( unlikely(d->vcpu == NULL) || unlikely(d->vcpu[0] == NULL) )
602 {
603 gdprintk(XENLOG_INFO,
604 "Memory event op on a domain (%u) with no vcpus\n",
605 d->domain_id);
606 return -EINVAL;
607 }
608
609 rc = -ENOSYS;
610
611 switch ( vec->mode )
612 {
613 #ifdef CONFIG_HAS_MEM_PAGING
614 case XEN_DOMCTL_VM_EVENT_OP_PAGING:
615 {
616 rc = -EINVAL;
617
618 switch( vec->op )
619 {
620 case XEN_VM_EVENT_ENABLE:
621 {
622 rc = -EOPNOTSUPP;
623 /* hvm fixme: p2m_is_foreign types need addressing */
624 if ( is_hvm_domain(hardware_domain) )
625 break;
626
627 rc = -ENODEV;
628 /* Only HAP is supported */
629 if ( !hap_enabled(d) )
630 break;
631
632 /* No paging if iommu is used */
633 rc = -EMLINK;
634 if ( unlikely(is_iommu_enabled(d)) )
635 break;
636
637 rc = -EXDEV;
638 /* Disallow paging in a PoD guest */
639 if ( p2m_pod_entry_count(p2m_get_hostp2m(d)) )
640 break;
641
642 /* domain_pause() not required here, see XSA-99 */
643 rc = vm_event_enable(d, vec, &d->vm_event_paging, _VPF_mem_paging,
644 HVM_PARAM_PAGING_RING_PFN,
645 mem_paging_notification);
646 }
647 break;
648
649 case XEN_VM_EVENT_DISABLE:
650 if ( vm_event_check_ring(d->vm_event_paging) )
651 {
652 domain_pause(d);
653 rc = vm_event_disable(d, &d->vm_event_paging);
654 domain_unpause(d);
655 }
656 break;
657
658 case XEN_VM_EVENT_RESUME:
659 rc = vm_event_resume(d, d->vm_event_paging);
660 break;
661
662 default:
663 rc = -ENOSYS;
664 break;
665 }
666 }
667 break;
668 #endif
669
670 case XEN_DOMCTL_VM_EVENT_OP_MONITOR:
671 {
672 rc = -EINVAL;
673
674 switch( vec->op )
675 {
676 case XEN_VM_EVENT_ENABLE:
677 /* domain_pause() not required here, see XSA-99 */
678 rc = arch_monitor_init_domain(d);
679 if ( rc )
680 break;
681 rc = vm_event_enable(d, vec, &d->vm_event_monitor, _VPF_mem_access,
682 HVM_PARAM_MONITOR_RING_PFN,
683 monitor_notification);
684 break;
685
686 case XEN_VM_EVENT_DISABLE:
687 if ( vm_event_check_ring(d->vm_event_monitor) )
688 {
689 domain_pause(d);
690 rc = vm_event_disable(d, &d->vm_event_monitor);
691 arch_monitor_cleanup_domain(d);
692 domain_unpause(d);
693 }
694 break;
695
696 case XEN_VM_EVENT_RESUME:
697 rc = vm_event_resume(d, d->vm_event_monitor);
698 break;
699
700 default:
701 rc = -ENOSYS;
702 break;
703 }
704 }
705 break;
706
707 #ifdef CONFIG_MEM_SHARING
708 case XEN_DOMCTL_VM_EVENT_OP_SHARING:
709 {
710 rc = -EINVAL;
711
712 switch( vec->op )
713 {
714 case XEN_VM_EVENT_ENABLE:
715 rc = -EOPNOTSUPP;
716 /* hvm fixme: p2m_is_foreign types need addressing */
717 if ( is_hvm_domain(hardware_domain) )
718 break;
719
720 rc = -ENODEV;
721 /* Only HAP is supported */
722 if ( !hap_enabled(d) )
723 break;
724
725 /* domain_pause() not required here, see XSA-99 */
726 rc = vm_event_enable(d, vec, &d->vm_event_share, _VPF_mem_sharing,
727 HVM_PARAM_SHARING_RING_PFN,
728 mem_sharing_notification);
729 break;
730
731 case XEN_VM_EVENT_DISABLE:
732 if ( vm_event_check_ring(d->vm_event_share) )
733 {
734 domain_pause(d);
735 rc = vm_event_disable(d, &d->vm_event_share);
736 domain_unpause(d);
737 }
738 break;
739
740 case XEN_VM_EVENT_RESUME:
741 rc = vm_event_resume(d, d->vm_event_share);
742 break;
743
744 default:
745 rc = -ENOSYS;
746 break;
747 }
748 }
749 break;
750 #endif
751
752 default:
753 rc = -ENOSYS;
754 }
755
756 return rc;
757 }
758
vm_event_vcpu_pause(struct vcpu * v)759 void vm_event_vcpu_pause(struct vcpu *v)
760 {
761 ASSERT(v == current);
762
763 atomic_inc(&v->vm_event_pause_count);
764 vcpu_pause_nosync(v);
765 }
766
vm_event_vcpu_unpause(struct vcpu * v)767 void vm_event_vcpu_unpause(struct vcpu *v)
768 {
769 int old, new, prev = v->vm_event_pause_count.counter;
770
771 /*
772 * All unpause requests as a result of toolstack responses.
773 * Prevent underflow of the vcpu pause count.
774 */
775 do
776 {
777 old = prev;
778 new = old - 1;
779
780 if ( new < 0 )
781 {
782 printk(XENLOG_G_WARNING
783 "%pv vm_event: Too many unpause attempts\n", v);
784 return;
785 }
786
787 prev = cmpxchg(&v->vm_event_pause_count.counter, old, new);
788 } while ( prev != old );
789
790 vcpu_unpause(v);
791 }
792
793 /*
794 * Local variables:
795 * mode: C
796 * c-file-style: "BSD"
797 * c-basic-offset: 4
798 * indent-tabs-mode: nil
799 * End:
800 */
801