ia64/xen-unstable

view linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c @ 6780:e17161930711

synch_bitops.h is an arch-specific header file.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Tue Sep 13 10:40:29 2005 +0000 (2005-09-13)
parents 291e816acbf4
children 4d899a738d59 8ca0f98ba8e2
line source
1 /******************************************************************************
2 * gnttab.c
3 *
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)
8 *
9 * Copyright (c) 2005, Christopher Clark
10 * Copyright (c) 2004, K A Fraser
11 */
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>
22 #include <asm/synch_bitops.h>
24 #if 1
25 #define ASSERT(_p) \
26 if ( !(_p) ) { printk(KERN_ALERT"Assertion '%s': line %d, file %s\n", \
27 #_p , __LINE__, __FILE__); *(int*)0=0; }
28 #else
29 #define ASSERT(_p) ((void)0)
30 #endif
32 #define WPRINTK(fmt, args...) \
33 printk(KERN_WARNING "xen_grant: " fmt, ##args)
36 EXPORT_SYMBOL(gnttab_grant_foreign_access);
37 EXPORT_SYMBOL(gnttab_end_foreign_access_ref);
38 EXPORT_SYMBOL(gnttab_end_foreign_access);
39 EXPORT_SYMBOL(gnttab_query_foreign_access);
40 EXPORT_SYMBOL(gnttab_grant_foreign_transfer);
41 EXPORT_SYMBOL(gnttab_end_foreign_transfer_ref);
42 EXPORT_SYMBOL(gnttab_end_foreign_transfer);
43 EXPORT_SYMBOL(gnttab_alloc_grant_references);
44 EXPORT_SYMBOL(gnttab_free_grant_references);
45 EXPORT_SYMBOL(gnttab_free_grant_reference);
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 #define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(grant_entry_t))
52 #define GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1)
54 static grant_ref_t gnttab_list[NR_GRANT_ENTRIES];
55 static int gnttab_free_count = NR_GRANT_ENTRIES;
56 static grant_ref_t gnttab_free_head;
57 static spinlock_t gnttab_list_lock = SPIN_LOCK_UNLOCKED;
59 static grant_entry_t *shared;
61 static struct gnttab_free_callback *gnttab_free_callback_list = NULL;
63 static int
64 get_free_entries(int count)
65 {
66 unsigned long flags;
67 int ref;
68 grant_ref_t head;
69 spin_lock_irqsave(&gnttab_list_lock, flags);
70 if (gnttab_free_count < count) {
71 spin_unlock_irqrestore(&gnttab_list_lock, flags);
72 return -1;
73 }
74 ref = head = gnttab_free_head;
75 gnttab_free_count -= count;
76 while (count-- > 1)
77 head = gnttab_list[head];
78 gnttab_free_head = gnttab_list[head];
79 gnttab_list[head] = GNTTAB_LIST_END;
80 spin_unlock_irqrestore(&gnttab_list_lock, flags);
81 return ref;
82 }
84 #define get_free_entry() get_free_entries(1)
86 static void
87 do_free_callbacks(void)
88 {
89 struct gnttab_free_callback *callback = gnttab_free_callback_list, *next;
90 gnttab_free_callback_list = NULL;
91 while (callback) {
92 next = callback->next;
93 if (gnttab_free_count >= callback->count) {
94 callback->next = NULL;
95 callback->fn(callback->arg);
96 } else {
97 callback->next = gnttab_free_callback_list;
98 gnttab_free_callback_list = callback;
99 }
100 callback = next;
101 }
102 }
104 static inline void
105 check_free_callbacks(void)
106 {
107 if (unlikely(gnttab_free_callback_list))
108 do_free_callbacks();
109 }
111 static void
112 put_free_entry(grant_ref_t ref)
113 {
114 unsigned long flags;
115 spin_lock_irqsave(&gnttab_list_lock, flags);
116 gnttab_list[ref] = gnttab_free_head;
117 gnttab_free_head = ref;
118 gnttab_free_count++;
119 check_free_callbacks();
120 spin_unlock_irqrestore(&gnttab_list_lock, flags);
121 }
123 /*
124 * Public grant-issuing interface functions
125 */
127 int
128 gnttab_grant_foreign_access(domid_t domid, unsigned long frame, int readonly)
129 {
130 int ref;
132 if ( unlikely((ref = get_free_entry()) == -1) )
133 return -ENOSPC;
135 shared[ref].frame = frame;
136 shared[ref].domid = domid;
137 wmb();
138 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
140 return ref;
141 }
143 void
144 gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
145 unsigned long frame, int readonly)
146 {
147 shared[ref].frame = frame;
148 shared[ref].domid = domid;
149 wmb();
150 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
151 }
154 int
155 gnttab_query_foreign_access(grant_ref_t ref)
156 {
157 u16 nflags;
159 nflags = shared[ref].flags;
161 return ( nflags & (GTF_reading|GTF_writing) );
162 }
164 void
165 gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
166 {
167 u16 flags, nflags;
169 nflags = shared[ref].flags;
170 do {
171 if ( (flags = nflags) & (GTF_reading|GTF_writing) )
172 printk(KERN_ALERT "WARNING: g.e. still in use!\n");
173 }
174 while ( (nflags = synch_cmpxchg(&shared[ref].flags, flags, 0)) != flags );
175 }
177 void
178 gnttab_end_foreign_access(grant_ref_t ref, int readonly)
179 {
180 gnttab_end_foreign_access_ref(ref, readonly);
181 put_free_entry(ref);
182 }
184 int
185 gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
186 {
187 int ref;
189 if ( unlikely((ref = get_free_entry()) == -1) )
190 return -ENOSPC;
192 shared[ref].frame = pfn;
193 shared[ref].domid = domid;
194 wmb();
195 shared[ref].flags = GTF_accept_transfer;
197 return ref;
198 }
200 void
201 gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
202 unsigned long pfn)
203 {
204 shared[ref].frame = pfn;
205 shared[ref].domid = domid;
206 wmb();
207 shared[ref].flags = GTF_accept_transfer;
208 }
210 unsigned long
211 gnttab_end_foreign_transfer_ref(grant_ref_t ref)
212 {
213 unsigned long frame = 0;
214 u16 flags;
216 flags = shared[ref].flags;
218 /*
219 * If a transfer is committed then wait for the frame address to appear.
220 * Otherwise invalidate the grant entry against future use.
221 */
222 if ( likely(flags != GTF_accept_transfer) ||
223 (synch_cmpxchg(&shared[ref].flags, flags, 0) != GTF_accept_transfer) )
224 while ( unlikely((frame = shared[ref].frame) == 0) )
225 cpu_relax();
227 return frame;
228 }
230 unsigned long
231 gnttab_end_foreign_transfer(grant_ref_t ref)
232 {
233 unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
234 put_free_entry(ref);
235 return frame;
236 }
238 void
239 gnttab_free_grant_reference(grant_ref_t ref)
240 {
242 put_free_entry(ref);
243 }
245 void
246 gnttab_free_grant_references(grant_ref_t head)
247 {
248 grant_ref_t ref;
249 unsigned long flags;
250 int count = 1;
251 if (head == GNTTAB_LIST_END)
252 return;
253 spin_lock_irqsave(&gnttab_list_lock, flags);
254 ref = head;
255 while (gnttab_list[ref] != GNTTAB_LIST_END) {
256 ref = gnttab_list[ref];
257 count++;
258 }
259 gnttab_list[ref] = gnttab_free_head;
260 gnttab_free_head = head;
261 gnttab_free_count += count;
262 check_free_callbacks();
263 spin_unlock_irqrestore(&gnttab_list_lock, flags);
264 }
266 int
267 gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
268 {
269 int h = get_free_entries(count);
271 if (h == -1)
272 return -ENOSPC;
274 *head = h;
276 return 0;
277 }
279 int
280 gnttab_claim_grant_reference(grant_ref_t *private_head)
281 {
282 grant_ref_t g = *private_head;
283 if (unlikely(g == GNTTAB_LIST_END))
284 return -ENOSPC;
285 *private_head = gnttab_list[g];
286 return g;
287 }
289 void
290 gnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release)
291 {
292 gnttab_list[release] = *private_head;
293 *private_head = release;
294 }
296 void
297 gnttab_request_free_callback(struct gnttab_free_callback *callback,
298 void (*fn)(void *), void *arg, u16 count)
299 {
300 unsigned long flags;
301 spin_lock_irqsave(&gnttab_list_lock, flags);
302 if (callback->next)
303 goto out;
304 callback->fn = fn;
305 callback->arg = arg;
306 callback->count = count;
307 callback->next = gnttab_free_callback_list;
308 gnttab_free_callback_list = callback;
309 check_free_callbacks();
310 out:
311 spin_unlock_irqrestore(&gnttab_list_lock, flags);
312 }
314 /*
315 * ProcFS operations
316 */
318 #ifdef CONFIG_PROC_FS
320 static struct proc_dir_entry *grant_pde;
322 static int
323 grant_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
324 unsigned long data)
325 {
326 int ret;
327 privcmd_hypercall_t hypercall;
329 /* XXX Need safety checks here if using for anything other
330 * than debugging */
331 return -ENOSYS;
333 if ( cmd != IOCTL_PRIVCMD_HYPERCALL )
334 return -ENOSYS;
336 if ( copy_from_user(&hypercall, (void *)data, sizeof(hypercall)) )
337 return -EFAULT;
339 if ( hypercall.op != __HYPERVISOR_grant_table_op )
340 return -ENOSYS;
342 /* hypercall-invoking asm taken from privcmd.c */
343 __asm__ __volatile__ (
344 "pushl %%ebx; pushl %%ecx; pushl %%edx; pushl %%esi; pushl %%edi; "
345 "movl 4(%%eax),%%ebx ;"
346 "movl 8(%%eax),%%ecx ;"
347 "movl 12(%%eax),%%edx ;"
348 "movl 16(%%eax),%%esi ;"
349 "movl 20(%%eax),%%edi ;"
350 "movl (%%eax),%%eax ;"
351 TRAP_INSTR "; "
352 "popl %%edi; popl %%esi; popl %%edx; popl %%ecx; popl %%ebx"
353 : "=a" (ret) : "0" (&hypercall) : "memory" );
355 return ret;
356 }
358 static struct file_operations grant_file_ops = {
359 ioctl: grant_ioctl,
360 };
362 static int
363 grant_read(char *page, char **start, off_t off, int count, int *eof,
364 void *data)
365 {
366 int len;
367 unsigned int i;
368 grant_entry_t *gt;
370 gt = (grant_entry_t *)shared;
371 len = 0;
373 for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
374 /* TODO: safety catch here until this can handle >PAGE_SIZE output */
375 if (len > (PAGE_SIZE - 200))
376 {
377 len += sprintf( page + len, "Truncated.\n");
378 break;
379 }
381 if ( gt[i].flags )
382 len += sprintf( page + len,
383 "Grant: ref (0x%x) flags (0x%hx) dom (0x%hx) frame (0x%x)\n",
384 i,
385 gt[i].flags,
386 gt[i].domid,
387 gt[i].frame );
389 *eof = 1;
390 return len;
391 }
393 static int
394 grant_write(struct file *file, const char __user *buffer, unsigned long count,
395 void *data)
396 {
397 /* TODO: implement this */
398 return -ENOSYS;
399 }
401 #endif /* CONFIG_PROC_FS */
403 int
404 gnttab_resume(void)
405 {
406 gnttab_setup_table_t setup;
407 unsigned long frames[NR_GRANT_FRAMES];
408 int i;
410 setup.dom = DOMID_SELF;
411 setup.nr_frames = NR_GRANT_FRAMES;
412 setup.frame_list = frames;
414 BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1) != 0);
415 BUG_ON(setup.status != 0);
417 for ( i = 0; i < NR_GRANT_FRAMES; i++ )
418 set_fixmap(FIX_GNTTAB_END - i, frames[i] << PAGE_SHIFT);
420 return 0;
421 }
423 int
424 gnttab_suspend(void)
425 {
426 int i;
428 for ( i = 0; i < NR_GRANT_FRAMES; i++ )
429 clear_fixmap(FIX_GNTTAB_END - i);
431 return 0;
432 }
434 static int __init
435 gnttab_init(void)
436 {
437 int i;
439 BUG_ON(gnttab_resume());
441 shared = (grant_entry_t *)fix_to_virt(FIX_GNTTAB_END);
443 for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
444 gnttab_list[i] = i + 1;
446 #ifdef CONFIG_PROC_FS
447 /*
448 * /proc/xen/grant : used by libxc to access grant tables
449 */
450 if ( (grant_pde = create_xen_proc_entry("grant", 0600)) == NULL )
451 {
452 WPRINTK("Unable to create grant xen proc entry\n");
453 return -1;
454 }
456 grant_file_ops.read = grant_pde->proc_fops->read;
457 grant_file_ops.write = grant_pde->proc_fops->write;
459 grant_pde->proc_fops = &grant_file_ops;
461 grant_pde->read_proc = &grant_read;
462 grant_pde->write_proc = &grant_write;
463 #endif
465 printk("Grant table initialized\n");
466 return 0;
467 }
469 __initcall(gnttab_init);