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
44 #include <xen/xen-ops.h>
75 struct privcmd_data *data = file->private_data; in privcmd_ioctl_hypercall()
80 if (data->domid != DOMID_INVALID) in privcmd_ioctl_hypercall()
81 return -EPERM; in privcmd_ioctl_hypercall()
84 return -EFAULT; in privcmd_ioctl_hypercall()
125 while (nelem--) { in gather_array()
126 if (pageidx > PAGE_SIZE-size) { in gather_array()
129 ret = -ENOMEM; in gather_array()
135 list_add_tail(&page->lru, pagelist); in gather_array()
139 ret = -EFAULT; in gather_array()
171 while (nelem--) { in traverse_pages()
172 if (pageidx > PAGE_SIZE-size) { in traverse_pages()
174 pos = pos->next; in traverse_pages()
208 pos = pos->next; in traverse_pages_block()
214 nelem -= nr; in traverse_pages_block()
230 struct vm_area_struct *vma = st->vma; in mmap_gfn_range()
234 if ((msg->npages > (LONG_MAX >> PAGE_SHIFT)) || in mmap_gfn_range()
235 ((unsigned long)(msg->npages << PAGE_SHIFT) >= -st->va)) in mmap_gfn_range()
236 return -EINVAL; in mmap_gfn_range()
239 if ((msg->va != st->va) || in mmap_gfn_range()
240 ((msg->va+(msg->npages<<PAGE_SHIFT)) > vma->vm_end)) in mmap_gfn_range()
241 return -EINVAL; in mmap_gfn_range()
244 msg->va & PAGE_MASK, in mmap_gfn_range()
245 msg->mfn, msg->npages, in mmap_gfn_range()
246 vma->vm_page_prot, in mmap_gfn_range()
247 st->domain, NULL); in mmap_gfn_range()
251 st->va += msg->npages << PAGE_SHIFT; in mmap_gfn_range()
258 struct privcmd_data *data = file->private_data; in privcmd_ioctl_mmap()
260 struct mm_struct *mm = current->mm; in privcmd_ioctl_mmap()
266 /* We only support privcmd_ioctl_mmap_batch for non-auto-translated. */ in privcmd_ioctl_mmap()
268 return -ENOSYS; in privcmd_ioctl_mmap()
271 return -EFAULT; in privcmd_ioctl_mmap()
274 if (data->domid != DOMID_INVALID && data->domid != mmapcmd.dom) in privcmd_ioctl_mmap()
275 return -EPERM; in privcmd_ioctl_mmap()
291 vma = vma_lookup(mm, msg->va); in privcmd_ioctl_mmap()
292 rc = -EINVAL; in privcmd_ioctl_mmap()
294 if (!vma || (msg->va != vma->vm_start) || vma->vm_private_data) in privcmd_ioctl_mmap()
296 vma->vm_private_data = PRIV_VMA_LOCKED; in privcmd_ioctl_mmap()
299 state.va = vma->vm_start; in privcmd_ioctl_mmap()
325 * -ENOENT errors have happened)
326 * -ENOENT if at least 1 -ENOENT has happened.
331 /* User-space gfn array to store errors in the second pass for V1. */
333 /* User-space int array to store errors in the second pass for V2. */
344 struct vm_area_struct *vma = st->vma; in mmap_batch_fn()
345 struct page **pages = vma->vm_private_data; in mmap_batch_fn()
350 cur_pages = &pages[st->index]; in mmap_batch_fn()
353 ret = xen_remap_domain_gfn_array(st->vma, st->va & PAGE_MASK, gfnp, nr, in mmap_batch_fn()
354 (int *)gfnp, st->vma->vm_page_prot, in mmap_batch_fn()
355 st->domain, cur_pages); in mmap_batch_fn()
359 if (ret == -ENOENT) in mmap_batch_fn()
360 st->global_error = -ENOENT; in mmap_batch_fn()
363 if (st->global_error == 0) in mmap_batch_fn()
364 st->global_error = 1; in mmap_batch_fn()
367 st->va += XEN_PAGE_SIZE * nr; in mmap_batch_fn()
368 st->index += nr / XEN_PFN_PER_PAGE; in mmap_batch_fn()
377 if (st->version == 1) { in mmap_return_error()
381 ret = get_user(gfn, st->user_gfn); in mmap_return_error()
387 * limitations vis-a-vis 64 bit callers). in mmap_return_error()
389 gfn |= (err == -ENOENT) ? in mmap_return_error()
392 return __put_user(gfn, st->user_gfn++); in mmap_return_error()
394 st->user_gfn++; in mmap_return_error()
395 } else { /* st->version == 2 */ in mmap_return_error()
397 return __put_user(err, st->user_err++); in mmap_return_error()
399 st->user_err++; in mmap_return_error()
422 * Returns: 0 if success, otherwise -errno
431 return -ENOMEM; in alloc_empty_pages()
438 return -ENOMEM; in alloc_empty_pages()
440 BUG_ON(vma->vm_private_data != NULL); in alloc_empty_pages()
441 vma->vm_private_data = pages; in alloc_empty_pages()
451 struct privcmd_data *data = file->private_data; in privcmd_ioctl_mmap_batch()
454 struct mm_struct *mm = current->mm; in privcmd_ioctl_mmap_batch()
463 return -EFAULT; in privcmd_ioctl_mmap_batch()
464 /* Returns per-frame error in m.arr. */ in privcmd_ioctl_mmap_batch()
467 return -EFAULT; in privcmd_ioctl_mmap_batch()
471 return -EFAULT; in privcmd_ioctl_mmap_batch()
472 /* Returns per-frame error code in m.err. */ in privcmd_ioctl_mmap_batch()
474 return -EFAULT; in privcmd_ioctl_mmap_batch()
477 return -EINVAL; in privcmd_ioctl_mmap_batch()
481 if (data->domid != DOMID_INVALID && data->domid != m.dom) in privcmd_ioctl_mmap_batch()
482 return -EPERM; in privcmd_ioctl_mmap_batch()
486 return -EINVAL; in privcmd_ioctl_mmap_batch()
493 ret = -EINVAL; in privcmd_ioctl_mmap_batch()
500 ret = -EFAULT; in privcmd_ioctl_mmap_batch()
509 vma->vm_ops != &privcmd_vm_ops) { in privcmd_ioctl_mmap_batch()
510 ret = -EINVAL; in privcmd_ioctl_mmap_batch()
525 if (vma->vm_private_data == NULL) { in privcmd_ioctl_mmap_batch()
526 if (m.addr != vma->vm_start || in privcmd_ioctl_mmap_batch()
527 m.addr + (nr_pages << PAGE_SHIFT) != vma->vm_end) { in privcmd_ioctl_mmap_batch()
528 ret = -EINVAL; in privcmd_ioctl_mmap_batch()
536 vma->vm_private_data = PRIV_VMA_LOCKED; in privcmd_ioctl_mmap_batch()
538 if (m.addr < vma->vm_start || in privcmd_ioctl_mmap_batch()
539 m.addr + (nr_pages << PAGE_SHIFT) > vma->vm_end) { in privcmd_ioctl_mmap_batch()
540 ret = -EINVAL; in privcmd_ioctl_mmap_batch()
544 ret = -EINVAL; in privcmd_ioctl_mmap_batch()
572 /* If we have not had any EFAULT-like global errors then set the global in privcmd_ioctl_mmap_batch()
573 * error to -ENOENT if necessary. */ in privcmd_ioctl_mmap_batch()
574 if ((ret == 0) && (state.global_error == -ENOENT)) in privcmd_ioctl_mmap_batch()
575 ret = -ENOENT; in privcmd_ioctl_mmap_batch()
598 PAGE_SIZE) - off; in lock_pages()
600 return -ENOSPC; in lock_pages()
606 return page_count ? : -EFAULT; in lock_pages()
609 nr_pages -= page_count; in lock_pages()
626 struct privcmd_data *data = file->private_data; in privcmd_ioctl_dm_op()
637 return -EFAULT; in privcmd_ioctl_dm_op()
640 if (data->domid != DOMID_INVALID && data->domid != kdata.dom) in privcmd_ioctl_dm_op()
641 return -EPERM; in privcmd_ioctl_dm_op()
647 return -E2BIG; in privcmd_ioctl_dm_op()
651 return -ENOMEM; in privcmd_ioctl_dm_op()
655 rc = -EFAULT; in privcmd_ioctl_dm_op()
661 rc = -E2BIG; in privcmd_ioctl_dm_op()
667 rc = -EFAULT; in privcmd_ioctl_dm_op()
678 rc = -ENOMEM; in privcmd_ioctl_dm_op()
684 rc = -ENOMEM; in privcmd_ioctl_dm_op()
712 struct privcmd_data *data = file->private_data; in privcmd_ioctl_restrict()
716 return -EFAULT; in privcmd_ioctl_restrict()
719 if (data->domid == DOMID_INVALID) in privcmd_ioctl_restrict()
720 data->domid = dom; in privcmd_ioctl_restrict()
721 else if (data->domid != dom) in privcmd_ioctl_restrict()
722 return -EINVAL; in privcmd_ioctl_restrict()
730 struct privcmd_data *data = file->private_data; in privcmd_ioctl_mmap_resource()
731 struct mm_struct *mm = current->mm; in privcmd_ioctl_mmap_resource()
739 return -EFAULT; in privcmd_ioctl_mmap_resource()
742 if (data->domid != DOMID_INVALID && data->domid != kdata.dom) in privcmd_ioctl_mmap_resource()
743 return -EPERM; in privcmd_ioctl_mmap_resource()
747 return -EINVAL; in privcmd_ioctl_mmap_resource()
758 return __put_user(xdata.nr_frames, &udata->num); in privcmd_ioctl_mmap_resource()
764 if (!vma || vma->vm_ops != &privcmd_vm_ops) { in privcmd_ioctl_mmap_resource()
765 rc = -EINVAL; in privcmd_ioctl_mmap_resource()
771 rc = -ENOMEM; in privcmd_ioctl_mmap_resource()
785 pages = vma->vm_private_data; in privcmd_ioctl_mmap_resource()
793 vma->vm_private_data = PRIV_VMA_LOCKED; in privcmd_ioctl_mmap_resource()
819 vma->vm_page_prot, in privcmd_ioctl_mmap_resource()
854 struct work_struct shutdown; member
864 list_del_init(&kirqfd->list); in irqfd_deactivate()
865 queue_work(irqfd_cleanup_wq, &kirqfd->shutdown); in irqfd_deactivate()
871 container_of(work, struct privcmd_kernel_irqfd, shutdown); in irqfd_shutdown()
877 eventfd_ctx_remove_wait_queue(kirqfd->eventfd, &kirqfd->wait, &cnt); in irqfd_shutdown()
878 eventfd_ctx_put(kirqfd->eventfd); in irqfd_shutdown()
887 eventfd_ctx_do_read(kirqfd->eventfd, &cnt); in irqfd_inject()
890 rc = HYPERVISOR_dm_op(kirqfd->dom, 1, &kirqfd->xbufs); in irqfd_inject()
894 if (rc && !kirqfd->error) { in irqfd_inject()
896 kirqfd->dom); in irqfd_inject()
899 kirqfd->error = rc; in irqfd_inject()
929 add_wait_queue_priority(wqh, &kirqfd->wait); in irqfd_poll_func()
941 kirqfd = kzalloc(sizeof(*kirqfd) + irqfd->size, GFP_KERNEL); in privcmd_irqfd_assign()
943 return -ENOMEM; in privcmd_irqfd_assign()
946 if (copy_from_user(dm_op, u64_to_user_ptr(irqfd->dm_op), irqfd->size)) { in privcmd_irqfd_assign()
947 ret = -EFAULT; in privcmd_irqfd_assign()
951 kirqfd->xbufs.size = irqfd->size; in privcmd_irqfd_assign()
952 set_xen_guest_handle(kirqfd->xbufs.h, dm_op); in privcmd_irqfd_assign()
953 kirqfd->dom = irqfd->dom; in privcmd_irqfd_assign()
954 INIT_WORK(&kirqfd->shutdown, irqfd_shutdown); in privcmd_irqfd_assign()
956 f = fdget(irqfd->fd); in privcmd_irqfd_assign()
958 ret = -EBADF; in privcmd_irqfd_assign()
962 kirqfd->eventfd = eventfd_ctx_fileget(f.file); in privcmd_irqfd_assign()
963 if (IS_ERR(kirqfd->eventfd)) { in privcmd_irqfd_assign()
964 ret = PTR_ERR(kirqfd->eventfd); in privcmd_irqfd_assign()
969 * Install our own custom wake-up handling so we are notified via a in privcmd_irqfd_assign()
972 init_waitqueue_func_entry(&kirqfd->wait, irqfd_wakeup); in privcmd_irqfd_assign()
973 init_poll_funcptr(&kirqfd->pt, irqfd_poll_func); in privcmd_irqfd_assign()
978 if (kirqfd->eventfd == tmp->eventfd) { in privcmd_irqfd_assign()
979 ret = -EBUSY; in privcmd_irqfd_assign()
986 list_add_tail(&kirqfd->list, &irqfds_list); in privcmd_irqfd_assign()
993 events = vfs_poll(f.file, &kirqfd->pt); in privcmd_irqfd_assign()
1007 eventfd_ctx_put(kirqfd->eventfd); in privcmd_irqfd_assign()
1023 eventfd = eventfd_ctx_fdget(irqfd->fd); in privcmd_irqfd_deassign()
1030 if (kirqfd->eventfd == eventfd) { in privcmd_irqfd_deassign()
1041 * Block until we know all outstanding shutdown jobs have completed so in privcmd_irqfd_deassign()
1052 struct privcmd_data *data = file->private_data; in privcmd_ioctl_irqfd()
1056 return -EFAULT; in privcmd_ioctl_irqfd()
1060 return -EINVAL; in privcmd_ioctl_irqfd()
1063 if (data->domid != DOMID_INVALID && data->domid != irqfd.dom) in privcmd_ioctl_irqfd()
1064 return -EPERM; in privcmd_ioctl_irqfd()
1074 irqfd_cleanup_wq = alloc_workqueue("privcmd-irqfd-cleanup", 0, 0); in privcmd_irqfd_init()
1076 return -ENOMEM; in privcmd_irqfd_init()
1098 return -EOPNOTSUPP; in privcmd_ioctl_irqfd()
1114 int ret = -ENOTTY; in privcmd_ioctl()
1162 return -ENOMEM; in privcmd_open()
1165 data->domid = DOMID_INVALID; in privcmd_open()
1167 file->private_data = data; in privcmd_open()
1173 struct privcmd_data *data = file->private_data; in privcmd_release()
1181 struct page **pages = vma->vm_private_data; in privcmd_close()
1183 int numgfns = (vma->vm_end - vma->vm_start) >> XEN_PAGE_SHIFT; in privcmd_close()
1200 printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n", in privcmd_fault()
1201 vmf->vma, vmf->vma->vm_start, vmf->vma->vm_end, in privcmd_fault()
1202 vmf->pgoff, (void *)vmf->address); in privcmd_fault()
1218 vma->vm_ops = &privcmd_vm_ops; in privcmd_mmap()
1219 vma->vm_private_data = NULL; in privcmd_mmap()
1231 return pte_none(ptep_get(pte)) ? 0 : -EBUSY; in is_mapped_fn()
1239 return apply_to_page_range(vma->vm_mm, addr, nr_pages << PAGE_SHIFT, in privcmd_vma_range_is_mapped()
1263 return -ENODEV; in privcmd_init()
1273 pr_err("Could not register Xen hypercall-buf device\n"); in privcmd_init()