ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c @ 7294:5df423407700

Added some clarifying comments regarding xenbus/xenstore kernel startup.

Signed-off-by: Steven Hand <steven@xensource.com>
author smh22@firebug.cl.cam.ac.uk
date Sun Oct 09 20:55:53 2005 +0100 (2005-10-09)
parents b6ee1d1cdc93
children 75ec60b67f64
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-xen/xen-public/xen.h>
29 #include <asm/hypervisor.h>
30 #include <asm-xen/linux-public/privcmd.h>
31 #include <asm/hypervisor.h>
32 #include <asm-xen/xen-public/xen.h>
33 #include <asm-xen/xen-public/dom0_ops.h>
34 #include <asm-xen/xen_proc.h>
36 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
37 #define pud_t pgd_t
38 #define pud_offset(d, va) d
39 #endif
41 static struct proc_dir_entry *privcmd_intf;
43 static int privcmd_ioctl(struct inode *inode, struct file *file,
44 unsigned int cmd, unsigned long data)
45 {
46 int ret = -ENOSYS;
48 switch (cmd) {
49 case IOCTL_PRIVCMD_HYPERCALL: {
50 privcmd_hypercall_t hypercall;
52 if (copy_from_user(&hypercall, (void *)data,
53 sizeof(hypercall)))
54 return -EFAULT;
56 #if defined(__i386__)
57 __asm__ __volatile__ (
58 "pushl %%ebx; pushl %%ecx; pushl %%edx; "
59 "pushl %%esi; pushl %%edi; "
60 "movl 4(%%eax),%%ebx ;"
61 "movl 8(%%eax),%%ecx ;"
62 "movl 12(%%eax),%%edx ;"
63 "movl 16(%%eax),%%esi ;"
64 "movl 20(%%eax),%%edi ;"
65 "movl (%%eax),%%eax ;"
66 TRAP_INSTR "; "
67 "popl %%edi; popl %%esi; popl %%edx; "
68 "popl %%ecx; popl %%ebx"
69 : "=a" (ret) : "0" (&hypercall) : "memory" );
70 #elif defined (__x86_64__)
71 {
72 long ign1, ign2, ign3;
73 __asm__ __volatile__ (
74 "movq %8,%%r10; movq %9,%%r8;" TRAP_INSTR
75 : "=a" (ret), "=D" (ign1),
76 "=S" (ign2), "=d" (ign3)
77 : "0" ((unsigned long)hypercall.op),
78 "1" ((unsigned long)hypercall.arg[0]),
79 "2" ((unsigned long)hypercall.arg[1]),
80 "3" ((unsigned long)hypercall.arg[2]),
81 "g" ((unsigned long)hypercall.arg[3]),
82 "g" ((unsigned long)hypercall.arg[4])
83 : "r11","rcx","r8","r10","memory");
84 }
85 #elif defined (__ia64__)
86 __asm__ __volatile__ (
87 ";; mov r14=%2; mov r15=%3; "
88 "mov r16=%4; mov r17=%5; mov r18=%6;"
89 "mov r2=%1; break 0x1000;; mov %0=r8 ;;"
90 : "=r" (ret)
91 : "r" (hypercall.op),
92 "r" (hypercall.arg[0]),
93 "r" (hypercall.arg[1]),
94 "r" (hypercall.arg[2]),
95 "r" (hypercall.arg[3]),
96 "r" (hypercall.arg[4])
97 : "r14","r15","r16","r17","r18","r2","r8","memory");
98 #endif
99 }
100 break;
102 #if defined(CONFIG_XEN_PRIVILEGED_GUEST)
103 case IOCTL_PRIVCMD_MMAP: {
104 #define PRIVCMD_MMAP_SZ 32
105 privcmd_mmap_t mmapcmd;
106 privcmd_mmap_entry_t msg[PRIVCMD_MMAP_SZ], *p;
107 int i, rc;
109 if (copy_from_user(&mmapcmd, (void *)data, sizeof(mmapcmd)))
110 return -EFAULT;
112 p = mmapcmd.entry;
114 for (i = 0; i < mmapcmd.num;
115 i += PRIVCMD_MMAP_SZ, p += PRIVCMD_MMAP_SZ) {
116 int j, n = ((mmapcmd.num-i)>PRIVCMD_MMAP_SZ)?
117 PRIVCMD_MMAP_SZ:(mmapcmd.num-i);
119 if (copy_from_user(&msg, p,
120 n*sizeof(privcmd_mmap_entry_t)))
121 return -EFAULT;
123 for (j = 0; j < n; j++) {
124 struct vm_area_struct *vma =
125 find_vma( current->mm, msg[j].va );
127 if (!vma)
128 return -EINVAL;
130 if (msg[j].va > PAGE_OFFSET)
131 return -EINVAL;
133 if ((msg[j].va + (msg[j].npages << PAGE_SHIFT))
134 > vma->vm_end )
135 return -EINVAL;
137 if ((rc = direct_remap_pfn_range(
138 vma,
139 msg[j].va&PAGE_MASK,
140 msg[j].mfn,
141 msg[j].npages<<PAGE_SHIFT,
142 vma->vm_page_prot,
143 mmapcmd.dom)) < 0)
144 return rc;
145 }
146 }
147 ret = 0;
148 }
149 break;
151 case IOCTL_PRIVCMD_MMAPBATCH: {
152 mmu_update_t u;
153 privcmd_mmapbatch_t m;
154 struct vm_area_struct *vma = NULL;
155 unsigned long *p, addr;
156 unsigned long mfn, ptep;
157 int i;
159 if (copy_from_user(&m, (void *)data, sizeof(m))) {
160 ret = -EFAULT;
161 goto batch_err;
162 }
164 vma = find_vma( current->mm, m.addr );
165 if (!vma) {
166 ret = -EINVAL;
167 goto batch_err;
168 }
170 if (m.addr > PAGE_OFFSET) {
171 ret = -EFAULT;
172 goto batch_err;
173 }
175 if ((m.addr + (m.num<<PAGE_SHIFT)) > vma->vm_end) {
176 ret = -EFAULT;
177 goto batch_err;
178 }
180 p = m.arr;
181 addr = m.addr;
182 for (i = 0; i < m.num; i++, addr += PAGE_SIZE, p++) {
183 if (get_user(mfn, p))
184 return -EFAULT;
186 ret = create_lookup_pte_addr(vma->vm_mm, addr, &ptep);
187 if (ret)
188 goto batch_err;
190 u.val = pte_val_ma(pfn_pte_ma(mfn, vma->vm_page_prot));
191 u.ptr = ptep;
193 if (HYPERVISOR_mmu_update(&u, 1, NULL, m.dom) < 0)
194 put_user(0xF0000000 | mfn, p);
195 }
197 ret = 0;
198 break;
200 batch_err:
201 printk("batch_err ret=%d vma=%p addr=%lx "
202 "num=%d arr=%p %lx-%lx\n",
203 ret, vma, m.addr, m.num, m.arr,
204 vma ? vma->vm_start : 0, vma ? vma->vm_end : 0);
205 break;
206 }
207 break;
208 #endif
210 case IOCTL_PRIVCMD_GET_MACH2PHYS_START_MFN: {
211 unsigned long m2pv = (unsigned long)machine_to_phys_mapping;
212 pgd_t *pgd = pgd_offset_k(m2pv);
213 pud_t *pud = pud_offset(pgd, m2pv);
214 pmd_t *pmd = pmd_offset(pud, m2pv);
215 unsigned long m2p_start_mfn =
216 (*(unsigned long *)pmd) >> PAGE_SHIFT;
217 ret = put_user(m2p_start_mfn, (unsigned long *)data) ?
218 -EFAULT: 0;
219 }
220 break;
222 case IOCTL_PRIVCMD_INITDOMAIN_STORE: {
223 extern int do_xenbus_probe(void*);
224 unsigned long page;
226 if (xen_start_info->store_evtchn != 0) {
227 ret = xen_start_info->store_mfn;
228 break;
229 }
231 /* Allocate page. */
232 page = get_zeroed_page(GFP_KERNEL);
233 if (!page) {
234 ret = -ENOMEM;
235 break;
236 }
238 /* We don't refcnt properly, so set reserved on page.
239 * (this allocation is permanent) */
240 SetPageReserved(virt_to_page(page));
242 /* Initial connect. Setup channel and page. */
243 xen_start_info->store_evtchn = data;
244 xen_start_info->store_mfn =
245 pfn_to_mfn(virt_to_phys((void *)page) >>
246 PAGE_SHIFT);
247 ret = xen_start_info->store_mfn;
249 /*
250 ** Complete initialization of xenbus (viz. set up the
251 ** connection to xenstored now that it has started).
252 */
253 kthread_run(do_xenbus_probe, NULL, "xenbus_probe");
254 }
255 break;
257 default:
258 ret = -EINVAL;
259 break;
260 }
262 return ret;
263 }
265 static int privcmd_mmap(struct file * file, struct vm_area_struct * vma)
266 {
267 /* DONTCOPY is essential for Xen as copy_page_range is broken. */
268 vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
270 return 0;
271 }
273 static struct file_operations privcmd_file_ops = {
274 .ioctl = privcmd_ioctl,
275 .mmap = privcmd_mmap,
276 };
279 static int __init privcmd_init(void)
280 {
281 privcmd_intf = create_xen_proc_entry("privcmd", 0400);
282 if (privcmd_intf != NULL)
283 privcmd_intf->proc_fops = &privcmd_file_ops;
285 return 0;
286 }
288 __initcall(privcmd_init);
290 /*
291 * Local variables:
292 * c-file-style: "linux"
293 * indent-tabs-mode: t
294 * c-indent-level: 8
295 * c-basic-offset: 8
296 * tab-width: 8
297 * End:
298 */