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/config.h>
35 #include <linux/module.h>
36 #include <linux/sched.h>
38 #include <linux/vmalloc.h>
39 #include <xen/interface/xen.h>
40 #include <xen/gnttab.h>
41 #include <asm/pgtable.h>
42 #include <asm/uaccess.h>
43 #include <asm/synch_bitops.h>
45 /* External tools reserve first few grant table entries. */
46 #define NR_RESERVED_ENTRIES 8
48 #define NR_GRANT_ENTRIES \
49 (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(struct grant_entry))
50 #define GNTTAB_LIST_END (NR_GRANT_ENTRIES + 1)
52 static grant_ref_t gnttab_list[NR_GRANT_ENTRIES];
53 static int gnttab_free_count;
54 static grant_ref_t gnttab_free_head;
55 static DEFINE_SPINLOCK(gnttab_list_lock);
57 static struct grant_entry *shared;
59 static struct gnttab_free_callback *gnttab_free_callback_list;
61 static int get_free_entries(int count)
66 spin_lock_irqsave(&gnttab_list_lock, flags);
67 if (gnttab_free_count < count) {
68 spin_unlock_irqrestore(&gnttab_list_lock, flags);
71 ref = head = gnttab_free_head;
72 gnttab_free_count -= count;
74 head = gnttab_list[head];
75 gnttab_free_head = gnttab_list[head];
76 gnttab_list[head] = GNTTAB_LIST_END;
77 spin_unlock_irqrestore(&gnttab_list_lock, flags);
81 #define get_free_entry() get_free_entries(1)
83 static void do_free_callbacks(void)
85 struct gnttab_free_callback *callback, *next;
87 callback = gnttab_free_callback_list;
88 gnttab_free_callback_list = NULL;
90 while (callback != NULL) {
91 next = callback->next;
92 if (gnttab_free_count >= callback->count) {
93 callback->next = NULL;
94 callback->fn(callback->arg);
96 callback->next = gnttab_free_callback_list;
97 gnttab_free_callback_list = callback;
103 static inline void check_free_callbacks(void)
105 if (unlikely(gnttab_free_callback_list))
109 static void put_free_entry(grant_ref_t ref)
112 spin_lock_irqsave(&gnttab_list_lock, flags);
113 gnttab_list[ref] = gnttab_free_head;
114 gnttab_free_head = ref;
116 check_free_callbacks();
117 spin_unlock_irqrestore(&gnttab_list_lock, flags);
121 * Public grant-issuing interface functions
124 int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
129 if (unlikely((ref = get_free_entry()) == -1))
132 shared[ref].frame = frame;
133 shared[ref].domid = domid;
135 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
139 EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
141 void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
142 unsigned long frame, int readonly)
144 shared[ref].frame = frame;
145 shared[ref].domid = domid;
147 shared[ref].flags = GTF_permit_access | (readonly ? GTF_readonly : 0);
149 EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
152 int gnttab_query_foreign_access(grant_ref_t ref)
156 nflags = shared[ref].flags;
158 return (nflags & (GTF_reading|GTF_writing));
160 EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
162 int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
166 nflags = shared[ref].flags;
168 if ((flags = nflags) & (GTF_reading|GTF_writing)) {
169 printk(KERN_ALERT "WARNING: g.e. still in use!\n");
172 } while ((nflags = synch_cmpxchg_subword(&shared[ref].flags, flags, 0)) !=
177 EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
179 void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
182 if (gnttab_end_foreign_access_ref(ref, readonly)) {
187 /* XXX This needs to be fixed so that the ref and page are
188 placed on a list to be freed up later. */
190 "WARNING: leaking g.e. and page still in use!\n");
193 EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
195 int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
199 if (unlikely((ref = get_free_entry()) == -1))
201 gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
205 EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
207 void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
210 shared[ref].frame = pfn;
211 shared[ref].domid = domid;
213 shared[ref].flags = GTF_accept_transfer;
215 EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
217 unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
223 * If a transfer is not even yet started, try to reclaim the grant
224 * reference and return failure (== 0).
226 while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
227 if (synch_cmpxchg_subword(&shared[ref].flags, flags, 0) == flags)
232 /* If a transfer is in progress then wait until it is completed. */
233 while (!(flags & GTF_transfer_completed)) {
234 flags = shared[ref].flags;
238 /* Read the frame number /after/ reading completion status. */
240 frame = shared[ref].frame;
245 EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
247 unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
249 unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
253 EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
255 void gnttab_free_grant_reference(grant_ref_t ref)
259 EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
261 void gnttab_free_grant_references(grant_ref_t head)
266 if (head == GNTTAB_LIST_END)
268 spin_lock_irqsave(&gnttab_list_lock, flags);
270 while (gnttab_list[ref] != GNTTAB_LIST_END) {
271 ref = gnttab_list[ref];
274 gnttab_list[ref] = gnttab_free_head;
275 gnttab_free_head = head;
276 gnttab_free_count += count;
277 check_free_callbacks();
278 spin_unlock_irqrestore(&gnttab_list_lock, flags);
280 EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
282 int gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
284 int h = get_free_entries(count);
293 EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
295 int gnttab_empty_grant_references(const grant_ref_t *private_head)
297 return (*private_head == GNTTAB_LIST_END);
299 EXPORT_SYMBOL_GPL(gnttab_empty_grant_references);
301 int gnttab_claim_grant_reference(grant_ref_t *private_head)
303 grant_ref_t g = *private_head;
304 if (unlikely(g == GNTTAB_LIST_END))
306 *private_head = gnttab_list[g];
309 EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
311 void gnttab_release_grant_reference(grant_ref_t *private_head,
314 gnttab_list[release] = *private_head;
315 *private_head = release;
317 EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
319 void gnttab_request_free_callback(struct gnttab_free_callback *callback,
320 void (*fn)(void *), void *arg, u16 count)
323 spin_lock_irqsave(&gnttab_list_lock, flags);
328 callback->count = count;
329 callback->next = gnttab_free_callback_list;
330 gnttab_free_callback_list = callback;
331 check_free_callbacks();
333 spin_unlock_irqrestore(&gnttab_list_lock, flags);
335 EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
337 void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
339 struct gnttab_free_callback **pcb;
342 spin_lock_irqsave(&gnttab_list_lock, flags);
343 for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
344 if (*pcb == callback) {
345 *pcb = callback->next;
349 spin_unlock_irqrestore(&gnttab_list_lock, flags);
351 EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
354 static int map_pte_fn(pte_t *pte, struct page *pmd_page,
355 unsigned long addr, void *data)
357 unsigned long **frames = (unsigned long **)data;
359 set_pte_at(&init_mm, addr, pte, pfn_pte_ma((*frames)[0], PAGE_KERNEL));
364 static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
365 unsigned long addr, void *data)
368 set_pte_at(&init_mm, addr, pte, __pte(0));
373 int gnttab_resume(void)
375 struct gnttab_setup_table setup;
376 unsigned long frames[NR_GRANT_FRAMES];
379 void *pframes = frames;
380 struct vm_struct *area;
383 setup.dom = DOMID_SELF;
384 setup.nr_frames = NR_GRANT_FRAMES;
385 set_xen_guest_handle(setup.frame_list, frames);
387 rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
391 BUG_ON(rc || setup.status);
394 if (shared == NULL) {
395 area = get_vm_area(PAGE_SIZE * NR_GRANT_FRAMES, VM_IOREMAP);
396 BUG_ON(area == NULL);
399 rc = apply_to_page_range(&init_mm, (unsigned long)shared,
400 PAGE_SIZE * NR_GRANT_FRAMES,
401 map_pte_fn, &pframes);
404 shared = __va(frames[0] << PAGE_SHIFT);
405 printk("grant table at %p\n", shared);
411 int gnttab_suspend(void)
415 apply_to_page_range(&init_mm, (unsigned long)shared,
416 PAGE_SIZE * NR_GRANT_FRAMES,
423 static int __init gnttab_init(void)
427 if (!is_running_on_xen())
430 if (gnttab_resume() < 0)
433 for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++)
434 gnttab_list[i] = i + 1;
435 gnttab_free_count = NR_GRANT_ENTRIES - NR_RESERVED_ENTRIES;
436 gnttab_free_head = NR_RESERVED_ENTRIES;
438 printk("Grant table initialized\n");
442 core_initcall(gnttab_init);