xen-vtx-unstable

annotate linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c @ 6347:4956ea5b1e34

Add EXPORT_SYMBOL for gnttab_free_grant_reference.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Tue Aug 23 09:25:46 2005 +0000 (2005-08-23)
parents 96f1f6c71089
children 5b1ed5b39451
rev   line source
cl349@4693 1 /******************************************************************************
cl349@4693 2 * gnttab.c
cl349@4693 3 *
cl349@4693 4 * Two sets of functionality:
cl349@4693 5 * 1. Granting foreign access to our memory reservation.
cl349@4693 6 * 2. Accessing others' memory reservations via grant references.
cl349@4693 7 * (i.e., mechanisms for both sender and recipient of grant references)
cl349@4693 8 *
cl349@4693 9 * Copyright (c) 2005, Christopher Clark
cl349@4693 10 * Copyright (c) 2004, K A Fraser
cl349@4693 11 */
cl349@4693 12
cl349@4693 13 #include <linux/config.h>
cl349@4693 14 #include <linux/module.h>
cl349@4693 15 #include <linux/sched.h>
cl349@4693 16 #include <asm/pgtable.h>
cl349@4693 17 #include <asm/fixmap.h>
cl349@4693 18 #include <asm/uaccess.h>
cl349@4693 19 #include <asm-xen/xen_proc.h>
cl349@4693 20 #include <asm-xen/linux-public/privcmd.h>
cl349@4693 21 #include <asm-xen/gnttab.h>
kaf24@5402 22 #include <asm-xen/synch_bitops.h>
cl349@4693 23
cl349@4693 24 #if 1
cl349@4693 25 #define ASSERT(_p) \
cl349@4693 26 if ( !(_p) ) { printk(KERN_ALERT"Assertion '%s': line %d, file %s\n", \
cl349@4693 27 #_p , __LINE__, __FILE__); *(int*)0=0; }
cl349@4693 28 #else
cl349@4693 29 #define ASSERT(_p) ((void)0)
cl349@4693 30 #endif
cl349@4693 31
cl349@4693 32 #define WPRINTK(fmt, args...) \
cl349@4693 33 printk(KERN_WARNING "xen_grant: " fmt, ##args)
cl349@4693 34
cl349@4693 35
cl349@4693 36 EXPORT_SYMBOL(gnttab_grant_foreign_access);
cl349@4693 37 EXPORT_SYMBOL(gnttab_end_foreign_access);
cl349@4693 38 EXPORT_SYMBOL(gnttab_query_foreign_access);
cl349@4693 39 EXPORT_SYMBOL(gnttab_grant_foreign_transfer);
cl349@4693 40 EXPORT_SYMBOL(gnttab_end_foreign_transfer);
cl349@4693 41 EXPORT_SYMBOL(gnttab_alloc_grant_references);
cl349@4693 42 EXPORT_SYMBOL(gnttab_free_grant_references);
cl349@6347 43 EXPORT_SYMBOL(gnttab_free_grant_reference);
cl349@4693 44 EXPORT_SYMBOL(gnttab_claim_grant_reference);
cl349@4693 45 EXPORT_SYMBOL(gnttab_release_grant_reference);
cl349@4693 46 EXPORT_SYMBOL(gnttab_grant_foreign_access_ref);
cl349@4693 47 EXPORT_SYMBOL(gnttab_grant_foreign_transfer_ref);
cl349@4693 48
cl349@4693 49 static grant_ref_t gnttab_free_list[NR_GRANT_ENTRIES];
cl349@4693 50 static grant_ref_t gnttab_free_head;
cl349@4693 51
cl349@4693 52 static grant_entry_t *shared;
cl349@4693 53
cl349@6339 54 static struct gnttab_free_callback *gnttab_free_callback_list = NULL;
cl349@6345 55 static spinlock_t gnttab_free_callback_list_lock = SPIN_LOCK_UNLOCKED;
cl349@6339 56
cl349@4693 57 /*
cl349@4693 58 * Lock-free grant-entry allocator
cl349@4693 59 */
cl349@4693 60
cl349@4693 61 static inline int
cl349@4693 62 get_free_entry(
cl349@4693 63 void)
cl349@4693 64 {
cl349@4693 65 grant_ref_t fh, nfh = gnttab_free_head;
cl349@4693 66 do { if ( unlikely((fh = nfh) == NR_GRANT_ENTRIES) ) return -1; }
cl349@4693 67 while ( unlikely((nfh = cmpxchg(&gnttab_free_head, fh,
cl349@4693 68 gnttab_free_list[fh])) != fh) );
cl349@4693 69 return fh;
cl349@4693 70 }
cl349@4693 71
cl349@6346 72 static void do_free_callbacks(unsigned long flags)
cl349@6339 73 {
cl349@6346 74 struct gnttab_free_callback *callback = gnttab_free_callback_list, *next;
cl349@6339 75 gnttab_free_callback_list = NULL;
cl349@6346 76 spin_unlock_irqrestore(&gnttab_free_callback_list_lock, flags);
cl349@6339 77 while (callback) {
cl349@6342 78 next = callback->next;
cl349@6342 79 callback->next = NULL;
cl349@6342 80 callback->fn(callback->arg);
cl349@6342 81 callback = next;
cl349@6339 82 }
cl349@6339 83 }
cl349@6339 84
cl349@4693 85 static inline void
cl349@4693 86 put_free_entry(
cl349@4693 87 grant_ref_t ref)
cl349@4693 88 {
cl349@4693 89 grant_ref_t fh, nfh = gnttab_free_head;
cl349@6346 90 unsigned long flags;
cl349@4693 91 do { gnttab_free_list[ref] = fh = nfh; wmb(); }
cl349@4693 92 while ( unlikely((nfh = cmpxchg(&gnttab_free_head, fh, ref)) != fh) );
cl349@6346 93 spin_lock_irqsave(&gnttab_free_callback_list_lock, flags);
cl349@6339 94 if ( unlikely(gnttab_free_callback_list) )
cl349@6346 95 do_free_callbacks(flags);
cl349@6346 96 else
cl349@6346 97 spin_unlock_irqrestore(&gnttab_free_callback_list_lock, flags);
cl349@4693 98 }
cl349@4693 99
cl349@4693 100 /*
cl349@4693 101 * Public grant-issuing interface functions
cl349@4693 102 */
cl349@4693 103
cl349@4693 104 int
cl349@4693 105 gnttab_grant_foreign_access(
cl349@4693 106 domid_t domid, unsigned long frame, int readonly)
cl349@4693 107 {
cl349@4693 108 int ref;
cl349@4693 109
cl349@4693 110 if ( unlikely((ref = get_free_entry()) == -1) )
cl349@4693 111 return -ENOSPC;
cl349@4693 112
cl349@4693 113 shared[ref].frame = frame;
cl349@4693 114 shared[ref].domid = domid;
cl349@4693 115 wmb();
cl349@4693 116 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
cl349@4693 117
cl349@4693 118 return ref;
cl349@4693 119 }
cl349@4693 120
cl349@4693 121 void
cl349@4693 122 gnttab_grant_foreign_access_ref(
cl349@4693 123 grant_ref_t ref, domid_t domid, unsigned long frame, int readonly)
cl349@4693 124 {
cl349@4693 125 shared[ref].frame = frame;
cl349@4693 126 shared[ref].domid = domid;
cl349@4693 127 wmb();
cl349@4693 128 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
cl349@4693 129 }
cl349@4693 130
cl349@4693 131
cl349@4693 132 int
cl349@4693 133 gnttab_query_foreign_access( grant_ref_t ref )
cl349@4693 134 {
cl349@4693 135 u16 nflags;
cl349@4693 136
cl349@4693 137 nflags = shared[ref].flags;
cl349@4693 138
cl349@4693 139 return ( nflags & (GTF_reading|GTF_writing) );
cl349@4693 140 }
cl349@4693 141
cl349@4693 142 void
cl349@4693 143 gnttab_end_foreign_access( grant_ref_t ref, int readonly )
cl349@4693 144 {
cl349@4693 145 u16 flags, nflags;
cl349@4693 146
cl349@4693 147 nflags = shared[ref].flags;
cl349@4693 148 do {
cl349@4693 149 if ( (flags = nflags) & (GTF_reading|GTF_writing) )
cl349@4693 150 printk(KERN_ALERT "WARNING: g.e. still in use!\n");
cl349@4693 151 }
sos22@5391 152 while ( (nflags = synch_cmpxchg(&shared[ref].flags, flags, 0)) != flags );
cl349@4693 153
cl349@4693 154 put_free_entry(ref);
cl349@4693 155 }
cl349@4693 156
cl349@4693 157 int
cl349@4693 158 gnttab_grant_foreign_transfer(
cl349@4693 159 domid_t domid, unsigned long pfn )
cl349@4693 160 {
cl349@4693 161 int ref;
cl349@4693 162
cl349@4693 163 if ( unlikely((ref = get_free_entry()) == -1) )
cl349@4693 164 return -ENOSPC;
cl349@4693 165
cl349@4693 166 shared[ref].frame = pfn;
cl349@4693 167 shared[ref].domid = domid;
cl349@4693 168 wmb();
cl349@4693 169 shared[ref].flags = GTF_accept_transfer;
cl349@4693 170
cl349@4693 171 return ref;
cl349@4693 172 }
cl349@4693 173
cl349@4693 174 void
cl349@4693 175 gnttab_grant_foreign_transfer_ref(
cl349@4693 176 grant_ref_t ref, domid_t domid, unsigned long pfn )
cl349@4693 177 {
cl349@4693 178 shared[ref].frame = pfn;
cl349@4693 179 shared[ref].domid = domid;
cl349@4693 180 wmb();
cl349@4693 181 shared[ref].flags = GTF_accept_transfer;
cl349@4693 182 }
cl349@4693 183
cl349@4693 184 unsigned long
cl349@4693 185 gnttab_end_foreign_transfer(
cl349@4693 186 grant_ref_t ref)
cl349@4693 187 {
cl349@4693 188 unsigned long frame = 0;
cl349@4693 189 u16 flags;
cl349@4693 190
cl349@4693 191 flags = shared[ref].flags;
vh249@5828 192 #ifdef CONFIG_XEN_NETDEV_GRANT_RX
vh249@5828 193 /*
vh249@5828 194 * But can't flags == (GTF_accept_transfer | GTF_transfer_completed)
vh249@5828 195 * if gnttab_donate executes without interruption???
vh249@5828 196 */
vh249@5828 197 #else
cl349@4693 198 ASSERT(flags == (GTF_accept_transfer | GTF_transfer_committed));
vh249@5828 199 #endif
cl349@4693 200 /*
cl349@4693 201 * If a transfer is committed then wait for the frame address to appear.
cl349@4693 202 * Otherwise invalidate the grant entry against future use.
cl349@4693 203 */
cl349@4693 204 if ( likely(flags != GTF_accept_transfer) ||
sos22@5391 205 (synch_cmpxchg(&shared[ref].flags, flags, 0) != GTF_accept_transfer) )
cl349@4693 206 while ( unlikely((frame = shared[ref].frame) == 0) )
cl349@4693 207 cpu_relax();
cl349@4693 208
cl349@4693 209 put_free_entry(ref);
cl349@4693 210
cl349@4693 211 return frame;
cl349@4693 212 }
cl349@4693 213
cl349@4693 214 void
cl349@6339 215 gnttab_free_grant_reference( grant_ref_t ref )
cl349@6339 216 {
cl349@6339 217
cl349@6339 218 put_free_entry(ref);
cl349@6339 219 }
cl349@6339 220
cl349@6339 221 void
cl349@6339 222 gnttab_free_grant_references( grant_ref_t *head,
cl349@6339 223 grant_ref_t terminal )
cl349@4693 224 {
cl349@4693 225 /* TODO: O(N)...? */
cl349@6339 226 grant_ref_t ref;
cl349@4693 227
cl349@6339 228 while (*head != terminal) {
cl349@6339 229 ref = *head;
cl349@6339 230 *head = gnttab_free_list[*head];
cl349@6339 231 put_free_entry(ref);
vh249@5272 232 }
cl349@4693 233 }
cl349@4693 234
cl349@4693 235 int
cl349@4693 236 gnttab_alloc_grant_references( u16 count,
cl349@4693 237 grant_ref_t *head,
cl349@4693 238 grant_ref_t *terminal )
cl349@4693 239 {
cl349@4693 240 int i;
cl349@4693 241 grant_ref_t h = gnttab_free_head;
cl349@4693 242
cl349@4693 243 for ( i = 0; i < count; i++ )
cl349@4693 244 if ( unlikely(get_free_entry() == -1) )
cl349@4693 245 goto not_enough_refs;
cl349@4693 246
cl349@4693 247 *head = h;
cl349@4693 248 *terminal = gnttab_free_head;
cl349@4693 249
cl349@4693 250 return 0;
cl349@4693 251
cl349@4693 252 not_enough_refs:
cl349@4693 253 gnttab_free_head = h;
cl349@4693 254 return -ENOSPC;
cl349@4693 255 }
cl349@4693 256
cl349@4693 257 int
cl349@4693 258 gnttab_claim_grant_reference( grant_ref_t *private_head,
cl349@4693 259 grant_ref_t terminal )
cl349@4693 260 {
cl349@4693 261 grant_ref_t g;
cl349@4693 262 if ( unlikely((g = *private_head) == terminal) )
cl349@4693 263 return -ENOSPC;
cl349@4693 264 *private_head = gnttab_free_list[g];
cl349@4693 265 return g;
cl349@4693 266 }
cl349@4693 267
cl349@4693 268 void
cl349@4693 269 gnttab_release_grant_reference( grant_ref_t *private_head,
cl349@4693 270 grant_ref_t release )
cl349@4693 271 {
cl349@4693 272 gnttab_free_list[release] = *private_head;
cl349@4693 273 *private_head = release;
cl349@4693 274 }
cl349@4693 275
cl349@6339 276 void
cl349@6339 277 gnttab_request_free_callback(struct gnttab_free_callback *callback,
cl349@6342 278 void (*fn)(void *), void *arg)
cl349@6339 279 {
cl349@6346 280 unsigned long flags;
cl349@6342 281 if (callback->next)
cl349@6342 282 return;
cl349@6342 283 callback->fn = fn;
cl349@6342 284 callback->arg = arg;
cl349@6346 285 spin_lock_irqsave(&gnttab_free_callback_list_lock, flags);
cl349@6339 286 callback->next = gnttab_free_callback_list;
cl349@6339 287 gnttab_free_callback_list = callback;
cl349@6346 288 spin_unlock_irqrestore(&gnttab_free_callback_list_lock, flags);
cl349@6339 289 }
cl349@6339 290
cl349@4693 291 /*
cl349@4693 292 * ProcFS operations
cl349@4693 293 */
cl349@4693 294
cl349@4693 295 #ifdef CONFIG_PROC_FS
cl349@4693 296
cl349@4693 297 static struct proc_dir_entry *grant_pde;
cl349@4693 298
cl349@4693 299 static int grant_ioctl(struct inode *inode, struct file *file,
cl349@4693 300 unsigned int cmd, unsigned long data)
cl349@4693 301 {
cl349@4693 302 int ret;
cl349@4693 303 privcmd_hypercall_t hypercall;
cl349@4693 304
cl349@4693 305 /* XXX Need safety checks here if using for anything other
cl349@4693 306 * than debugging */
cl349@4693 307 return -ENOSYS;
cl349@4693 308
cl349@4693 309 if ( cmd != IOCTL_PRIVCMD_HYPERCALL )
cl349@4693 310 return -ENOSYS;
cl349@4693 311
cl349@4693 312 if ( copy_from_user(&hypercall, (void *)data, sizeof(hypercall)) )
cl349@4693 313 return -EFAULT;
cl349@4693 314
cl349@4693 315 if ( hypercall.op != __HYPERVISOR_grant_table_op )
cl349@4693 316 return -ENOSYS;
cl349@4693 317
cl349@4693 318 /* hypercall-invoking asm taken from privcmd.c */
cl349@4693 319 __asm__ __volatile__ (
cl349@4693 320 "pushl %%ebx; pushl %%ecx; pushl %%edx; pushl %%esi; pushl %%edi; "
cl349@4693 321 "movl 4(%%eax),%%ebx ;"
cl349@4693 322 "movl 8(%%eax),%%ecx ;"
cl349@4693 323 "movl 12(%%eax),%%edx ;"
cl349@4693 324 "movl 16(%%eax),%%esi ;"
cl349@4693 325 "movl 20(%%eax),%%edi ;"
cl349@4693 326 "movl (%%eax),%%eax ;"
cl349@4693 327 TRAP_INSTR "; "
cl349@4693 328 "popl %%edi; popl %%esi; popl %%edx; popl %%ecx; popl %%ebx"
cl349@4693 329 : "=a" (ret) : "0" (&hypercall) : "memory" );
cl349@4693 330
cl349@4693 331 return ret;
cl349@4693 332 }
cl349@4693 333
cl349@4693 334 static struct file_operations grant_file_ops = {
cl349@4693 335 ioctl: grant_ioctl,
cl349@4693 336 };
cl349@4693 337
cl349@4693 338 static int grant_read(char *page, char **start, off_t off,
cl349@4693 339 int count, int *eof, void *data)
cl349@4693 340 {
cl349@4693 341 int len;
cl349@4693 342 unsigned int i;
cl349@4693 343 grant_entry_t *gt;
cl349@4693 344
cl349@4693 345 gt = (grant_entry_t *)shared;
cl349@4693 346 len = 0;
cl349@4693 347
cl349@4693 348 for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
cl349@4693 349 /* TODO: safety catch here until this can handle >PAGE_SIZE output */
cl349@4693 350 if (len > (PAGE_SIZE - 200))
cl349@4693 351 {
cl349@4693 352 len += sprintf( page + len, "Truncated.\n");
cl349@4693 353 break;
cl349@4693 354 }
cl349@4693 355
cl349@4693 356 if ( gt[i].flags )
cl349@4693 357 len += sprintf( page + len,
cl349@4693 358 "Grant: ref (0x%x) flags (0x%hx) dom (0x%hx) frame (0x%x)\n",
cl349@4693 359 i,
cl349@4693 360 gt[i].flags,
cl349@4693 361 gt[i].domid,
cl349@4693 362 gt[i].frame );
cl349@4693 363
cl349@4693 364 *eof = 1;
cl349@4693 365 return len;
cl349@4693 366 }
cl349@4693 367
cl349@4693 368 static int grant_write(struct file *file, const char __user *buffer,
cl349@4693 369 unsigned long count, void *data)
cl349@4693 370 {
cl349@4693 371 /* TODO: implement this */
cl349@4693 372 return -ENOSYS;
cl349@4693 373 }
cl349@4693 374
cl349@4693 375 #endif /* CONFIG_PROC_FS */
cl349@4693 376
cl349@4693 377 int gnttab_resume(void)
cl349@4693 378 {
cl349@4693 379 gnttab_setup_table_t setup;
cl349@4693 380 unsigned long frames[NR_GRANT_FRAMES];
cl349@4693 381 int i;
cl349@4693 382
cl349@4693 383 setup.dom = DOMID_SELF;
cl349@4693 384 setup.nr_frames = NR_GRANT_FRAMES;
cl349@4693 385 setup.frame_list = frames;
cl349@4693 386
cl349@4693 387 BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1) != 0);
cl349@4693 388 BUG_ON(setup.status != 0);
cl349@4693 389
cl349@4693 390 for ( i = 0; i < NR_GRANT_FRAMES; i++ )
cl349@4777 391 set_fixmap(FIX_GNTTAB_END - i, frames[i] << PAGE_SHIFT);
cl349@4693 392
cl349@4693 393 return 0;
cl349@4693 394 }
cl349@4693 395
cl349@4693 396 int gnttab_suspend(void)
cl349@4693 397 {
cl349@4693 398 int i;
cl349@4693 399
cl349@4693 400 for ( i = 0; i < NR_GRANT_FRAMES; i++ )
cl349@4693 401 clear_fixmap(FIX_GNTTAB_END - i);
cl349@4693 402
cl349@4693 403 return 0;
cl349@4693 404 }
cl349@4693 405
cl349@4693 406 static int __init gnttab_init(void)
cl349@4693 407 {
cl349@4693 408 int i;
cl349@4693 409
cl349@4693 410 BUG_ON(gnttab_resume());
cl349@4693 411
cl349@4693 412 shared = (grant_entry_t *)fix_to_virt(FIX_GNTTAB_END);
cl349@4693 413
cl349@4693 414 for ( i = 0; i < NR_GRANT_ENTRIES; i++ )
cl349@4693 415 gnttab_free_list[i] = i + 1;
cl349@4693 416
cl349@4693 417 #ifdef CONFIG_PROC_FS
cl349@4693 418 /*
cl349@4693 419 * /proc/xen/grant : used by libxc to access grant tables
cl349@4693 420 */
cl349@4693 421 if ( (grant_pde = create_xen_proc_entry("grant", 0600)) == NULL )
cl349@4693 422 {
cl349@4693 423 WPRINTK("Unable to create grant xen proc entry\n");
cl349@4693 424 return -1;
cl349@4693 425 }
cl349@4693 426
cl349@4693 427 grant_file_ops.read = grant_pde->proc_fops->read;
cl349@4693 428 grant_file_ops.write = grant_pde->proc_fops->write;
cl349@4693 429
cl349@4693 430 grant_pde->proc_fops = &grant_file_ops;
cl349@4693 431
cl349@4693 432 grant_pde->read_proc = &grant_read;
cl349@4693 433 grant_pde->write_proc = &grant_write;
cl349@4693 434 #endif
cl349@4693 435
cl349@4693 436 printk("Grant table initialized\n");
cl349@4693 437 return 0;
cl349@4693 438 }
cl349@4693 439
cl349@4693 440 __initcall(gnttab_init);