ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c @ 11793:d13809a631b0

Fix privcmd mmap() on 64b architectures for regions larger than 2GB.
Signed-off-by: Xin Li <xin.b.li@intel.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Thu Oct 12 14:25:51 2006 +0100 (2006-10-12)
parents 5b3ec078993b
children b725c9e51a7c
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/config.h>
10 #include <linux/kernel.h>
11 #include <linux/sched.h>
12 #include <linux/slab.h>
13 #include <linux/string.h>
14 #include <linux/errno.h>
15 #include <linux/mm.h>
16 #include <linux/mman.h>
17 #include <linux/swap.h>
18 #include <linux/smp_lock.h>
19 #include <linux/highmem.h>
20 #include <linux/pagemap.h>
21 #include <linux/seq_file.h>
22 #include <linux/kthread.h>
23 #include <asm/hypervisor.h>
25 #include <asm/pgalloc.h>
26 #include <asm/pgtable.h>
27 #include <asm/uaccess.h>
28 #include <asm/tlb.h>
29 #include <asm/hypervisor.h>
30 #include <xen/public/privcmd.h>
31 #include <xen/interface/xen.h>
32 #include <xen/interface/dom0_ops.h>
33 #include <xen/xen_proc.h>
35 static struct proc_dir_entry *privcmd_intf;
36 static struct proc_dir_entry *capabilities_intf;
38 #ifndef HAVE_ARCH_PRIVCMD_MMAP
39 static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
40 #endif
42 static int privcmd_ioctl(struct inode *inode, struct file *file,
43 unsigned int cmd, unsigned long data)
44 {
45 int ret = -ENOSYS;
46 void __user *udata = (void __user *) data;
48 switch (cmd) {
49 case IOCTL_PRIVCMD_HYPERCALL: {
50 privcmd_hypercall_t hypercall;
52 if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
53 return -EFAULT;
55 #if defined(__i386__)
56 __asm__ __volatile__ (
57 "pushl %%ebx; pushl %%ecx; pushl %%edx; "
58 "pushl %%esi; pushl %%edi; "
59 "movl 8(%%eax),%%ebx ;"
60 "movl 16(%%eax),%%ecx ;"
61 "movl 24(%%eax),%%edx ;"
62 "movl 32(%%eax),%%esi ;"
63 "movl 40(%%eax),%%edi ;"
64 "movl (%%eax),%%eax ;"
65 "shll $5,%%eax ;"
66 "addl $hypercall_page,%%eax ;"
67 "call *%%eax ;"
68 "popl %%edi; popl %%esi; popl %%edx; "
69 "popl %%ecx; popl %%ebx"
70 : "=a" (ret) : "0" (&hypercall) : "memory" );
71 #elif defined (__x86_64__)
72 {
73 long ign1, ign2, ign3;
74 __asm__ __volatile__ (
75 "movq %8,%%r10; movq %9,%%r8;"
76 "shlq $5,%%rax ;"
77 "addq $hypercall_page,%%rax ;"
78 "call *%%rax"
79 : "=a" (ret), "=D" (ign1),
80 "=S" (ign2), "=d" (ign3)
81 : "0" ((unsigned long)hypercall.op),
82 "1" ((unsigned long)hypercall.arg[0]),
83 "2" ((unsigned long)hypercall.arg[1]),
84 "3" ((unsigned long)hypercall.arg[2]),
85 "g" ((unsigned long)hypercall.arg[3]),
86 "g" ((unsigned long)hypercall.arg[4])
87 : "r8", "r10", "memory" );
88 }
89 #elif defined (__ia64__)
90 __asm__ __volatile__ (
91 ";; mov r14=%2; mov r15=%3; "
92 "mov r16=%4; mov r17=%5; mov r18=%6;"
93 "mov r2=%1; break 0x1000;; mov %0=r8 ;;"
94 : "=r" (ret)
95 : "r" (hypercall.op),
96 "r" (hypercall.arg[0]),
97 "r" (hypercall.arg[1]),
98 "r" (hypercall.arg[2]),
99 "r" (hypercall.arg[3]),
100 "r" (hypercall.arg[4])
101 : "r14","r15","r16","r17","r18","r2","r8","memory");
102 #endif
103 }
104 break;
106 case IOCTL_PRIVCMD_MMAP: {
107 privcmd_mmap_t mmapcmd;
108 privcmd_mmap_entry_t msg;
109 privcmd_mmap_entry_t __user *p;
110 struct mm_struct *mm = current->mm;
111 struct vm_area_struct *vma;
112 unsigned long va;
113 int i, rc;
115 if (!is_initial_xendomain())
116 return -EPERM;
118 if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
119 return -EFAULT;
121 p = mmapcmd.entry;
122 if (copy_from_user(&msg, p, sizeof(msg)))
123 return -EFAULT;
125 down_read(&mm->mmap_sem);
127 vma = find_vma(mm, msg.va);
128 rc = -EINVAL;
129 if (!vma || (msg.va != vma->vm_start) ||
130 !privcmd_enforce_singleshot_mapping(vma))
131 goto mmap_out;
133 va = vma->vm_start;
135 for (i = 0; i < mmapcmd.num; i++) {
136 rc = -EFAULT;
137 if (copy_from_user(&msg, p, sizeof(msg)))
138 goto mmap_out;
140 /* Do not allow range to wrap the address space. */
141 rc = -EINVAL;
142 if ((msg.npages > (LONG_MAX >> PAGE_SHIFT)) ||
143 ((unsigned long)(msg.npages << PAGE_SHIFT) >= -va))
144 goto mmap_out;
146 /* Range chunks must be contiguous in va space. */
147 if ((msg.va != va) ||
148 ((msg.va+(msg.npages<<PAGE_SHIFT)) > vma->vm_end))
149 goto mmap_out;
151 if ((rc = direct_remap_pfn_range(
152 vma,
153 msg.va & PAGE_MASK,
154 msg.mfn,
155 msg.npages << PAGE_SHIFT,
156 vma->vm_page_prot,
157 mmapcmd.dom)) < 0)
158 goto mmap_out;
160 p++;
161 va += msg.npages << PAGE_SHIFT;
162 }
164 rc = 0;
166 mmap_out:
167 up_read(&mm->mmap_sem);
168 ret = rc;
169 }
170 break;
172 case IOCTL_PRIVCMD_MMAPBATCH: {
173 privcmd_mmapbatch_t m;
174 struct mm_struct *mm = current->mm;
175 struct vm_area_struct *vma;
176 xen_pfn_t __user *p;
177 unsigned long addr, mfn;
178 int i;
180 if (!is_initial_xendomain())
181 return -EPERM;
183 if (copy_from_user(&m, udata, sizeof(m)))
184 return -EFAULT;
186 if ((m.num <= 0) || (m.num > (LONG_MAX >> PAGE_SHIFT)))
187 return -EINVAL;
189 down_read(&mm->mmap_sem);
191 vma = find_vma(mm, m.addr);
192 if (!vma ||
193 (m.addr != vma->vm_start) ||
194 ((m.addr + ((unsigned long)m.num<<PAGE_SHIFT)) !=
195 vma->vm_end) ||
196 !privcmd_enforce_singleshot_mapping(vma)) {
197 up_read(&mm->mmap_sem);
198 return -EINVAL;
199 }
201 p = m.arr;
202 addr = m.addr;
203 for (i = 0; i < m.num; i++, addr += PAGE_SIZE, p++) {
204 if (get_user(mfn, p)) {
205 up_read(&mm->mmap_sem);
206 return -EFAULT;
207 }
209 ret = direct_remap_pfn_range(vma, addr & PAGE_MASK,
210 mfn, PAGE_SIZE,
211 vma->vm_page_prot, m.dom);
212 if (ret < 0)
213 put_user(0xF0000000 | mfn, p);
214 }
216 up_read(&mm->mmap_sem);
217 ret = 0;
218 }
219 break;
221 default:
222 ret = -EINVAL;
223 break;
224 }
226 return ret;
227 }
229 #ifndef HAVE_ARCH_PRIVCMD_MMAP
230 static struct page *privcmd_nopage(struct vm_area_struct *vma,
231 unsigned long address,
232 int *type)
233 {
234 return NOPAGE_SIGBUS;
235 }
237 static struct vm_operations_struct privcmd_vm_ops = {
238 .nopage = privcmd_nopage
239 };
241 static int privcmd_mmap(struct file * file, struct vm_area_struct * vma)
242 {
243 /* Unsupported for auto-translate guests. */
244 if (xen_feature(XENFEAT_auto_translated_physmap))
245 return -ENOSYS;
247 /* DONTCOPY is essential for Xen as copy_page_range is broken. */
248 vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
249 vma->vm_ops = &privcmd_vm_ops;
250 vma->vm_private_data = NULL;
252 return 0;
253 }
255 static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
256 {
257 return (xchg(&vma->vm_private_data, (void *)1) == NULL);
258 }
259 #endif
261 static struct file_operations privcmd_file_ops = {
262 .ioctl = privcmd_ioctl,
263 .mmap = privcmd_mmap,
264 };
266 static int capabilities_read(char *page, char **start, off_t off,
267 int count, int *eof, void *data)
268 {
269 int len = 0;
270 *page = 0;
272 if (is_initial_xendomain())
273 len = sprintf( page, "control_d\n" );
275 *eof = 1;
276 return len;
277 }
279 static int __init privcmd_init(void)
280 {
281 if (!is_running_on_xen())
282 return -ENODEV;
284 privcmd_intf = create_xen_proc_entry("privcmd", 0400);
285 if (privcmd_intf != NULL)
286 privcmd_intf->proc_fops = &privcmd_file_ops;
288 capabilities_intf = create_xen_proc_entry("capabilities", 0400 );
289 if (capabilities_intf != NULL)
290 capabilities_intf->read_proc = capabilities_read;
292 return 0;
293 }
295 __initcall(privcmd_init);