1 /******************************************************************************
4 * Granting foreign access to our memory reservation.
6 * Copyright (c) 2005, Christopher Clark
7 * Copyright (c) 2004-2005, K A Fraser
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation; or, when distributed
12 * separately from the Linux kernel or incorporated into other
13 * software packages, subject to the following license:
15 * Permission is hereby granted, free of charge, to any person obtaining a copy
16 * of this source file (the "Software"), to deal in the Software without
17 * restriction, including without limitation the rights to use, copy, modify,
18 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
19 * and to permit persons to whom the Software is furnished to do so, subject to
20 * the following conditions:
22 * The above copyright notice and this permission notice shall be included in
23 * all copies or substantial portions of the Software.
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
34 #include <linux/module.h>
35 #include <linux/sched.h>
37 #include <linux/vmalloc.h>
38 #include <xen/interface/xen.h>
39 #include <xen/gnttab.h>
40 #include <asm/pgtable.h>
41 #include <asm/uaccess.h>
42 #include <asm/synch_bitops.h>
44 #include <xen/interface/memory.h>
46 /* External tools reserve first few grant table entries. */
47 #define NR_RESERVED_ENTRIES 8
49 #define NR_GRANT_ENTRIES \
50 (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(struct grant_entry))
51 #define GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1)
53 static grant_ref_t gnttab_list[NR_GRANT_ENTRIES];
54 static int gnttab_free_count;
55 static grant_ref_t gnttab_free_head;
56 static DEFINE_SPINLOCK(gnttab_list_lock);
58 static struct grant_entry *shared;
60 static struct gnttab_free_callback *gnttab_free_callback_list;
62 static int get_free_entries(int count)
67 spin_lock_irqsave(&gnttab_list_lock, flags);
68 if (gnttab_free_count < count) {
69 spin_unlock_irqrestore(&gnttab_list_lock, flags);
72 ref = head = gnttab_free_head;
73 gnttab_free_count -= count;
75 head = gnttab_list[head];
76 gnttab_free_head = gnttab_list[head];
77 gnttab_list[head] = GNTTAB_LIST_END;
78 spin_unlock_irqrestore(&gnttab_list_lock, flags);
82 #define get_free_entry() get_free_entries(1)
84 static void do_free_callbacks(void)
86 struct gnttab_free_callback *callback, *next;
88 callback = gnttab_free_callback_list;
89 gnttab_free_callback_list = NULL;
91 while (callback != NULL) {
92 next = callback->next;
93 if (gnttab_free_count >= callback->count) {
94 callback->next = NULL;
95 callback->fn(callback->arg);
97 callback->next = gnttab_free_callback_list;
98 gnttab_free_callback_list = callback;
104 static inline void check_free_callbacks(void)
106 if (unlikely(gnttab_free_callback_list))
110 static void put_free_entry(grant_ref_t ref)
113 spin_lock_irqsave(&gnttab_list_lock, flags);
114 gnttab_list[ref] = gnttab_free_head;
115 gnttab_free_head = ref;
117 check_free_callbacks();
118 spin_unlock_irqrestore(&gnttab_list_lock, flags);
122 * Public grant-issuing interface functions
125 int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
130 if (unlikely((ref = get_free_entry()) == -1))
133 shared[ref].frame = frame;
134 shared[ref].domid = domid;
136 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
140 EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
142 void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
143 unsigned long frame, int readonly)
145 shared[ref].frame = frame;
146 shared[ref].domid = domid;
148 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
150 EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
153 int gnttab_query_foreign_access(grant_ref_t ref)
157 nflags = shared[ref].flags;
159 return (nflags & (GTF_reading|GTF_writing));
161 EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
163 int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
167 nflags = shared[ref].flags;
169 if ((flags = nflags) & (GTF_reading|GTF_writing)) {
170 printk(KERN_ALERT "WARNING: g.e. still in use!\n");
173 } while ((nflags = synch_cmpxchg_subword(&shared[ref].flags, flags, 0)) !=
178 EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
180 void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
183 if (gnttab_end_foreign_access_ref(ref, readonly)) {
188 /* XXX This needs to be fixed so that the ref and page are
189 placed on a list to be freed up later. */
191 "WARNING: leaking g.e. and page still in use!\n");
194 EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
196 int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
200 if (unlikely((ref = get_free_entry()) == -1))
202 gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
206 EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
208 void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
211 shared[ref].frame = pfn;
212 shared[ref].domid = domid;
214 shared[ref].flags = GTF_accept_transfer;
216 EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
218 unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
224 * If a transfer is not even yet started, try to reclaim the grant
225 * reference and return failure (== 0).
227 while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
228 if (synch_cmpxchg_subword(&shared[ref].flags, flags, 0) == flags)
233 /* If a transfer is in progress then wait until it is completed. */
234 while (!(flags & GTF_transfer_completed)) {
235 flags = shared[ref].flags;
239 /* Read the frame number /after/ reading completion status. */
241 frame = shared[ref].frame;
246 EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
248 unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
250 unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
254 EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
256 void gnttab_free_grant_reference(grant_ref_t ref)
260 EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
262 void gnttab_free_grant_references(grant_ref_t head)
267 if (head == GNTTAB_LIST_END)
269 spin_lock_irqsave(&gnttab_list_lock, flags);
271 while (gnttab_list[ref] != GNTTAB_LIST_END) {
272 ref = gnttab_list[ref];
275 gnttab_list[ref] = gnttab_free_head;
276 gnttab_free_head = head;
277 gnttab_free_count += count;
278 check_free_callbacks();
279 spin_unlock_irqrestore(&gnttab_list_lock, flags);
281 EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
283 int gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
285 int h = get_free_entries(count);
294 EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
296 int gnttab_empty_grant_references(const grant_ref_t *private_head)
298 return (*private_head == GNTTAB_LIST_END);
300 EXPORT_SYMBOL_GPL(gnttab_empty_grant_references);
302 int gnttab_claim_grant_reference(grant_ref_t *private_head)
304 grant_ref_t g = *private_head;
305 if (unlikely(g == GNTTAB_LIST_END))
307 *private_head = gnttab_list[g];
310 EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
312 void gnttab_release_grant_reference(grant_ref_t *private_head,
315 gnttab_list[release] = *private_head;
316 *private_head = release;
318 EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
320 void gnttab_request_free_callback(struct gnttab_free_callback *callback,
321 void (*fn)(void *), void *arg, u16 count)
324 spin_lock_irqsave(&gnttab_list_lock, flags);
329 callback->count = count;
330 callback->next = gnttab_free_callback_list;
331 gnttab_free_callback_list = callback;
332 check_free_callbacks();
334 spin_unlock_irqrestore(&gnttab_list_lock, flags);
336 EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
338 void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
340 struct gnttab_free_callback **pcb;
343 spin_lock_irqsave(&gnttab_list_lock, flags);
344 for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
345 if (*pcb == callback) {
346 *pcb = callback->next;
350 spin_unlock_irqrestore(&gnttab_list_lock, flags);
352 EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
357 static int map_pte_fn(pte_t *pte, struct page *pmd_page,
358 unsigned long addr, void *data)
360 unsigned long **frames = (unsigned long **)data;
362 set_pte_at(&init_mm, addr, pte, pfn_pte_ma((*frames)[0], PAGE_KERNEL));
367 static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
368 unsigned long addr, void *data)
371 set_pte_at(&init_mm, addr, pte, __pte(0));
376 int gnttab_resume(void)
378 struct gnttab_setup_table setup;
379 unsigned long frames[NR_GRANT_FRAMES];
382 void *pframes = frames;
383 struct vm_struct *area;
386 setup.dom = DOMID_SELF;
387 setup.nr_frames = NR_GRANT_FRAMES;
388 set_xen_guest_handle(setup.frame_list, frames);
390 rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
394 BUG_ON(rc || setup.status);
397 if (shared == NULL) {
398 area = get_vm_area(PAGE_SIZE * NR_GRANT_FRAMES, VM_IOREMAP);
399 BUG_ON(area == NULL);
402 rc = apply_to_page_range(&init_mm, (unsigned long)shared,
403 PAGE_SIZE * NR_GRANT_FRAMES,
404 map_pte_fn, &pframes);
407 shared = __va(frames[0] << PAGE_SHIFT);
408 printk("grant table at %p\n", shared);
414 int gnttab_suspend(void)
417 apply_to_page_range(&init_mm, (unsigned long)shared,
418 PAGE_SIZE * NR_GRANT_FRAMES,
424 #else /* !CONFIG_XEN */
426 #include <platform-pci.h>
428 int gnttab_resume(void)
430 unsigned long frames;
431 struct xen_add_to_physmap xatp;
434 frames = alloc_xen_mmio(PAGE_SIZE * NR_GRANT_FRAMES);
436 for (i = 0; i < NR_GRANT_FRAMES; i++) {
437 xatp.domid = DOMID_SELF;
439 xatp.space = XENMAPSPACE_grant_table;
440 xatp.gpfn = (frames >> PAGE_SHIFT) + i;
441 if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
445 shared = ioremap(frames, PAGE_SIZE * NR_GRANT_FRAMES);
446 if (shared == NULL) {
447 printk("error to ioremap gnttab share frames\n");
454 int gnttab_suspend(void)
460 #endif /* !CONFIG_XEN */
462 int __init gnttab_init(void)
466 if (!is_running_on_xen())
469 if (gnttab_resume() < 0)
472 for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++)
473 gnttab_list[i] = i + 1;
474 gnttab_free_count = NR_GRANT_ENTRIES - NR_RESERVED_ENTRIES;
475 gnttab_free_head = NR_RESERVED_ENTRIES;
477 printk("Grant table initialized\n");
482 core_initcall(gnttab_init);