1 /******************************************************************************
4 * Two sets of functionality:
5 * 1. Granting foreign access to our memory reservation.
6 * 2. Accessing others' memory reservations via grant references.
7 * (i.e., mechanisms for both sender and recipient of grant references)
9 * Copyright (c) 2005, Christopher Clark
10 * Copyright (c) 2004, K A Fraser
13 #include <linux/config.h>
14 #include <linux/module.h>
15 #include <linux/sched.h>
16 #include <asm/pgtable.h>
17 #include <asm/fixmap.h>
18 #include <asm/uaccess.h>
19 #include <asm-xen/xen_proc.h>
20 #include <asm-xen/linux-public/privcmd.h>
21 #include <asm-xen/gnttab.h>
24 #define set_fixmap_ma set_fixmap
29 if ( !(_p) ) { printk(KERN_ALERT"Assertion '%s': line %d, file %s\n", \
30 #_p , __LINE__, __FILE__); *(int*)0=0; }
32 #define ASSERT(_p) ((void)0)
35 #define WPRINTK(fmt, args...) \
36 printk(KERN_WARNING "xen_grant: " fmt, ##args)
39 EXPORT_SYMBOL(gnttab_grant_foreign_access);
40 EXPORT_SYMBOL(gnttab_end_foreign_access);
41 EXPORT_SYMBOL(gnttab_query_foreign_access);
42 EXPORT_SYMBOL(gnttab_grant_foreign_transfer);
43 EXPORT_SYMBOL(gnttab_end_foreign_transfer);
44 EXPORT_SYMBOL(gnttab_alloc_grant_references);
45 EXPORT_SYMBOL(gnttab_free_grant_references);
46 EXPORT_SYMBOL(gnttab_claim_grant_reference);
47 EXPORT_SYMBOL(gnttab_release_grant_reference);
48 EXPORT_SYMBOL(gnttab_grant_foreign_access_ref);
49 EXPORT_SYMBOL(gnttab_grant_foreign_transfer_ref);
51 static grant_ref_t gnttab_free_list[NR_GRANT_ENTRIES];
52 static grant_ref_t gnttab_free_head;
54 static grant_entry_t *shared;
57 * Lock-free grant-entry allocator
64 grant_ref_t fh, nfh = gnttab_free_head;
65 do { if ( unlikely((fh = nfh) == NR_GRANT_ENTRIES) ) return -1; }
66 while ( unlikely((nfh = cmpxchg(&gnttab_free_head, fh,
67 gnttab_free_list[fh])) != fh) );
75 grant_ref_t fh, nfh = gnttab_free_head;
76 do { gnttab_free_list[ref] = fh = nfh; wmb(); }
77 while ( unlikely((nfh = cmpxchg(&gnttab_free_head, fh, ref)) != fh) );
81 * Public grant-issuing interface functions
85 gnttab_grant_foreign_access(
86 domid_t domid, unsigned long frame, int readonly)
90 if ( unlikely((ref = get_free_entry()) == -1) )
93 shared[ref].frame = frame;
94 shared[ref].domid = domid;
96 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
102 gnttab_grant_foreign_access_ref(
103 grant_ref_t ref, domid_t domid, unsigned long frame, int readonly)
105 shared[ref].frame = frame;
106 shared[ref].domid = domid;
108 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
113 gnttab_query_foreign_access( grant_ref_t ref )
117 nflags = shared[ref].flags;
119 return ( nflags & (GTF_reading|GTF_writing) );
123 gnttab_end_foreign_access( grant_ref_t ref, int readonly )
127 nflags = shared[ref].flags;
129 if ( (flags = nflags) & (GTF_reading|GTF_writing) )
130 printk(KERN_ALERT "WARNING: g.e. still in use!\n");
132 while ( (nflags = cmpxchg(&shared[ref].flags, flags, 0)) != flags );
138 gnttab_grant_foreign_transfer(
139 domid_t domid, unsigned long pfn )
143 if ( unlikely((ref = get_free_entry()) == -1) )
146 shared[ref].frame = pfn;
147 shared[ref].domid = domid;
149 shared[ref].flags = GTF_accept_transfer;
155 gnttab_grant_foreign_transfer_ref(
156 grant_ref_t ref, domid_t domid, unsigned long pfn )
158 shared[ref].frame = pfn;
159 shared[ref].domid = domid;
161 shared[ref].flags = GTF_accept_transfer;
165 gnttab_end_foreign_transfer(
168 unsigned long frame = 0;
171 flags = shared[ref].flags;
172 ASSERT(flags == (GTF_accept_transfer | GTF_transfer_committed));
175 * If a transfer is committed then wait for the frame address to appear.
176 * Otherwise invalidate the grant entry against future use.
178 if ( likely(flags != GTF_accept_transfer) ||
179 (cmpxchg(&shared[ref].flags, flags, 0) != GTF_accept_transfer) )
180 while ( unlikely((frame = shared[ref].frame) == 0) )
189 gnttab_free_grant_references( u16 count, grant_ref_t head )
192 grant_ref_t to_die = 0, next = head;
195 for ( i = 0; i < count; i++ )
197 next = gnttab_free_list[next];
198 put_free_entry( to_die );
202 gnttab_alloc_grant_references( u16 count,
204 grant_ref_t *terminal )
207 grant_ref_t h = gnttab_free_head;
209 for ( i = 0; i < count; i++ )
210 if ( unlikely(get_free_entry() == -1) )
211 goto not_enough_refs;
214 *terminal = gnttab_free_head;
219 gnttab_free_head = h;
224 gnttab_claim_grant_reference( grant_ref_t *private_head,
225 grant_ref_t terminal )
228 if ( unlikely((g = *private_head) == terminal) )
230 *private_head = gnttab_free_list[g];
235 gnttab_release_grant_reference( grant_ref_t *private_head,
236 grant_ref_t release )
238 gnttab_free_list[release] = *private_head;
239 *private_head = release;
246 #ifdef CONFIG_PROC_FS
248 static struct proc_dir_entry *grant_pde;
250 static int grant_ioctl(struct inode *inode, struct file *file,
251 unsigned int cmd, unsigned long data)
254 privcmd_hypercall_t hypercall;
256 /* XXX Need safety checks here if using for anything other
260 if ( cmd != IOCTL_PRIVCMD_HYPERCALL )
263 if ( copy_from_user(&hypercall, (void *)data, sizeof(hypercall)) )
266 if ( hypercall.op != __HYPERVISOR_grant_table_op )
269 /* hypercall-invoking asm taken from privcmd.c */
270 __asm__ __volatile__ (
271 "pushl %%ebx; pushl %%ecx; pushl %%edx; pushl %%esi; pushl %%edi; "
272 "movl 4(%%eax),%%ebx ;"
273 "movl 8(%%eax),%%ecx ;"
274 "movl 12(%%eax),%%edx ;"
275 "movl 16(%%eax),%%esi ;"
276 "movl 20(%%eax),%%edi ;"
277 "movl (%%eax),%%eax ;"
279 "popl %%edi; popl %%esi; popl %%edx; popl %%ecx; popl %%ebx"
280 : "=a" (ret) : "0" (&hypercall) : "memory" );
285 static struct file_operations grant_file_ops = {
289 static int grant_read(char *page, char **start, off_t off,
290 int count, int *eof, void *data)
296 gt = (grant_entry_t *)shared;
299 for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
300 /* TODO: safety catch here until this can handle >PAGE_SIZE output */
301 if (len > (PAGE_SIZE - 200))
303 len += sprintf( page + len, "Truncated.\n");
308 len += sprintf( page + len,
309 "Grant: ref (0x%x) flags (0x%hx) dom (0x%hx) frame (0x%x)\n",
319 static int grant_write(struct file *file, const char __user *buffer,
320 unsigned long count, void *data)
322 /* TODO: implement this */
326 #endif /* CONFIG_PROC_FS */
328 int gnttab_resume(void)
330 gnttab_setup_table_t setup;
331 unsigned long frames[NR_GRANT_FRAMES];
334 setup.dom = DOMID_SELF;
335 setup.nr_frames = NR_GRANT_FRAMES;
336 setup.frame_list = frames;
338 BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1) != 0);
339 BUG_ON(setup.status != 0);
341 for ( i = 0; i < NR_GRANT_FRAMES; i++ )
342 set_fixmap_ma(FIX_GNTTAB_END - i, frames[i] << PAGE_SHIFT);
347 int gnttab_suspend(void)
351 for ( i = 0; i < NR_GRANT_FRAMES; i++ )
352 clear_fixmap(FIX_GNTTAB_END - i);
357 static int __init gnttab_init(void)
361 BUG_ON(gnttab_resume());
363 shared = (grant_entry_t *)fix_to_virt(FIX_GNTTAB_END);
365 for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
366 gnttab_free_list[i] = i + 1;
368 #ifdef CONFIG_PROC_FS
370 * /proc/xen/grant : used by libxc to access grant tables
372 if ( (grant_pde = create_xen_proc_entry("grant", 0600)) == NULL )
374 WPRINTK("Unable to create grant xen proc entry\n");
378 grant_file_ops.read = grant_pde->proc_fops->read;
379 grant_file_ops.write = grant_pde->proc_fops->write;
381 grant_pde->proc_fops = &grant_file_ops;
383 grant_pde->read_proc = &grant_read;
384 grant_pde->write_proc = &grant_write;
387 printk("Grant table initialized\n");
391 __initcall(gnttab_init);