cl349@4693: /****************************************************************************** cl349@4693: * gnttab.c cl349@4693: * cl349@4693: * Two sets of functionality: cl349@4693: * 1. Granting foreign access to our memory reservation. cl349@4693: * 2. Accessing others' memory reservations via grant references. cl349@4693: * (i.e., mechanisms for both sender and recipient of grant references) cl349@4693: * cl349@4693: * Copyright (c) 2005, Christopher Clark cl349@4693: * Copyright (c) 2004, K A Fraser cl349@4693: */ cl349@4693: cl349@4693: #include cl349@4693: #include cl349@4693: #include cl349@4693: #include cl349@4693: #include cl349@4693: #include cl349@4693: #include cl349@4693: #include cl349@4693: #include kaf24@6760: #include cl349@4693: cl349@4693: #if 1 cl349@4693: #define ASSERT(_p) \ cl349@4693: if ( !(_p) ) { printk(KERN_ALERT"Assertion '%s': line %d, file %s\n", \ cl349@4693: #_p , __LINE__, __FILE__); *(int*)0=0; } cl349@4693: #else cl349@4693: #define ASSERT(_p) ((void)0) cl349@4693: #endif cl349@4693: cl349@4693: #define WPRINTK(fmt, args...) \ cl349@4693: printk(KERN_WARNING "xen_grant: " fmt, ##args) cl349@4693: cl349@4693: cl349@4693: EXPORT_SYMBOL(gnttab_grant_foreign_access); kaf24@6396: EXPORT_SYMBOL(gnttab_end_foreign_access_ref); cl349@4693: EXPORT_SYMBOL(gnttab_end_foreign_access); cl349@4693: EXPORT_SYMBOL(gnttab_query_foreign_access); cl349@4693: EXPORT_SYMBOL(gnttab_grant_foreign_transfer); kaf24@6396: EXPORT_SYMBOL(gnttab_end_foreign_transfer_ref); cl349@4693: EXPORT_SYMBOL(gnttab_end_foreign_transfer); cl349@4693: EXPORT_SYMBOL(gnttab_alloc_grant_references); cl349@4693: EXPORT_SYMBOL(gnttab_free_grant_references); cl349@6347: EXPORT_SYMBOL(gnttab_free_grant_reference); cl349@4693: EXPORT_SYMBOL(gnttab_claim_grant_reference); cl349@4693: EXPORT_SYMBOL(gnttab_release_grant_reference); cl349@4693: EXPORT_SYMBOL(gnttab_grant_foreign_access_ref); cl349@4693: EXPORT_SYMBOL(gnttab_grant_foreign_transfer_ref); cl349@4693: cl349@6349: #define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(grant_entry_t)) cl349@6349: #define GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1) cl349@6349: cl349@6349: static grant_ref_t gnttab_list[NR_GRANT_ENTRIES]; cl349@6349: static int gnttab_free_count = NR_GRANT_ENTRIES; cl349@4693: static grant_ref_t gnttab_free_head; cl349@6349: static spinlock_t gnttab_list_lock = SPIN_LOCK_UNLOCKED; cl349@4693: cl349@4693: static grant_entry_t *shared; cl349@4693: cl349@6339: static struct gnttab_free_callback *gnttab_free_callback_list = NULL; cl349@4693: cl349@6349: static int cl349@6349: get_free_entries(int count) cl349@4693: { cl349@6349: unsigned long flags; cl349@6349: int ref; cl349@6349: grant_ref_t head; cl349@6349: spin_lock_irqsave(&gnttab_list_lock, flags); cl349@6349: if (gnttab_free_count < count) { cl349@6349: spin_unlock_irqrestore(&gnttab_list_lock, flags); cl349@6349: return -1; cl349@6349: } cl349@6349: ref = head = gnttab_free_head; cl349@6349: gnttab_free_count -= count; cl349@6349: while (count-- > 1) cl349@6349: head = gnttab_list[head]; cl349@6349: gnttab_free_head = gnttab_list[head]; cl349@6349: gnttab_list[head] = GNTTAB_LIST_END; cl349@6349: spin_unlock_irqrestore(&gnttab_list_lock, flags); cl349@6349: return ref; cl349@4693: } cl349@4693: cl349@6349: #define get_free_entry() get_free_entries(1) cl349@6349: cl349@6349: static void cl349@6349: do_free_callbacks(void) cl349@6339: { cl349@6346: struct gnttab_free_callback *callback = gnttab_free_callback_list, *next; cl349@6339: gnttab_free_callback_list = NULL; cl349@6339: while (callback) { cl349@6342: next = callback->next; cl349@6349: if (gnttab_free_count >= callback->count) { cl349@6349: callback->next = NULL; cl349@6349: callback->fn(callback->arg); cl349@6349: } else { cl349@6349: callback->next = gnttab_free_callback_list; cl349@6349: gnttab_free_callback_list = callback; cl349@6349: } cl349@6342: callback = next; cl349@6339: } cl349@4693: } cl349@4693: cl349@4693: static inline void cl349@6349: check_free_callbacks(void) cl349@4693: { cl349@6349: if (unlikely(gnttab_free_callback_list)) cl349@6349: do_free_callbacks(); cl349@6349: } cl349@6349: cl349@6349: static void cl349@6349: put_free_entry(grant_ref_t ref) cl349@6349: { cl349@6346: unsigned long flags; cl349@6349: spin_lock_irqsave(&gnttab_list_lock, flags); cl349@6349: gnttab_list[ref] = gnttab_free_head; cl349@6349: gnttab_free_head = ref; cl349@6349: gnttab_free_count++; cl349@6349: check_free_callbacks(); cl349@6349: spin_unlock_irqrestore(&gnttab_list_lock, flags); cl349@4693: } cl349@4693: cl349@4693: /* cl349@4693: * Public grant-issuing interface functions cl349@4693: */ cl349@4693: cl349@4693: int cl349@6349: gnttab_grant_foreign_access(domid_t domid, unsigned long frame, int readonly) cl349@4693: { cl349@4693: int ref; cl349@4693: cl349@4693: if ( unlikely((ref = get_free_entry()) == -1) ) cl349@4693: return -ENOSPC; cl349@4693: cl349@4693: shared[ref].frame = frame; cl349@4693: shared[ref].domid = domid; cl349@4693: wmb(); cl349@4693: shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); cl349@4693: cl349@4693: return ref; cl349@4693: } cl349@4693: cl349@4693: void cl349@6349: gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid, cl349@6349: unsigned long frame, int readonly) cl349@4693: { cl349@4693: shared[ref].frame = frame; cl349@4693: shared[ref].domid = domid; cl349@4693: wmb(); cl349@4693: shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0); cl349@4693: } cl349@4693: cl349@4693: cl349@4693: int cl349@6349: gnttab_query_foreign_access(grant_ref_t ref) cl349@4693: { cl349@4693: u16 nflags; cl349@4693: cl349@4693: nflags = shared[ref].flags; cl349@4693: cl349@4693: return ( nflags & (GTF_reading|GTF_writing) ); cl349@4693: } cl349@4693: cl349@4693: void kaf24@6396: gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) cl349@4693: { cl349@4693: u16 flags, nflags; cl349@4693: cl349@4693: nflags = shared[ref].flags; cl349@4693: do { cl349@4693: if ( (flags = nflags) & (GTF_reading|GTF_writing) ) cl349@4693: printk(KERN_ALERT "WARNING: g.e. still in use!\n"); cl349@4693: } sos22@5391: while ( (nflags = synch_cmpxchg(&shared[ref].flags, flags, 0)) != flags ); kaf24@6396: } cl349@4693: kaf24@6396: void kaf24@6396: gnttab_end_foreign_access(grant_ref_t ref, int readonly) kaf24@6396: { kaf24@6396: gnttab_end_foreign_access_ref(ref, readonly); cl349@4693: put_free_entry(ref); cl349@4693: } cl349@4693: cl349@4693: int cl349@6349: gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn) cl349@4693: { cl349@4693: int ref; cl349@4693: cl349@4693: if ( unlikely((ref = get_free_entry()) == -1) ) cl349@4693: return -ENOSPC; cl349@4693: cl349@4693: shared[ref].frame = pfn; cl349@4693: shared[ref].domid = domid; cl349@4693: wmb(); cl349@4693: shared[ref].flags = GTF_accept_transfer; cl349@4693: cl349@4693: return ref; cl349@4693: } cl349@4693: cl349@4693: void cl349@6349: gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid, cl349@6349: unsigned long pfn) cl349@4693: { cl349@4693: shared[ref].frame = pfn; cl349@4693: shared[ref].domid = domid; cl349@4693: wmb(); cl349@4693: shared[ref].flags = GTF_accept_transfer; cl349@4693: } cl349@4693: cl349@4693: unsigned long kaf24@6396: gnttab_end_foreign_transfer_ref(grant_ref_t ref) cl349@4693: { cl349@4693: unsigned long frame = 0; cl349@4693: u16 flags; cl349@4693: cl349@4693: flags = shared[ref].flags; kaf24@6396: cl349@4693: /* cl349@4693: * If a transfer is committed then wait for the frame address to appear. cl349@4693: * Otherwise invalidate the grant entry against future use. cl349@4693: */ cl349@4693: if ( likely(flags != GTF_accept_transfer) || sos22@5391: (synch_cmpxchg(&shared[ref].flags, flags, 0) != GTF_accept_transfer) ) cl349@4693: while ( unlikely((frame = shared[ref].frame) == 0) ) cl349@4693: cpu_relax(); cl349@4693: kaf24@6396: return frame; kaf24@6396: } kaf24@6396: kaf24@6396: unsigned long kaf24@6396: gnttab_end_foreign_transfer(grant_ref_t ref) kaf24@6396: { kaf24@6396: unsigned long frame = gnttab_end_foreign_transfer_ref(ref); cl349@4693: put_free_entry(ref); cl349@4693: return frame; cl349@4693: } cl349@4693: cl349@4693: void cl349@6349: gnttab_free_grant_reference(grant_ref_t ref) cl349@4693: { cl349@6339: cl349@6339: put_free_entry(ref); cl349@6339: } cl349@4693: cl349@6339: void cl349@6349: gnttab_free_grant_references(grant_ref_t head) cl349@4693: { cl349@6339: grant_ref_t ref; cl349@6349: unsigned long flags; cl349@6349: int count = 1; cl349@6349: if (head == GNTTAB_LIST_END) cl349@6349: return; cl349@6349: spin_lock_irqsave(&gnttab_list_lock, flags); cl349@6349: ref = head; cl349@6349: while (gnttab_list[ref] != GNTTAB_LIST_END) { cl349@6349: ref = gnttab_list[ref]; cl349@6349: count++; vh249@5272: } cl349@6349: gnttab_list[ref] = gnttab_free_head; cl349@6349: gnttab_free_head = head; cl349@6349: gnttab_free_count += count; cl349@6349: check_free_callbacks(); cl349@6349: spin_unlock_irqrestore(&gnttab_list_lock, flags); cl349@4693: } cl349@4693: cl349@4693: int cl349@6349: gnttab_alloc_grant_references(u16 count, grant_ref_t *head) cl349@4693: { cl349@6349: int h = get_free_entries(count); cl349@4693: cl349@6349: if (h == -1) cl349@6349: return -ENOSPC; cl349@4693: cl349@4693: *head = h; cl349@4693: cl349@4693: return 0; cl349@4693: } cl349@4693: cl349@4693: int cl349@6349: gnttab_claim_grant_reference(grant_ref_t *private_head) cl349@4693: { cl349@6349: grant_ref_t g = *private_head; cl349@6349: if (unlikely(g == GNTTAB_LIST_END)) cl349@4693: return -ENOSPC; cl349@6349: *private_head = gnttab_list[g]; cl349@4693: return g; cl349@4693: } cl349@4693: cl349@4693: void cl349@6349: gnttab_release_grant_reference(grant_ref_t *private_head, grant_ref_t release) cl349@4693: { cl349@6349: gnttab_list[release] = *private_head; cl349@4693: *private_head = release; cl349@4693: } cl349@4693: cl349@6339: void cl349@6339: gnttab_request_free_callback(struct gnttab_free_callback *callback, cl349@6349: void (*fn)(void *), void *arg, u16 count) cl349@4693: { cl349@6346: unsigned long flags; cl349@6349: spin_lock_irqsave(&gnttab_list_lock, flags); cl349@6342: if (callback->next) cl349@6349: goto out; cl349@6342: callback->fn = fn; cl349@6342: callback->arg = arg; cl349@6349: callback->count = count; cl349@6339: callback->next = gnttab_free_callback_list; cl349@6339: gnttab_free_callback_list = callback; cl349@6349: check_free_callbacks(); cl349@6349: out: cl349@6349: spin_unlock_irqrestore(&gnttab_list_lock, flags); cl349@4693: } cl349@4693: cl349@4693: /* cl349@4693: * ProcFS operations cl349@4693: */ cl349@4693: cl349@4693: #ifdef CONFIG_PROC_FS cl349@4693: cl349@4693: static struct proc_dir_entry *grant_pde; cl349@4693: cl349@6349: static int cl349@6349: grant_ioctl(struct inode *inode, struct file *file, unsigned int cmd, cl349@6349: unsigned long data) cl349@4693: { cl349@4693: int ret; cl349@4693: privcmd_hypercall_t hypercall; cl349@4693: cl349@4693: /* XXX Need safety checks here if using for anything other cl349@4693: * than debugging */ cl349@4693: return -ENOSYS; cl349@4693: cl349@4693: if ( cmd != IOCTL_PRIVCMD_HYPERCALL ) cl349@4693: return -ENOSYS; cl349@4693: cl349@4693: if ( copy_from_user(&hypercall, (void *)data, sizeof(hypercall)) ) cl349@4693: return -EFAULT; cl349@4693: cl349@4693: if ( hypercall.op != __HYPERVISOR_grant_table_op ) cl349@4693: return -ENOSYS; cl349@4693: cl349@4693: /* hypercall-invoking asm taken from privcmd.c */ cl349@4693: __asm__ __volatile__ ( cl349@4693: "pushl %%ebx; pushl %%ecx; pushl %%edx; pushl %%esi; pushl %%edi; " cl349@4693: "movl 4(%%eax),%%ebx ;" cl349@4693: "movl 8(%%eax),%%ecx ;" cl349@4693: "movl 12(%%eax),%%edx ;" cl349@4693: "movl 16(%%eax),%%esi ;" cl349@4693: "movl 20(%%eax),%%edi ;" cl349@4693: "movl (%%eax),%%eax ;" cl349@4693: TRAP_INSTR "; " cl349@4693: "popl %%edi; popl %%esi; popl %%edx; popl %%ecx; popl %%ebx" cl349@4693: : "=a" (ret) : "0" (&hypercall) : "memory" ); cl349@4693: cl349@4693: return ret; cl349@4693: } cl349@4693: cl349@4693: static struct file_operations grant_file_ops = { cl349@4693: ioctl: grant_ioctl, cl349@4693: }; cl349@4693: cl349@6349: static int cl349@6349: grant_read(char *page, char **start, off_t off, int count, int *eof, cl349@6349: void *data) cl349@4693: { cl349@4693: int len; cl349@4693: unsigned int i; cl349@4693: grant_entry_t *gt; cl349@4693: cl349@4693: gt = (grant_entry_t *)shared; cl349@4693: len = 0; cl349@4693: cl349@4693: for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) cl349@4693: /* TODO: safety catch here until this can handle >PAGE_SIZE output */ cl349@4693: if (len > (PAGE_SIZE - 200)) cl349@4693: { cl349@4693: len += sprintf( page + len, "Truncated.\n"); cl349@4693: break; cl349@4693: } cl349@4693: cl349@4693: if ( gt[i].flags ) cl349@4693: len += sprintf( page + len, cl349@4693: "Grant: ref (0x%x) flags (0x%hx) dom (0x%hx) frame (0x%x)\n", cl349@4693: i, cl349@4693: gt[i].flags, cl349@4693: gt[i].domid, cl349@4693: gt[i].frame ); cl349@4693: cl349@4693: *eof = 1; cl349@4693: return len; cl349@4693: } cl349@4693: cl349@6349: static int cl349@6349: grant_write(struct file *file, const char __user *buffer, unsigned long count, cl349@6349: void *data) cl349@4693: { cl349@4693: /* TODO: implement this */ cl349@4693: return -ENOSYS; cl349@4693: } cl349@4693: cl349@4693: #endif /* CONFIG_PROC_FS */ cl349@4693: cl349@6349: int cl349@6349: gnttab_resume(void) cl349@4693: { cl349@4693: gnttab_setup_table_t setup; cl349@4693: unsigned long frames[NR_GRANT_FRAMES]; cl349@4693: int i; cl349@4693: cl349@4693: setup.dom = DOMID_SELF; cl349@4693: setup.nr_frames = NR_GRANT_FRAMES; cl349@4693: setup.frame_list = frames; cl349@4693: cl349@4693: BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1) != 0); cl349@4693: BUG_ON(setup.status != 0); cl349@4693: cl349@4693: for ( i = 0; i < NR_GRANT_FRAMES; i++ ) cl349@4777: set_fixmap(FIX_GNTTAB_END - i, frames[i] << PAGE_SHIFT); cl349@4693: cl349@4693: return 0; cl349@4693: } cl349@4693: cl349@6349: int cl349@6349: gnttab_suspend(void) cl349@4693: { cl349@4693: int i; cl349@4693: cl349@4693: for ( i = 0; i < NR_GRANT_FRAMES; i++ ) cl349@4693: clear_fixmap(FIX_GNTTAB_END - i); cl349@4693: cl349@4693: return 0; cl349@4693: } cl349@4693: cl349@6349: static int __init cl349@6349: gnttab_init(void) cl349@4693: { cl349@4693: int i; cl349@4693: cl349@4693: BUG_ON(gnttab_resume()); cl349@4693: cl349@4693: shared = (grant_entry_t *)fix_to_virt(FIX_GNTTAB_END); cl349@4693: cl349@4693: for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) cl349@6349: gnttab_list[i] = i + 1; cl349@4693: cl349@4693: #ifdef CONFIG_PROC_FS cl349@4693: /* cl349@4693: * /proc/xen/grant : used by libxc to access grant tables cl349@4693: */ cl349@4693: if ( (grant_pde = create_xen_proc_entry("grant", 0600)) == NULL ) cl349@4693: { cl349@4693: WPRINTK("Unable to create grant xen proc entry\n"); cl349@4693: return -1; cl349@4693: } cl349@4693: cl349@4693: grant_file_ops.read = grant_pde->proc_fops->read; cl349@4693: grant_file_ops.write = grant_pde->proc_fops->write; cl349@4693: cl349@4693: grant_pde->proc_fops = &grant_file_ops; cl349@4693: cl349@4693: grant_pde->read_proc = &grant_read; cl349@4693: grant_pde->write_proc = &grant_write; cl349@4693: #endif cl349@4693: cl349@4693: printk("Grant table initialized\n"); cl349@4693: return 0; cl349@4693: } cl349@4693: cl349@4693: __initcall(gnttab_init);