ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c @ 14100:e47738923a05

[LINUX] Purge include <linux/config.h>. It has been obsolete for some time now.

Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
author Ian Campbell <ian.campbell@xensource.com>
date Fri Feb 23 16:56:45 2007 +0000 (2007-02-23)
parents b1d436f094fa
children 2caed72258e8
line source
1 /******************************************************************************
2 * privcmd.c
3 *
4 * Interface to privileged domain-0 commands.
5 *
6 * Copyright (c) 2002-2004, K A Fraser, B Dragovic
7 */
9 #include <linux/kernel.h>
10 #include <linux/sched.h>
11 #include <linux/slab.h>
12 #include <linux/string.h>
13 #include <linux/errno.h>
14 #include <linux/mm.h>
15 #include <linux/mman.h>
16 #include <linux/swap.h>
17 #include <linux/smp_lock.h>
18 #include <linux/highmem.h>
19 #include <linux/pagemap.h>
20 #include <linux/seq_file.h>
21 #include <linux/kthread.h>
22 #include <asm/hypervisor.h>
24 #include <asm/pgalloc.h>
25 #include <asm/pgtable.h>
26 #include <asm/uaccess.h>
27 #include <asm/tlb.h>
28 #include <asm/hypervisor.h>
29 #include <xen/public/privcmd.h>
30 #include <xen/interface/xen.h>
31 #include <xen/interface/dom0_ops.h>
32 #include <xen/xen_proc.h>
34 static struct proc_dir_entry *privcmd_intf;
35 static struct proc_dir_entry *capabilities_intf;
37 #ifndef HAVE_ARCH_PRIVCMD_MMAP
38 static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
39 #endif
41 static int privcmd_ioctl(struct inode *inode, struct file *file,
42 unsigned int cmd, unsigned long data)
43 {
44 int ret = -ENOSYS;
45 void __user *udata = (void __user *) data;
47 switch (cmd) {
48 case IOCTL_PRIVCMD_HYPERCALL: {
49 privcmd_hypercall_t hypercall;
51 if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
52 return -EFAULT;
54 #if defined(__i386__)
55 if (hypercall.op >= (PAGE_SIZE >> 5))
56 break;
57 __asm__ __volatile__ (
58 "pushl %%ebx; pushl %%ecx; pushl %%edx; "
59 "pushl %%esi; pushl %%edi; "
60 "movl 8(%%eax),%%ebx ;"
61 "movl 16(%%eax),%%ecx ;"
62 "movl 24(%%eax),%%edx ;"
63 "movl 32(%%eax),%%esi ;"
64 "movl 40(%%eax),%%edi ;"
65 "movl (%%eax),%%eax ;"
66 "shll $5,%%eax ;"
67 "addl $hypercall_page,%%eax ;"
68 "call *%%eax ;"
69 "popl %%edi; popl %%esi; popl %%edx; "
70 "popl %%ecx; popl %%ebx"
71 : "=a" (ret) : "0" (&hypercall) : "memory" );
72 #elif defined (__x86_64__)
73 if (hypercall.op < (PAGE_SIZE >> 5)) {
74 long ign1, ign2, ign3;
75 __asm__ __volatile__ (
76 "movq %8,%%r10; movq %9,%%r8;"
77 "shll $5,%%eax ;"
78 "addq $hypercall_page,%%rax ;"
79 "call *%%rax"
80 : "=a" (ret), "=D" (ign1),
81 "=S" (ign2), "=d" (ign3)
82 : "0" ((unsigned int)hypercall.op),
83 "1" (hypercall.arg[0]),
84 "2" (hypercall.arg[1]),
85 "3" (hypercall.arg[2]),
86 "g" (hypercall.arg[3]),
87 "g" (hypercall.arg[4])
88 : "r8", "r10", "memory" );
89 }
90 #elif defined (__ia64__)
91 ret = privcmd_hypercall(&hypercall);
92 #endif
93 }
94 break;
96 case IOCTL_PRIVCMD_MMAP: {
97 privcmd_mmap_t mmapcmd;
98 privcmd_mmap_entry_t msg;
99 privcmd_mmap_entry_t __user *p;
100 struct mm_struct *mm = current->mm;
101 struct vm_area_struct *vma;
102 unsigned long va;
103 int i, rc;
105 if (!is_initial_xendomain())
106 return -EPERM;
108 if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
109 return -EFAULT;
111 p = mmapcmd.entry;
112 if (copy_from_user(&msg, p, sizeof(msg)))
113 return -EFAULT;
115 down_read(&mm->mmap_sem);
117 vma = find_vma(mm, msg.va);
118 rc = -EINVAL;
119 if (!vma || (msg.va != vma->vm_start) ||
120 !privcmd_enforce_singleshot_mapping(vma))
121 goto mmap_out;
123 va = vma->vm_start;
125 for (i = 0; i < mmapcmd.num; i++) {
126 rc = -EFAULT;
127 if (copy_from_user(&msg, p, sizeof(msg)))
128 goto mmap_out;
130 /* Do not allow range to wrap the address space. */
131 rc = -EINVAL;
132 if ((msg.npages > (LONG_MAX >> PAGE_SHIFT)) ||
133 ((unsigned long)(msg.npages << PAGE_SHIFT) >= -va))
134 goto mmap_out;
136 /* Range chunks must be contiguous in va space. */
137 if ((msg.va != va) ||
138 ((msg.va+(msg.npages<<PAGE_SHIFT)) > vma->vm_end))
139 goto mmap_out;
141 if ((rc = direct_remap_pfn_range(
142 vma,
143 msg.va & PAGE_MASK,
144 msg.mfn,
145 msg.npages << PAGE_SHIFT,
146 vma->vm_page_prot,
147 mmapcmd.dom)) < 0)
148 goto mmap_out;
150 p++;
151 va += msg.npages << PAGE_SHIFT;
152 }
154 rc = 0;
156 mmap_out:
157 up_read(&mm->mmap_sem);
158 ret = rc;
159 }
160 break;
162 case IOCTL_PRIVCMD_MMAPBATCH: {
163 privcmd_mmapbatch_t m;
164 struct mm_struct *mm = current->mm;
165 struct vm_area_struct *vma;
166 xen_pfn_t __user *p;
167 unsigned long addr, mfn, nr_pages;
168 int i;
170 if (!is_initial_xendomain())
171 return -EPERM;
173 if (copy_from_user(&m, udata, sizeof(m)))
174 return -EFAULT;
176 nr_pages = m.num;
177 if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
178 return -EINVAL;
180 down_read(&mm->mmap_sem);
182 vma = find_vma(mm, m.addr);
183 if (!vma ||
184 (m.addr != vma->vm_start) ||
185 ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) ||
186 !privcmd_enforce_singleshot_mapping(vma)) {
187 up_read(&mm->mmap_sem);
188 return -EINVAL;
189 }
191 p = m.arr;
192 addr = m.addr;
193 for (i = 0; i < nr_pages; i++, addr += PAGE_SIZE, p++) {
194 if (get_user(mfn, p)) {
195 up_read(&mm->mmap_sem);
196 return -EFAULT;
197 }
199 ret = direct_remap_pfn_range(vma, addr & PAGE_MASK,
200 mfn, PAGE_SIZE,
201 vma->vm_page_prot, m.dom);
202 if (ret < 0)
203 put_user(0xF0000000 | mfn, p);
204 }
206 up_read(&mm->mmap_sem);
207 ret = 0;
208 }
209 break;
211 default:
212 ret = -EINVAL;
213 break;
214 }
216 return ret;
217 }
219 #ifndef HAVE_ARCH_PRIVCMD_MMAP
220 static struct page *privcmd_nopage(struct vm_area_struct *vma,
221 unsigned long address,
222 int *type)
223 {
224 return NOPAGE_SIGBUS;
225 }
227 static struct vm_operations_struct privcmd_vm_ops = {
228 .nopage = privcmd_nopage
229 };
231 static int privcmd_mmap(struct file * file, struct vm_area_struct * vma)
232 {
233 /* Unsupported for auto-translate guests. */
234 if (xen_feature(XENFEAT_auto_translated_physmap))
235 return -ENOSYS;
237 /* DONTCOPY is essential for Xen as copy_page_range is broken. */
238 vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
239 vma->vm_ops = &privcmd_vm_ops;
240 vma->vm_private_data = NULL;
242 return 0;
243 }
245 static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
246 {
247 return (xchg(&vma->vm_private_data, (void *)1) == NULL);
248 }
249 #endif
251 static struct file_operations privcmd_file_ops = {
252 .ioctl = privcmd_ioctl,
253 .mmap = privcmd_mmap,
254 };
256 static int capabilities_read(char *page, char **start, off_t off,
257 int count, int *eof, void *data)
258 {
259 int len = 0;
260 *page = 0;
262 if (is_initial_xendomain())
263 len = sprintf( page, "control_d\n" );
265 *eof = 1;
266 return len;
267 }
269 static int __init privcmd_init(void)
270 {
271 if (!is_running_on_xen())
272 return -ENODEV;
274 privcmd_intf = create_xen_proc_entry("privcmd", 0400);
275 if (privcmd_intf != NULL)
276 privcmd_intf->proc_fops = &privcmd_file_ops;
278 capabilities_intf = create_xen_proc_entry("capabilities", 0400 );
279 if (capabilities_intf != NULL)
280 capabilities_intf->read_proc = capabilities_read;
282 return 0;
283 }
285 __initcall(privcmd_init);