xen-vtx-unstable

annotate linux-2.6-xen-sparse/arch/xen/kernel/gnttab.c @ 6774:4d899a738d59

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