Lines Matching +full:uv +full:- +full:shutdown
1 // SPDX-License-Identifier: GPL-2.0-only
5 * Interface to privileged domain-0 commands.
7 * Copyright (c) 2002-2004, K A Fraser, B Dragovic
43 #include <xen/xen-ops.h>
74 struct privcmd_data *data = file->private_data; in privcmd_ioctl_hypercall()
79 if (data->domid != DOMID_INVALID) in privcmd_ioctl_hypercall()
80 return -EPERM; in privcmd_ioctl_hypercall()
83 return -EFAULT; in privcmd_ioctl_hypercall()
124 while (nelem--) { in gather_array()
125 if (pageidx > PAGE_SIZE-size) { in gather_array()
128 ret = -ENOMEM; in gather_array()
134 list_add_tail(&page->lru, pagelist); in gather_array()
138 ret = -EFAULT; in gather_array()
170 while (nelem--) { in traverse_pages()
171 if (pageidx > PAGE_SIZE-size) { in traverse_pages()
173 pos = pos->next; in traverse_pages()
207 pos = pos->next; in traverse_pages_block()
213 nelem -= nr; in traverse_pages_block()
229 struct vm_area_struct *vma = st->vma; in mmap_gfn_range()
233 if ((msg->npages > (LONG_MAX >> PAGE_SHIFT)) || in mmap_gfn_range()
234 ((unsigned long)(msg->npages << PAGE_SHIFT) >= -st->va)) in mmap_gfn_range()
235 return -EINVAL; in mmap_gfn_range()
238 if ((msg->va != st->va) || in mmap_gfn_range()
239 ((msg->va+(msg->npages<<PAGE_SHIFT)) > vma->vm_end)) in mmap_gfn_range()
240 return -EINVAL; in mmap_gfn_range()
243 msg->va & PAGE_MASK, in mmap_gfn_range()
244 msg->mfn, msg->npages, in mmap_gfn_range()
245 vma->vm_page_prot, in mmap_gfn_range()
246 st->domain, NULL); in mmap_gfn_range()
250 st->va += msg->npages << PAGE_SHIFT; in mmap_gfn_range()
257 struct privcmd_data *data = file->private_data; in privcmd_ioctl_mmap()
259 struct mm_struct *mm = current->mm; in privcmd_ioctl_mmap()
265 /* We only support privcmd_ioctl_mmap_batch for non-auto-translated. */ in privcmd_ioctl_mmap()
267 return -ENOSYS; in privcmd_ioctl_mmap()
270 return -EFAULT; in privcmd_ioctl_mmap()
273 if (data->domid != DOMID_INVALID && data->domid != mmapcmd.dom) in privcmd_ioctl_mmap()
274 return -EPERM; in privcmd_ioctl_mmap()
290 vma = vma_lookup(mm, msg->va); in privcmd_ioctl_mmap()
291 rc = -EINVAL; in privcmd_ioctl_mmap()
293 if (!vma || (msg->va != vma->vm_start) || vma->vm_private_data) in privcmd_ioctl_mmap()
295 vma->vm_private_data = PRIV_VMA_LOCKED; in privcmd_ioctl_mmap()
298 state.va = vma->vm_start; in privcmd_ioctl_mmap()
324 * -ENOENT errors have happened)
325 * -ENOENT if at least 1 -ENOENT has happened.
330 /* User-space gfn array to store errors in the second pass for V1. */
332 /* User-space int array to store errors in the second pass for V2. */
343 struct vm_area_struct *vma = st->vma; in mmap_batch_fn()
344 struct page **pages = vma->vm_private_data; in mmap_batch_fn()
349 cur_pages = &pages[st->index]; in mmap_batch_fn()
352 ret = xen_remap_domain_gfn_array(st->vma, st->va & PAGE_MASK, gfnp, nr, in mmap_batch_fn()
353 (int *)gfnp, st->vma->vm_page_prot, in mmap_batch_fn()
354 st->domain, cur_pages); in mmap_batch_fn()
358 if (ret == -ENOENT) in mmap_batch_fn()
359 st->global_error = -ENOENT; in mmap_batch_fn()
362 if (st->global_error == 0) in mmap_batch_fn()
363 st->global_error = 1; in mmap_batch_fn()
366 st->va += XEN_PAGE_SIZE * nr; in mmap_batch_fn()
367 st->index += nr / XEN_PFN_PER_PAGE; in mmap_batch_fn()
376 if (st->version == 1) { in mmap_return_error()
380 ret = get_user(gfn, st->user_gfn); in mmap_return_error()
386 * limitations vis-a-vis 64 bit callers). in mmap_return_error()
388 gfn |= (err == -ENOENT) ? in mmap_return_error()
391 return __put_user(gfn, st->user_gfn++); in mmap_return_error()
393 st->user_gfn++; in mmap_return_error()
394 } else { /* st->version == 2 */ in mmap_return_error()
396 return __put_user(err, st->user_err++); in mmap_return_error()
398 st->user_err++; in mmap_return_error()
421 * Returns: 0 if success, otherwise -errno
430 return -ENOMEM; in alloc_empty_pages()
437 return -ENOMEM; in alloc_empty_pages()
439 BUG_ON(vma->vm_private_data != NULL); in alloc_empty_pages()
440 vma->vm_private_data = pages; in alloc_empty_pages()
450 struct privcmd_data *data = file->private_data; in privcmd_ioctl_mmap_batch()
453 struct mm_struct *mm = current->mm; in privcmd_ioctl_mmap_batch()
462 return -EFAULT; in privcmd_ioctl_mmap_batch()
463 /* Returns per-frame error in m.arr. */ in privcmd_ioctl_mmap_batch()
466 return -EFAULT; in privcmd_ioctl_mmap_batch()
470 return -EFAULT; in privcmd_ioctl_mmap_batch()
471 /* Returns per-frame error code in m.err. */ in privcmd_ioctl_mmap_batch()
473 return -EFAULT; in privcmd_ioctl_mmap_batch()
476 return -EINVAL; in privcmd_ioctl_mmap_batch()
480 if (data->domid != DOMID_INVALID && data->domid != m.dom) in privcmd_ioctl_mmap_batch()
481 return -EPERM; in privcmd_ioctl_mmap_batch()
485 return -EINVAL; in privcmd_ioctl_mmap_batch()
492 ret = -EINVAL; in privcmd_ioctl_mmap_batch()
499 ret = -EFAULT; in privcmd_ioctl_mmap_batch()
508 vma->vm_ops != &privcmd_vm_ops) { in privcmd_ioctl_mmap_batch()
509 ret = -EINVAL; in privcmd_ioctl_mmap_batch()
524 if (vma->vm_private_data == NULL) { in privcmd_ioctl_mmap_batch()
525 if (m.addr != vma->vm_start || in privcmd_ioctl_mmap_batch()
526 m.addr + (nr_pages << PAGE_SHIFT) != vma->vm_end) { in privcmd_ioctl_mmap_batch()
527 ret = -EINVAL; in privcmd_ioctl_mmap_batch()
535 vma->vm_private_data = PRIV_VMA_LOCKED; in privcmd_ioctl_mmap_batch()
537 if (m.addr < vma->vm_start || in privcmd_ioctl_mmap_batch()
538 m.addr + (nr_pages << PAGE_SHIFT) > vma->vm_end) { in privcmd_ioctl_mmap_batch()
539 ret = -EINVAL; in privcmd_ioctl_mmap_batch()
543 ret = -EINVAL; in privcmd_ioctl_mmap_batch()
571 /* If we have not had any EFAULT-like global errors then set the global in privcmd_ioctl_mmap_batch()
572 * error to -ENOENT if necessary. */ in privcmd_ioctl_mmap_batch()
573 if ((ret == 0) && (state.global_error == -ENOENT)) in privcmd_ioctl_mmap_batch()
574 ret = -ENOENT; in privcmd_ioctl_mmap_batch()
597 PAGE_SIZE) - off; in lock_pages()
599 return -ENOSPC; in lock_pages()
605 return page_count ? : -EFAULT; in lock_pages()
608 nr_pages -= page_count; in lock_pages()
625 struct privcmd_data *data = file->private_data; in privcmd_ioctl_dm_op()
636 return -EFAULT; in privcmd_ioctl_dm_op()
639 if (data->domid != DOMID_INVALID && data->domid != kdata.dom) in privcmd_ioctl_dm_op()
640 return -EPERM; in privcmd_ioctl_dm_op()
646 return -E2BIG; in privcmd_ioctl_dm_op()
650 return -ENOMEM; in privcmd_ioctl_dm_op()
654 rc = -EFAULT; in privcmd_ioctl_dm_op()
660 rc = -E2BIG; in privcmd_ioctl_dm_op()
666 rc = -EFAULT; in privcmd_ioctl_dm_op()
677 rc = -ENOMEM; in privcmd_ioctl_dm_op()
683 rc = -ENOMEM; in privcmd_ioctl_dm_op()
711 struct privcmd_data *data = file->private_data; in privcmd_ioctl_restrict()
715 return -EFAULT; in privcmd_ioctl_restrict()
718 if (data->domid == DOMID_INVALID) in privcmd_ioctl_restrict()
719 data->domid = dom; in privcmd_ioctl_restrict()
720 else if (data->domid != dom) in privcmd_ioctl_restrict()
721 return -EINVAL; in privcmd_ioctl_restrict()
729 struct privcmd_data *data = file->private_data; in privcmd_ioctl_mmap_resource()
730 struct mm_struct *mm = current->mm; in privcmd_ioctl_mmap_resource()
738 return -EFAULT; in privcmd_ioctl_mmap_resource()
741 if (data->domid != DOMID_INVALID && data->domid != kdata.dom) in privcmd_ioctl_mmap_resource()
742 return -EPERM; in privcmd_ioctl_mmap_resource()
746 return -EINVAL; in privcmd_ioctl_mmap_resource()
757 return __put_user(xdata.nr_frames, &udata->num); in privcmd_ioctl_mmap_resource()
763 if (!vma || vma->vm_ops != &privcmd_vm_ops) { in privcmd_ioctl_mmap_resource()
764 rc = -EINVAL; in privcmd_ioctl_mmap_resource()
770 rc = -ENOMEM; in privcmd_ioctl_mmap_resource()
784 pages = vma->vm_private_data; in privcmd_ioctl_mmap_resource()
792 vma->vm_private_data = PRIV_VMA_LOCKED; in privcmd_ioctl_mmap_resource()
818 vma->vm_page_prot, in privcmd_ioctl_mmap_resource()
852 struct work_struct shutdown; member
862 list_del_init(&kirqfd->list); in irqfd_deactivate()
863 queue_work(irqfd_cleanup_wq, &kirqfd->shutdown); in irqfd_deactivate()
869 container_of(work, struct privcmd_kernel_irqfd, shutdown); in irqfd_shutdown()
872 eventfd_ctx_remove_wait_queue(kirqfd->eventfd, &kirqfd->wait, &cnt); in irqfd_shutdown()
873 eventfd_ctx_put(kirqfd->eventfd); in irqfd_shutdown()
882 eventfd_ctx_do_read(kirqfd->eventfd, &cnt); in irqfd_inject()
885 rc = HYPERVISOR_dm_op(kirqfd->dom, 1, &kirqfd->xbufs); in irqfd_inject()
889 if (rc && !kirqfd->error) { in irqfd_inject()
891 kirqfd->dom); in irqfd_inject()
894 kirqfd->error = rc; in irqfd_inject()
922 add_wait_queue_priority(wqh, &kirqfd->wait); in irqfd_poll_func()
933 kirqfd = kzalloc(sizeof(*kirqfd) + irqfd->size, GFP_KERNEL); in privcmd_irqfd_assign()
935 return -ENOMEM; in privcmd_irqfd_assign()
938 if (copy_from_user(dm_op, u64_to_user_ptr(irqfd->dm_op), irqfd->size)) { in privcmd_irqfd_assign()
939 ret = -EFAULT; in privcmd_irqfd_assign()
943 kirqfd->xbufs.size = irqfd->size; in privcmd_irqfd_assign()
944 set_xen_guest_handle(kirqfd->xbufs.h, dm_op); in privcmd_irqfd_assign()
945 kirqfd->dom = irqfd->dom; in privcmd_irqfd_assign()
946 INIT_WORK(&kirqfd->shutdown, irqfd_shutdown); in privcmd_irqfd_assign()
948 f = fdget(irqfd->fd); in privcmd_irqfd_assign()
950 ret = -EBADF; in privcmd_irqfd_assign()
954 kirqfd->eventfd = eventfd_ctx_fileget(f.file); in privcmd_irqfd_assign()
955 if (IS_ERR(kirqfd->eventfd)) { in privcmd_irqfd_assign()
956 ret = PTR_ERR(kirqfd->eventfd); in privcmd_irqfd_assign()
961 * Install our own custom wake-up handling so we are notified via a in privcmd_irqfd_assign()
964 init_waitqueue_func_entry(&kirqfd->wait, irqfd_wakeup); in privcmd_irqfd_assign()
965 init_poll_funcptr(&kirqfd->pt, irqfd_poll_func); in privcmd_irqfd_assign()
970 if (kirqfd->eventfd == tmp->eventfd) { in privcmd_irqfd_assign()
971 ret = -EBUSY; in privcmd_irqfd_assign()
977 list_add_tail(&kirqfd->list, &irqfds_list); in privcmd_irqfd_assign()
984 events = vfs_poll(f.file, &kirqfd->pt); in privcmd_irqfd_assign()
996 eventfd_ctx_put(kirqfd->eventfd); in privcmd_irqfd_assign()
1011 eventfd = eventfd_ctx_fdget(irqfd->fd); in privcmd_irqfd_deassign()
1018 if (kirqfd->eventfd == eventfd) { in privcmd_irqfd_deassign()
1029 * Block until we know all outstanding shutdown jobs have completed so in privcmd_irqfd_deassign()
1040 struct privcmd_data *data = file->private_data; in privcmd_ioctl_irqfd()
1044 return -EFAULT; in privcmd_ioctl_irqfd()
1048 return -EINVAL; in privcmd_ioctl_irqfd()
1051 if (data->domid != DOMID_INVALID && data->domid != irqfd.dom) in privcmd_ioctl_irqfd()
1052 return -EPERM; in privcmd_ioctl_irqfd()
1062 irqfd_cleanup_wq = alloc_workqueue("privcmd-irqfd-cleanup", 0, 0); in privcmd_irqfd_init()
1064 return -ENOMEM; in privcmd_irqfd_init()
1085 return -EOPNOTSUPP; in privcmd_ioctl_irqfd()
1101 int ret = -ENOTTY; in privcmd_ioctl()
1149 return -ENOMEM; in privcmd_open()
1152 data->domid = DOMID_INVALID; in privcmd_open()
1154 file->private_data = data; in privcmd_open()
1160 struct privcmd_data *data = file->private_data; in privcmd_release()
1168 struct page **pages = vma->vm_private_data; in privcmd_close()
1170 int numgfns = (vma->vm_end - vma->vm_start) >> XEN_PAGE_SHIFT; in privcmd_close()
1187 printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n", in privcmd_fault()
1188 vmf->vma, vmf->vma->vm_start, vmf->vma->vm_end, in privcmd_fault()
1189 vmf->pgoff, (void *)vmf->address); in privcmd_fault()
1205 vma->vm_ops = &privcmd_vm_ops; in privcmd_mmap()
1206 vma->vm_private_data = NULL; in privcmd_mmap()
1218 return pte_none(ptep_get(pte)) ? 0 : -EBUSY; in is_mapped_fn()
1226 return apply_to_page_range(vma->vm_mm, addr, nr_pages << PAGE_SHIFT, in privcmd_vma_range_is_mapped()
1250 return -ENODEV; in privcmd_init()
1260 pr_err("Could not register Xen hypercall-buf device\n"); in privcmd_init()