direct-io.hg

view linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c @ 7530:813e504dc716

Necessary change to make ia64 dom0 rework:
- All even channels on xen/ia64 shares one common interrupt vector
- xen_start_info is initialized only after xen_init, so adjust
sequence to avoid access before initialization

Signed-off-by Kevin Tian <kevin.tian@intel.com>
author djm@kirby.fc.hp.com
date Mon Oct 24 09:15:53 2005 -0600 (2005-10-24)
parents 75ec60b67f64
children 5a4893a537ca
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>
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 <asm-xen/linux-public/privcmd.h>
30 #include <asm-xen/xen-public/xen.h>
31 #include <asm-xen/xen-public/dom0_ops.h>
32 #include <asm-xen/xen_proc.h>
34 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
35 #define pud_t pgd_t
36 #define pud_offset(d, va) d
37 #endif
39 static struct proc_dir_entry *privcmd_intf;
41 static int privcmd_ioctl(struct inode *inode, struct file *file,
42 unsigned int cmd, unsigned long data)
43 {
44 int ret = -ENOSYS;
46 switch (cmd) {
47 case IOCTL_PRIVCMD_HYPERCALL: {
48 privcmd_hypercall_t hypercall;
50 if (copy_from_user(&hypercall, (void *)data,
51 sizeof(hypercall)))
52 return -EFAULT;
54 #if defined(__i386__)
55 __asm__ __volatile__ (
56 "pushl %%ebx; pushl %%ecx; pushl %%edx; "
57 "pushl %%esi; pushl %%edi; "
58 "movl 4(%%eax),%%ebx ;"
59 "movl 8(%%eax),%%ecx ;"
60 "movl 12(%%eax),%%edx ;"
61 "movl 16(%%eax),%%esi ;"
62 "movl 20(%%eax),%%edi ;"
63 "movl (%%eax),%%eax ;"
64 TRAP_INSTR "; "
65 "popl %%edi; popl %%esi; popl %%edx; "
66 "popl %%ecx; popl %%ebx"
67 : "=a" (ret) : "0" (&hypercall) : "memory" );
68 #elif defined (__x86_64__)
69 {
70 long ign1, ign2, ign3;
71 __asm__ __volatile__ (
72 "movq %8,%%r10; movq %9,%%r8;" TRAP_INSTR
73 : "=a" (ret), "=D" (ign1),
74 "=S" (ign2), "=d" (ign3)
75 : "0" ((unsigned long)hypercall.op),
76 "1" ((unsigned long)hypercall.arg[0]),
77 "2" ((unsigned long)hypercall.arg[1]),
78 "3" ((unsigned long)hypercall.arg[2]),
79 "g" ((unsigned long)hypercall.arg[3]),
80 "g" ((unsigned long)hypercall.arg[4])
81 : "r11","rcx","r8","r10","memory");
82 }
83 #elif defined (__ia64__)
84 __asm__ __volatile__ (
85 ";; mov r14=%2; mov r15=%3; "
86 "mov r16=%4; mov r17=%5; mov r18=%6;"
87 "mov r2=%1; break 0x1000;; mov %0=r8 ;;"
88 : "=r" (ret)
89 : "r" (hypercall.op),
90 "r" (hypercall.arg[0]),
91 "r" (hypercall.arg[1]),
92 "r" (hypercall.arg[2]),
93 "r" (hypercall.arg[3]),
94 "r" (hypercall.arg[4])
95 : "r14","r15","r16","r17","r18","r2","r8","memory");
96 #endif
97 }
98 break;
100 #if defined(CONFIG_XEN_PRIVILEGED_GUEST)
101 case IOCTL_PRIVCMD_MMAP: {
102 #define PRIVCMD_MMAP_SZ 32
103 privcmd_mmap_t mmapcmd;
104 privcmd_mmap_entry_t msg[PRIVCMD_MMAP_SZ], *p;
105 int i, rc;
107 if (copy_from_user(&mmapcmd, (void *)data, sizeof(mmapcmd)))
108 return -EFAULT;
110 p = mmapcmd.entry;
112 for (i = 0; i < mmapcmd.num;
113 i += PRIVCMD_MMAP_SZ, p += PRIVCMD_MMAP_SZ) {
114 int j, n = ((mmapcmd.num-i)>PRIVCMD_MMAP_SZ)?
115 PRIVCMD_MMAP_SZ:(mmapcmd.num-i);
117 if (copy_from_user(&msg, p,
118 n*sizeof(privcmd_mmap_entry_t)))
119 return -EFAULT;
121 for (j = 0; j < n; j++) {
122 struct vm_area_struct *vma =
123 find_vma( current->mm, msg[j].va );
125 if (!vma)
126 return -EINVAL;
128 if (msg[j].va > PAGE_OFFSET)
129 return -EINVAL;
131 if ((msg[j].va + (msg[j].npages << PAGE_SHIFT))
132 > vma->vm_end )
133 return -EINVAL;
135 if ((rc = direct_remap_pfn_range(
136 vma,
137 msg[j].va&PAGE_MASK,
138 msg[j].mfn,
139 msg[j].npages<<PAGE_SHIFT,
140 vma->vm_page_prot,
141 mmapcmd.dom)) < 0)
142 return rc;
143 }
144 }
145 ret = 0;
146 }
147 break;
149 case IOCTL_PRIVCMD_MMAPBATCH: {
150 mmu_update_t u;
151 privcmd_mmapbatch_t m;
152 struct vm_area_struct *vma = NULL;
153 unsigned long *p, addr;
154 unsigned long mfn, ptep;
155 int i;
157 if (copy_from_user(&m, (void *)data, sizeof(m))) {
158 ret = -EFAULT;
159 goto batch_err;
160 }
162 vma = find_vma( current->mm, m.addr );
163 if (!vma) {
164 ret = -EINVAL;
165 goto batch_err;
166 }
168 if (m.addr > PAGE_OFFSET) {
169 ret = -EFAULT;
170 goto batch_err;
171 }
173 if ((m.addr + (m.num<<PAGE_SHIFT)) > vma->vm_end) {
174 ret = -EFAULT;
175 goto batch_err;
176 }
178 p = m.arr;
179 addr = m.addr;
180 for (i = 0; i < m.num; i++, addr += PAGE_SIZE, p++) {
181 if (get_user(mfn, p))
182 return -EFAULT;
184 ret = create_lookup_pte_addr(vma->vm_mm, addr, &ptep);
185 if (ret)
186 goto batch_err;
188 u.val = pte_val_ma(pfn_pte_ma(mfn, vma->vm_page_prot));
189 u.ptr = ptep;
191 if (HYPERVISOR_mmu_update(&u, 1, NULL, m.dom) < 0)
192 put_user(0xF0000000 | mfn, p);
193 }
195 ret = 0;
196 break;
198 batch_err:
199 printk("batch_err ret=%d vma=%p addr=%lx "
200 "num=%d arr=%p %lx-%lx\n",
201 ret, vma, m.addr, m.num, m.arr,
202 vma ? vma->vm_start : 0, vma ? vma->vm_end : 0);
203 break;
204 }
205 break;
206 #endif
208 case IOCTL_PRIVCMD_GET_MACH2PHYS_START_MFN: {
209 unsigned long m2pv = (unsigned long)machine_to_phys_mapping;
210 pgd_t *pgd = pgd_offset_k(m2pv);
211 pud_t *pud = pud_offset(pgd, m2pv);
212 pmd_t *pmd = pmd_offset(pud, m2pv);
213 unsigned long m2p_start_mfn =
214 (*(unsigned long *)pmd) >> PAGE_SHIFT;
215 ret = put_user(m2p_start_mfn, (unsigned long *)data) ?
216 -EFAULT: 0;
217 }
218 break;
220 default:
221 ret = -EINVAL;
222 break;
223 }
225 return ret;
226 }
228 static int privcmd_mmap(struct file * file, struct vm_area_struct * vma)
229 {
230 /* DONTCOPY is essential for Xen as copy_page_range is broken. */
231 vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
233 return 0;
234 }
236 static struct file_operations privcmd_file_ops = {
237 .ioctl = privcmd_ioctl,
238 .mmap = privcmd_mmap,
239 };
242 static int __init privcmd_init(void)
243 {
244 privcmd_intf = create_xen_proc_entry("privcmd", 0400);
245 if (privcmd_intf != NULL)
246 privcmd_intf->proc_fops = &privcmd_file_ops;
248 return 0;
249 }
251 __initcall(privcmd_init);
253 /*
254 * Local variables:
255 * c-file-style: "linux"
256 * indent-tabs-mode: t
257 * c-indent-level: 8
258 * c-basic-offset: 8
259 * tab-width: 8
260 * End:
261 */