1 /******************************************************************************
4 * Interface to privileged domain-0 commands.
6 * Copyright (c) 2002-2004, K A Fraser, B Dragovic
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>
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 <asm/hypervisor.h>
23 #include <asm/pgalloc.h>
24 #include <asm/pgtable.h>
25 #include <asm/uaccess.h>
27 #include <asm/hypervisor.h>
28 #include <xen/public/privcmd.h>
29 #include <xen/interface/xen.h>
30 #include <xen/xen_proc.h>
31 #include <xen/features.h>
33 static struct proc_dir_entry *privcmd_intf;
34 static struct proc_dir_entry *capabilities_intf;
36 #ifndef CONFIG_XEN_PRIVILEGED_GUEST
37 #define HAVE_ARCH_PRIVCMD_MMAP
39 #ifndef HAVE_ARCH_PRIVCMD_MMAP
40 static int enforce_singleshot_mapping_fn(pte_t *pte, struct page *pmd_page,
41 unsigned long addr, void *data)
43 return pte_none(*pte) ? 0 : -EBUSY;
46 static inline int enforce_singleshot_mapping(struct vm_area_struct *vma,
50 return apply_to_page_range(vma->vm_mm, addr, npages << PAGE_SHIFT,
51 enforce_singleshot_mapping_fn, NULL) == 0;
54 #define enforce_singleshot_mapping(vma, addr, npages) \
55 privcmd_enforce_singleshot_mapping(vma)
58 static long privcmd_ioctl(struct file *file,
59 unsigned int cmd, unsigned long data)
62 void __user *udata = (void __user *) data;
63 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
64 unsigned long i, addr, nr, nr_pages;
66 struct mm_struct *mm = current->mm;
67 struct vm_area_struct *vma;
69 struct list_head *l, *l2;
73 case IOCTL_PRIVCMD_HYPERCALL: {
74 privcmd_hypercall_t hypercall;
76 if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
81 if (hypercall.op >= (PAGE_SIZE >> 5))
83 ret = _hypercall(long, (unsigned int)hypercall.op,
84 (unsigned long)hypercall.arg[0],
85 (unsigned long)hypercall.arg[1],
86 (unsigned long)hypercall.arg[2],
87 (unsigned long)hypercall.arg[3],
88 (unsigned long)hypercall.arg[4]);
90 ret = privcmd_hypercall(&hypercall);
95 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
97 case IOCTL_PRIVCMD_MMAP: {
98 #define MMAP_NR_PER_PAGE \
99 (unsigned long)((PAGE_SIZE - sizeof(*l)) / sizeof(*msg))
100 privcmd_mmap_t mmapcmd;
101 privcmd_mmap_entry_t *msg;
102 privcmd_mmap_entry_t __user *p;
104 if (!is_initial_xendomain())
107 if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
110 if (mmapcmd.num <= 0)
114 for (i = 0; i < mmapcmd.num;) {
115 nr = min(mmapcmd.num - i, MMAP_NR_PER_PAGE);
118 l = (struct list_head *) __get_free_page(GFP_KERNEL);
123 list_add_tail(l, &pagelist);
124 msg = (privcmd_mmap_entry_t*)(l + 1);
127 if (copy_from_user(msg, p, nr*sizeof(*msg)))
134 msg = (privcmd_mmap_entry_t*)(l + 1);
136 down_write(&mm->mmap_sem);
138 vma = find_vma(mm, msg->va);
140 if (!vma || (msg->va != vma->vm_start))
143 addr = vma->vm_start;
146 list_for_each(l, &pagelist) {
147 nr = i + min(mmapcmd.num - i, MMAP_NR_PER_PAGE);
149 msg = (privcmd_mmap_entry_t*)(l + 1);
152 /* Do not allow range to wrap the address space. */
153 if ((msg->npages > (LONG_MAX >> PAGE_SHIFT)) ||
154 (((unsigned long)msg->npages << PAGE_SHIFT) >= -addr))
157 /* Range chunks must be contiguous in va space. */
158 if ((msg->va != addr) ||
159 ((msg->va+(msg->npages<<PAGE_SHIFT)) > vma->vm_end))
162 addr += msg->npages << PAGE_SHIFT;
168 if (!enforce_singleshot_mapping(vma, vma->vm_start,
169 (addr - vma->vm_start) >> PAGE_SHIFT))
172 addr = vma->vm_start;
174 list_for_each(l, &pagelist) {
175 nr = i + min(mmapcmd.num - i, MMAP_NR_PER_PAGE);
177 msg = (privcmd_mmap_entry_t*)(l + 1);
179 if ((ret = direct_remap_pfn_range(
183 msg->npages << PAGE_SHIFT,
188 addr += msg->npages << PAGE_SHIFT;
197 up_write(&mm->mmap_sem);
198 list_for_each_safe(l,l2,&pagelist)
199 free_page((unsigned long)l);
201 #undef MMAP_NR_PER_PAGE
204 case IOCTL_PRIVCMD_MMAPBATCH: {
205 #define MMAPBATCH_NR_PER_PAGE \
206 (unsigned long)((PAGE_SIZE - sizeof(*l)) / sizeof(*mfn))
207 privcmd_mmapbatch_t m;
211 if (!is_initial_xendomain())
214 if (copy_from_user(&m, udata, sizeof(m)))
219 if (m.num <= 0 || nr_pages > (LONG_MAX >> PAGE_SHIFT) ||
220 addr != m.addr || nr_pages > (-addr >> PAGE_SHIFT))
224 for (i=0; i<nr_pages; ) {
225 nr = min(nr_pages - i, MMAPBATCH_NR_PER_PAGE);
228 l = (struct list_head *)__get_free_page(GFP_KERNEL);
233 list_add_tail(l, &pagelist);
235 mfn = (unsigned long*)(l + 1);
237 if (copy_from_user(mfn, p, nr*sizeof(*mfn)))
243 down_write(&mm->mmap_sem);
245 vma = find_vma(mm, addr);
248 addr < vma->vm_start ||
249 addr + (nr_pages << PAGE_SHIFT) > vma->vm_end ||
250 !enforce_singleshot_mapping(vma, addr, nr_pages)) {
251 up_write(&mm->mmap_sem);
258 list_for_each(l, &pagelist) {
259 nr = i + min(nr_pages - i, MMAPBATCH_NR_PER_PAGE);
260 mfn = (unsigned long *)(l + 1);
265 rc = direct_remap_pfn_range(vma, addr & PAGE_MASK,
267 vma->vm_page_prot, m.dom);
278 mfn++; i++; addr += PAGE_SIZE;
282 up_write(&mm->mmap_sem);
290 list_for_each(l, &pagelist) {
291 nr = min(nr_pages - i, MMAPBATCH_NR_PER_PAGE);
292 mfn = (unsigned long *)(l + 1);
293 if (copy_to_user(p, mfn, nr*sizeof(*mfn)))
299 list_for_each_safe(l,l2,&pagelist)
300 free_page((unsigned long)l);
304 case IOCTL_PRIVCMD_MMAPBATCH_V2: {
305 privcmd_mmapbatch_v2_t m;
306 const xen_pfn_t __user *p;
310 if (!is_initial_xendomain())
313 if (copy_from_user(&m, udata, sizeof(m)))
318 if (m.num <= 0 || nr_pages > (ULONG_MAX >> PAGE_SHIFT) ||
319 addr != m.addr || nr_pages > (-addr >> PAGE_SHIFT))
323 for (i = 0; i < nr_pages; i += nr, p += nr) {
324 nr = min(nr_pages - i, MMAPBATCH_NR_PER_PAGE);
327 l = (struct list_head *)__get_free_page(GFP_KERNEL);
329 goto mmapbatch_v2_out;
332 list_add_tail(l, &pagelist);
334 mfn = (void *)(l + 1);
336 if (copy_from_user(mfn, p, nr * sizeof(*mfn)))
337 goto mmapbatch_v2_out;
340 down_write(&mm->mmap_sem);
342 vma = find_vma(mm, addr);
345 addr < vma->vm_start ||
346 addr + (nr_pages << PAGE_SHIFT) > vma->vm_end ||
347 !enforce_singleshot_mapping(vma, addr, nr_pages)) {
348 up_write(&mm->mmap_sem);
349 goto mmapbatch_v2_out;
355 list_for_each(l, &pagelist) {
356 nr = i + min(nr_pages - i, MMAPBATCH_NR_PER_PAGE);
357 mfn = (void *)(l + 1);
358 err = (void *)(l + 1);
359 BUILD_BUG_ON(sizeof(*err) > sizeof(*mfn));
364 rc = direct_remap_pfn_range(vma, addr & PAGE_MASK,
366 vma->vm_page_prot, m.dom);
374 mfn++; i++; addr += PAGE_SIZE;
378 up_write(&mm->mmap_sem);
381 int __user *p = m.err;
383 ret = paged_out ? -ENOENT : 0;
385 list_for_each(l, &pagelist) {
386 nr = min(nr_pages - i, MMAPBATCH_NR_PER_PAGE);
387 err = (void *)(l + 1);
388 if (copy_to_user(p, err, nr * sizeof(*err)))
392 } else if (clear_user(m.err, nr_pages * sizeof(*m.err)))
396 list_for_each_safe(l, l2, &pagelist)
397 free_page((unsigned long)l);
398 #undef MMAPBATCH_NR_PER_PAGE
402 #endif /* CONFIG_XEN_PRIVILEGED_GUEST */
412 #ifndef HAVE_ARCH_PRIVCMD_MMAP
413 static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
415 return VM_FAULT_SIGBUS;
418 static struct vm_operations_struct privcmd_vm_ops = {
419 .fault = privcmd_fault
422 static int privcmd_mmap(struct file * file, struct vm_area_struct * vma)
424 /* Unsupported for auto-translate guests. */
425 if (xen_feature(XENFEAT_auto_translated_physmap))
428 /* DONTCOPY is essential for Xen as copy_page_range is broken. */
429 vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTCOPY;
430 vma->vm_ops = &privcmd_vm_ops;
431 vma->vm_private_data = NULL;
437 static const struct file_operations privcmd_file_ops = {
438 .unlocked_ioctl = privcmd_ioctl,
439 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
440 .mmap = privcmd_mmap,
444 static int capabilities_read(char *page, char **start, off_t off,
445 int count, int *eof, void *data)
450 if (is_initial_xendomain())
451 len = sprintf( page, "control_d\n" );
457 static int __init privcmd_init(void)
459 if (!is_running_on_xen())
462 privcmd_intf = create_xen_proc_entry("privcmd", 0400);
463 if (privcmd_intf != NULL)
464 privcmd_intf->proc_fops = &privcmd_file_ops;
466 capabilities_intf = create_xen_proc_entry("capabilities", 0400 );
467 if (capabilities_intf != NULL)
468 capabilities_intf->read_proc = capabilities_read;
473 __initcall(privcmd_init);