static int mem_event_disable(struct domain *d, struct mem_event_domain *med) { if ( med->ring_page ) { struct vcpu *v; mem_event_ring_lock(med); if ( !list_empty(&med->wq.list) ) { mem_event_ring_unlock(med); return -EBUSY; } /* Free domU's event channel and leave the other one unbound */ free_xen_event_channel(d, med->xen_port); /* Unblock all vCPUs */ for_each_vcpu ( d, v ) { if ( test_and_clear_bit(med->pause_flag, &v->pause_flags) ) { vcpu_unpause(v); med->blocked--; } } destroy_ring_for_helper(&med->ring_page, med->ring_pg_struct); mem_event_ring_unlock(med); } return 0; }
void domain_vpl011_deinit(struct domain *d) { struct vpl011 *vpl011 = &d->arch.vpl011; if ( !vpl011->ring_buf ) return; free_xen_event_channel(d, vpl011->evtchn); destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page); }
int domain_vpl011_init(struct domain *d, struct vpl011_init_info *info) { int rc; struct vpl011 *vpl011 = &d->arch.vpl011; if ( vpl011->ring_buf ) return -EINVAL; /* Map the guest PFN to Xen address space. */ rc = prepare_ring_for_helper(d, gfn_x(info->gfn), &vpl011->ring_page, &vpl011->ring_buf); if ( rc < 0 ) goto out; rc = vgic_reserve_virq(d, GUEST_VPL011_SPI); if ( !rc ) { rc = -EINVAL; goto out1; } rc = alloc_unbound_xen_event_channel(d, 0, info->console_domid, vpl011_notification); if ( rc < 0 ) goto out2; vpl011->evtchn = info->evtchn = rc; spin_lock_init(&vpl011->lock); register_mmio_handler(d, &vpl011_mmio_handler, GUEST_PL011_BASE, GUEST_PL011_SIZE, NULL); return 0; out2: vgic_free_virq(d, GUEST_VPL011_SPI); out1: destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page); out: return rc; }
static int mem_event_enable( struct domain *d, xen_domctl_mem_event_op_t *mec, struct mem_event_domain *med, int pause_flag, int param, xen_event_channel_notification_t notification_fn) { int rc; unsigned long ring_gfn = d->arch.hvm_domain.params[param]; /* Only one helper at a time. If the helper crashed, * the ring is in an undefined state and so is the guest. */ if ( med->ring_page ) return -EBUSY; /* The parameter defaults to zero, and it should be * set to something */ if ( ring_gfn == 0 ) return -ENOSYS; mem_event_ring_lock_init(med); mem_event_ring_lock(med); rc = prepare_ring_for_helper(d, ring_gfn, &med->ring_pg_struct, &med->ring_page); if ( rc < 0 ) goto err; /* Set the number of currently blocked vCPUs to 0. */ med->blocked = 0; /* Allocate event channel */ rc = alloc_unbound_xen_event_channel(d, 0, current->domain->domain_id, notification_fn); if ( rc < 0 ) goto err; med->xen_port = mec->port = rc; /* Prepare ring buffer */ FRONT_RING_INIT(&med->front_ring, (mem_event_sring_t *)med->ring_page, PAGE_SIZE); /* Save the pause flag for this particular ring. */ med->pause_flag = pause_flag; /* Initialize the last-chance wait queue. */ init_waitqueue_head(&med->wq); mem_event_ring_unlock(med); return 0; err: destroy_ring_for_helper(&med->ring_page, med->ring_pg_struct); mem_event_ring_unlock(med); return rc; }