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