11c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge/******************************************************************************
21c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge * privcmd.c
31c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge *
41c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge * Interface to privileged domain-0 commands.
51c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge *
61c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge * Copyright (c) 2002-2004, K A Fraser, B Dragovic
71c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge */
81c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
91c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <linux/kernel.h>
10d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank#include <linux/module.h>
111c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <linux/sched.h>
121c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <linux/slab.h>
131c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <linux/string.h>
141c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <linux/errno.h>
151c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <linux/mm.h>
161c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <linux/mman.h>
171c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <linux/uaccess.h>
181c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <linux/swap.h>
191c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <linux/highmem.h>
201c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <linux/pagemap.h>
211c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <linux/seq_file.h>
22d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank#include <linux/miscdevice.h>
231c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
241c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <asm/pgalloc.h>
251c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <asm/pgtable.h>
261c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <asm/tlb.h>
271c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <asm/xen/hypervisor.h>
281c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <asm/xen/hypercall.h>
291c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
301c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <xen/xen.h>
311c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <xen/privcmd.h>
321c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <xen/interface/xen.h>
331c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <xen/features.h>
341c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#include <xen/page.h>
35de1ef2065c4675ab1062ebc8d1cb6c5f42b61d04Ian Campbell#include <xen/xen-ops.h>
36f020e2905166e12f9a8f109fe968cb5a9db887e9Ian Campbell
37d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank#include "privcmd.h"
38d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank
39d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian BlankMODULE_LICENSE("GPL");
40d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank
411c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#ifndef HAVE_ARCH_PRIVCMD_MMAP
421c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
431c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge#endif
441c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
451c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic long privcmd_ioctl_hypercall(void __user *udata)
461c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge{
471c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct privcmd_hypercall hypercall;
481c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	long ret;
491c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
501c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
511c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		return -EFAULT;
521c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
531c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	ret = privcmd_call(hypercall.op,
541c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			   hypercall.arg[0], hypercall.arg[1],
551c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			   hypercall.arg[2], hypercall.arg[3],
561c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			   hypercall.arg[4]);
571c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
581c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	return ret;
591c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge}
601c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
611c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic void free_page_list(struct list_head *pages)
621c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge{
631c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct page *p, *n;
641c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
651c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	list_for_each_entry_safe(p, n, pages, lru)
661c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		__free_page(p);
671c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
681c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	INIT_LIST_HEAD(pages);
691c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge}
701c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
711c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge/*
721c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge * Given an array of items in userspace, return a list of pages
731c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge * containing the data.  If copying fails, either because of memory
741c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge * allocation failure or a problem reading user memory, return an
751c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge * error code; its up to the caller to dispose of any partial list.
761c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge */
771c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic int gather_array(struct list_head *pagelist,
781c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			unsigned nelem, size_t size,
791c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			void __user *data)
801c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge{
811c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	unsigned pageidx;
821c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	void *pagedata;
831c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	int ret;
841c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
851c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if (size > PAGE_SIZE)
861c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		return 0;
871c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
881c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	pageidx = PAGE_SIZE;
891c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	pagedata = NULL;	/* quiet, gcc */
901c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	while (nelem--) {
911c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		if (pageidx > PAGE_SIZE-size) {
921c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			struct page *page = alloc_page(GFP_KERNEL);
931c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
941c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			ret = -ENOMEM;
951c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			if (page == NULL)
961c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge				goto fail;
971c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
981c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			pagedata = page_address(page);
991c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1001c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			list_add_tail(&page->lru, pagelist);
1011c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			pageidx = 0;
1021c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		}
1031c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1041c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		ret = -EFAULT;
1051c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		if (copy_from_user(pagedata + pageidx, data, size))
1061c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			goto fail;
1071c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1081c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		data += size;
1091c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		pageidx += size;
1101c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	}
1111c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1121c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	ret = 0;
1131c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1141c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingefail:
1151c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	return ret;
1161c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge}
1171c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1181c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge/*
1191c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge * Call function "fn" on each element of the array fragmented
1201c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge * over a list of pages.
1211c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge */
1221c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic int traverse_pages(unsigned nelem, size_t size,
1231c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			  struct list_head *pos,
1241c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			  int (*fn)(void *data, void *state),
1251c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			  void *state)
1261c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge{
1271c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	void *pagedata;
1281c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	unsigned pageidx;
129f020e2905166e12f9a8f109fe968cb5a9db887e9Ian Campbell	int ret = 0;
1301c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1311c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	BUG_ON(size > PAGE_SIZE);
1321c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1331c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	pageidx = PAGE_SIZE;
1341c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	pagedata = NULL;	/* hush, gcc */
1351c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1361c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	while (nelem--) {
1371c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		if (pageidx > PAGE_SIZE-size) {
1381c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			struct page *page;
1391c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			pos = pos->next;
1401c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			page = list_entry(pos, struct page, lru);
1411c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			pagedata = page_address(page);
1421c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			pageidx = 0;
1431c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		}
1441c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1451c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		ret = (*fn)(pagedata + pageidx, state);
1461c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		if (ret)
1471c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			break;
1481c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		pageidx += size;
1491c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	}
1501c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1511c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	return ret;
1521c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge}
1531c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1541c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestruct mmap_mfn_state {
1551c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	unsigned long va;
1561c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct vm_area_struct *vma;
1571c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	domid_t domain;
1581c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge};
1591c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1601c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic int mmap_mfn_range(void *data, void *state)
1611c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge{
1621c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct privcmd_mmap_entry *msg = data;
1631c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct mmap_mfn_state *st = state;
1641c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct vm_area_struct *vma = st->vma;
1651c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	int rc;
1661c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1671c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	/* Do not allow range to wrap the address space. */
1681c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if ((msg->npages > (LONG_MAX >> PAGE_SHIFT)) ||
1691c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	    ((unsigned long)(msg->npages << PAGE_SHIFT) >= -st->va))
1701c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		return -EINVAL;
1711c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1721c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	/* Range chunks must be contiguous in va space. */
1731c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if ((msg->va != st->va) ||
1741c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	    ((msg->va+(msg->npages<<PAGE_SHIFT)) > vma->vm_end))
1751c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		return -EINVAL;
1761c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
177de1ef2065c4675ab1062ebc8d1cb6c5f42b61d04Ian Campbell	rc = xen_remap_domain_mfn_range(vma,
178de1ef2065c4675ab1062ebc8d1cb6c5f42b61d04Ian Campbell					msg->va & PAGE_MASK,
179de1ef2065c4675ab1062ebc8d1cb6c5f42b61d04Ian Campbell					msg->mfn, msg->npages,
180de1ef2065c4675ab1062ebc8d1cb6c5f42b61d04Ian Campbell					vma->vm_page_prot,
181de1ef2065c4675ab1062ebc8d1cb6c5f42b61d04Ian Campbell					st->domain);
1821c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if (rc < 0)
1831c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		return rc;
1841c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1851c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	st->va += msg->npages << PAGE_SHIFT;
1861c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1871c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	return 0;
1881c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge}
1891c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1901c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic long privcmd_ioctl_mmap(void __user *udata)
1911c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge{
1921c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct privcmd_mmap mmapcmd;
1931c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct mm_struct *mm = current->mm;
1941c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct vm_area_struct *vma;
1951c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	int rc;
1961c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	LIST_HEAD(pagelist);
1971c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct mmap_mfn_state state;
1981c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
1991c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if (!xen_initial_domain())
2001c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		return -EPERM;
2011c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2021c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
2031c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		return -EFAULT;
2041c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2051c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	rc = gather_array(&pagelist,
2061c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			  mmapcmd.num, sizeof(struct privcmd_mmap_entry),
2071c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			  mmapcmd.entry);
2081c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2091c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if (rc || list_empty(&pagelist))
2101c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		goto out;
2111c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2121c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	down_write(&mm->mmap_sem);
2131c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2141c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	{
2151c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		struct page *page = list_first_entry(&pagelist,
2161c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge						     struct page, lru);
2171c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		struct privcmd_mmap_entry *msg = page_address(page);
2181c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2191c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		vma = find_vma(mm, msg->va);
2201c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		rc = -EINVAL;
2211c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2221c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		if (!vma || (msg->va != vma->vm_start) ||
2231c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		    !privcmd_enforce_singleshot_mapping(vma))
2241c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			goto out_up;
2251c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	}
2261c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2271c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	state.va = vma->vm_start;
2281c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	state.vma = vma;
2291c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	state.domain = mmapcmd.dom;
2301c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2311c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	rc = traverse_pages(mmapcmd.num, sizeof(struct privcmd_mmap_entry),
2321c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			    &pagelist,
2331c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			    mmap_mfn_range, &state);
2341c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2351c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2361c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingeout_up:
2371c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	up_write(&mm->mmap_sem);
2381c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2391c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingeout:
2401c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	free_page_list(&pagelist);
2411c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2421c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	return rc;
2431c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge}
2441c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2451c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestruct mmap_batch_state {
2461c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	domid_t domain;
2471c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	unsigned long va;
2481c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct vm_area_struct *vma;
2491c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	int err;
2501c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2511c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	xen_pfn_t __user *user;
2521c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge};
2531c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2541c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic int mmap_batch_fn(void *data, void *state)
2551c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge{
2561c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	xen_pfn_t *mfnp = data;
2571c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct mmap_batch_state *st = state;
2581c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
259de1ef2065c4675ab1062ebc8d1cb6c5f42b61d04Ian Campbell	if (xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp, 1,
260de1ef2065c4675ab1062ebc8d1cb6c5f42b61d04Ian Campbell				       st->vma->vm_page_prot, st->domain) < 0) {
2611c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		*mfnp |= 0xf0000000U;
2621c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		st->err++;
2631c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	}
2641c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	st->va += PAGE_SIZE;
2651c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2661c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	return 0;
2671c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge}
2681c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2691c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic int mmap_return_errors(void *data, void *state)
2701c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge{
2711c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	xen_pfn_t *mfnp = data;
2721c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct mmap_batch_state *st = state;
2731c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
274313e74412105c670ff8900ec8099a3a5df1fa83cVasiliy Kulikov	return put_user(*mfnp, st->user++);
2751c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge}
2761c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
277f31fdf510531333dea95f0a92e6eaa1c3a7541e2Jeremy Fitzhardingestatic struct vm_operations_struct privcmd_vm_ops;
278f31fdf510531333dea95f0a92e6eaa1c3a7541e2Jeremy Fitzhardinge
2791c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic long privcmd_ioctl_mmap_batch(void __user *udata)
2801c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge{
2811c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	int ret;
2821c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct privcmd_mmapbatch m;
2831c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct mm_struct *mm = current->mm;
2841c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct vm_area_struct *vma;
2851c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	unsigned long nr_pages;
2861c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	LIST_HEAD(pagelist);
2871c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	struct mmap_batch_state state;
2881c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2891c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if (!xen_initial_domain())
2901c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		return -EPERM;
2911c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2921c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if (copy_from_user(&m, udata, sizeof(m)))
2931c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		return -EFAULT;
2941c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2951c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	nr_pages = m.num;
2961c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
2971c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		return -EINVAL;
2981c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
2991c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	ret = gather_array(&pagelist, m.num, sizeof(xen_pfn_t),
3001c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			   m.arr);
3011c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3021c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if (ret || list_empty(&pagelist))
3031c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		goto out;
3041c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3051c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	down_write(&mm->mmap_sem);
3061c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3071c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	vma = find_vma(mm, m.addr);
3081c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	ret = -EINVAL;
3091c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if (!vma ||
310f31fdf510531333dea95f0a92e6eaa1c3a7541e2Jeremy Fitzhardinge	    vma->vm_ops != &privcmd_vm_ops ||
3111c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	    (m.addr != vma->vm_start) ||
3121c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	    ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) ||
3131c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	    !privcmd_enforce_singleshot_mapping(vma)) {
3141c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		up_write(&mm->mmap_sem);
3151c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		goto out;
3161c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	}
3171c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3181c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	state.domain = m.dom;
3191c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	state.vma = vma;
3201c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	state.va = m.addr;
3211c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	state.err = 0;
3221c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3231c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	ret = traverse_pages(m.num, sizeof(xen_pfn_t),
3241c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			     &pagelist, mmap_batch_fn, &state);
3251c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3261c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	up_write(&mm->mmap_sem);
3271c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3281c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if (state.err > 0) {
329f020e2905166e12f9a8f109fe968cb5a9db887e9Ian Campbell		state.user = m.arr;
330313e74412105c670ff8900ec8099a3a5df1fa83cVasiliy Kulikov		ret = traverse_pages(m.num, sizeof(xen_pfn_t),
3311c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			       &pagelist,
3321c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			       mmap_return_errors, &state);
3331c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	}
3341c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3351c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingeout:
3361c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	free_page_list(&pagelist);
3371c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3381c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	return ret;
3391c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge}
3401c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3411c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic long privcmd_ioctl(struct file *file,
3421c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge			  unsigned int cmd, unsigned long data)
3431c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge{
3441c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	int ret = -ENOSYS;
3451c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	void __user *udata = (void __user *) data;
3461c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3471c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	switch (cmd) {
3481c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	case IOCTL_PRIVCMD_HYPERCALL:
3491c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		ret = privcmd_ioctl_hypercall(udata);
3501c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		break;
3511c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3521c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	case IOCTL_PRIVCMD_MMAP:
3531c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		ret = privcmd_ioctl_mmap(udata);
3541c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		break;
3551c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3561c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	case IOCTL_PRIVCMD_MMAPBATCH:
3571c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		ret = privcmd_ioctl_mmap_batch(udata);
3581c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		break;
3591c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3601c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	default:
3611c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		ret = -EINVAL;
3621c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		break;
3631c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	}
3641c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3651c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	return ret;
3661c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge}
3671c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3681c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
3691c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge{
370441c7416b55d3d48b4aaafc5bdd804092387d877Jeremy Fitzhardinge	printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n",
371441c7416b55d3d48b4aaafc5bdd804092387d877Jeremy Fitzhardinge	       vma, vma->vm_start, vma->vm_end,
372441c7416b55d3d48b4aaafc5bdd804092387d877Jeremy Fitzhardinge	       vmf->pgoff, vmf->virtual_address);
373441c7416b55d3d48b4aaafc5bdd804092387d877Jeremy Fitzhardinge
3741c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	return VM_FAULT_SIGBUS;
3751c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge}
3761c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3771c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic struct vm_operations_struct privcmd_vm_ops = {
3781c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	.fault = privcmd_fault
3791c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge};
3801c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3811c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic int privcmd_mmap(struct file *file, struct vm_area_struct *vma)
3821c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge{
3831c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	/* Unsupported for auto-translate guests. */
3841c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	if (xen_feature(XENFEAT_auto_translated_physmap))
3851c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge		return -ENOSYS;
3861c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
387e060e7af98182494b764d002eba7fa022fe91bdfStefano Stabellini	/* DONTCOPY is essential for Xen because copy_page_range doesn't know
388e060e7af98182494b764d002eba7fa022fe91bdfStefano Stabellini	 * how to recreate these mappings */
389e060e7af98182494b764d002eba7fa022fe91bdfStefano Stabellini	vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP;
3901c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	vma->vm_ops = &privcmd_vm_ops;
3911c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	vma->vm_private_data = NULL;
3921c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3931c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	return 0;
3941c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge}
3951c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
3961c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardingestatic int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
3971c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge{
3981c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	return (xchg(&vma->vm_private_data, (void *)1) == NULL);
3991c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge}
4001c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge
401d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blankconst struct file_operations xen_privcmd_fops = {
402d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank	.owner = THIS_MODULE,
4031c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	.unlocked_ioctl = privcmd_ioctl,
4041c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge	.mmap = privcmd_mmap,
4051c5de1939c204bde9cce87f4eb3d26e9f9eb732bJeremy Fitzhardinge};
406d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian BlankEXPORT_SYMBOL_GPL(xen_privcmd_fops);
407d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank
408d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blankstatic struct miscdevice privcmd_dev = {
409d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank	.minor = MISC_DYNAMIC_MINOR,
410d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank	.name = "xen/privcmd",
411d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank	.fops = &xen_privcmd_fops,
412d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank};
413d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank
414d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blankstatic int __init privcmd_init(void)
415d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank{
416d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank	int err;
417d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank
418d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank	if (!xen_domain())
419d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank		return -ENODEV;
420d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank
421d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank	err = misc_register(&privcmd_dev);
422d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank	if (err != 0) {
423d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank		printk(KERN_ERR "Could not register Xen privcmd device\n");
424d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank		return err;
425d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank	}
426d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank	return 0;
427d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank}
428d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank
429d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blankstatic void __exit privcmd_exit(void)
430d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank{
431d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank	misc_deregister(&privcmd_dev);
432d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank}
433d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blank
434d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blankmodule_init(privcmd_init);
435d8414d3c157dc1f83e73c17447ba41fe5afa9d3dBastian Blankmodule_exit(privcmd_exit);
436