1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#include <linux/module.h>
35#include <linux/sched.h>
36#include <linux/mm.h>
37#include <linux/slab.h>
38#include <linux/vmalloc.h>
39#include <linux/uaccess.h>
40#include <linux/io.h>
41
42#include <xen/xen.h>
43#include <xen/interface/xen.h>
44#include <xen/page.h>
45#include <xen/grant_table.h>
46#include <xen/interface/memory.h>
47#include <xen/hvc-console.h>
48#include <asm/xen/hypercall.h>
49
50#include <asm/pgtable.h>
51#include <asm/sync_bitops.h>
52
53
54#define NR_RESERVED_ENTRIES 8
55#define GNTTAB_LIST_END 0xffffffff
56#define GREFS_PER_GRANT_FRAME \
57(grant_table_version == 1 ? \
58(PAGE_SIZE / sizeof(struct grant_entry_v1)) : \
59(PAGE_SIZE / sizeof(union grant_entry_v2)))
60
61static grant_ref_t **gnttab_list;
62static unsigned int nr_grant_frames;
63static unsigned int boot_max_nr_grant_frames;
64static int gnttab_free_count;
65static grant_ref_t gnttab_free_head;
66static DEFINE_SPINLOCK(gnttab_list_lock);
67unsigned long xen_hvm_resume_frames;
68EXPORT_SYMBOL_GPL(xen_hvm_resume_frames);
69
70static union {
71 struct grant_entry_v1 *v1;
72 union grant_entry_v2 *v2;
73 void *addr;
74} gnttab_shared;
75
76
77struct gnttab_ops {
78
79
80
81
82
83
84 int (*map_frames)(unsigned long *frames, unsigned int nr_gframes);
85
86
87
88
89 void (*unmap_frames)(void);
90
91
92
93
94
95
96
97 void (*update_entry)(grant_ref_t ref, domid_t domid,
98 unsigned long frame, unsigned flags);
99
100
101
102
103
104
105
106
107 int (*end_foreign_access_ref)(grant_ref_t ref, int readonly);
108
109
110
111
112
113
114
115 unsigned long (*end_foreign_transfer_ref)(grant_ref_t ref);
116
117
118
119
120
121
122 int (*query_foreign_access)(grant_ref_t ref);
123
124
125
126
127
128
129
130
131 void (*update_subpage_entry)(grant_ref_t ref, domid_t domid,
132 unsigned long frame, int flags,
133 unsigned page_off, unsigned length);
134
135
136
137
138
139
140
141
142
143
144 void (*update_trans_entry)(grant_ref_t ref, domid_t domid, int flags,
145 domid_t trans_domid, grant_ref_t trans_gref);
146};
147
148static struct gnttab_ops *gnttab_interface;
149
150
151static grant_status_t *grstatus;
152
153static int grant_table_version;
154
155static struct gnttab_free_callback *gnttab_free_callback_list;
156
157static int gnttab_expand(unsigned int req_entries);
158
159#define RPP (PAGE_SIZE / sizeof(grant_ref_t))
160#define SPP (PAGE_SIZE / sizeof(grant_status_t))
161
162static inline grant_ref_t *__gnttab_entry(grant_ref_t entry)
163{
164 return &gnttab_list[(entry) / RPP][(entry) % RPP];
165}
166
167#define gnttab_entry(entry) (*__gnttab_entry(entry))
168
169static int get_free_entries(unsigned count)
170{
171 unsigned long flags;
172 int ref, rc = 0;
173 grant_ref_t head;
174
175 spin_lock_irqsave(&gnttab_list_lock, flags);
176
177 if ((gnttab_free_count < count) &&
178 ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
179 spin_unlock_irqrestore(&gnttab_list_lock, flags);
180 return rc;
181 }
182
183 ref = head = gnttab_free_head;
184 gnttab_free_count -= count;
185 while (count-- > 1)
186 head = gnttab_entry(head);
187 gnttab_free_head = gnttab_entry(head);
188 gnttab_entry(head) = GNTTAB_LIST_END;
189
190 spin_unlock_irqrestore(&gnttab_list_lock, flags);
191
192 return ref;
193}
194
195static void do_free_callbacks(void)
196{
197 struct gnttab_free_callback *callback, *next;
198
199 callback = gnttab_free_callback_list;
200 gnttab_free_callback_list = NULL;
201
202 while (callback != NULL) {
203 next = callback->next;
204 if (gnttab_free_count >= callback->count) {
205 callback->next = NULL;
206 callback->fn(callback->arg);
207 } else {
208 callback->next = gnttab_free_callback_list;
209 gnttab_free_callback_list = callback;
210 }
211 callback = next;
212 }
213}
214
215static inline void check_free_callbacks(void)
216{
217 if (unlikely(gnttab_free_callback_list))
218 do_free_callbacks();
219}
220
221static void put_free_entry(grant_ref_t ref)
222{
223 unsigned long flags;
224 spin_lock_irqsave(&gnttab_list_lock, flags);
225 gnttab_entry(ref) = gnttab_free_head;
226 gnttab_free_head = ref;
227 gnttab_free_count++;
228 check_free_callbacks();
229 spin_unlock_irqrestore(&gnttab_list_lock, flags);
230}
231
232
233
234
235
236
237
238
239
240
241
242
243static void gnttab_update_entry_v1(grant_ref_t ref, domid_t domid,
244 unsigned long frame, unsigned flags)
245{
246 gnttab_shared.v1[ref].domid = domid;
247 gnttab_shared.v1[ref].frame = frame;
248 wmb();
249 gnttab_shared.v1[ref].flags = flags;
250}
251
252static void gnttab_update_entry_v2(grant_ref_t ref, domid_t domid,
253 unsigned long frame, unsigned flags)
254{
255 gnttab_shared.v2[ref].hdr.domid = domid;
256 gnttab_shared.v2[ref].full_page.frame = frame;
257 wmb();
258 gnttab_shared.v2[ref].hdr.flags = GTF_permit_access | flags;
259}
260
261
262
263
264void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
265 unsigned long frame, int readonly)
266{
267 gnttab_interface->update_entry(ref, domid, frame,
268 GTF_permit_access | (readonly ? GTF_readonly : 0));
269}
270EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
271
272int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
273 int readonly)
274{
275 int ref;
276
277 ref = get_free_entries(1);
278 if (unlikely(ref < 0))
279 return -ENOSPC;
280
281 gnttab_grant_foreign_access_ref(ref, domid, frame, readonly);
282
283 return ref;
284}
285EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
286
287void gnttab_update_subpage_entry_v2(grant_ref_t ref, domid_t domid,
288 unsigned long frame, int flags,
289 unsigned page_off,
290 unsigned length)
291{
292 gnttab_shared.v2[ref].sub_page.frame = frame;
293 gnttab_shared.v2[ref].sub_page.page_off = page_off;
294 gnttab_shared.v2[ref].sub_page.length = length;
295 gnttab_shared.v2[ref].hdr.domid = domid;
296 wmb();
297 gnttab_shared.v2[ref].hdr.flags =
298 GTF_permit_access | GTF_sub_page | flags;
299}
300
301int gnttab_grant_foreign_access_subpage_ref(grant_ref_t ref, domid_t domid,
302 unsigned long frame, int flags,
303 unsigned page_off,
304 unsigned length)
305{
306 if (flags & (GTF_accept_transfer | GTF_reading |
307 GTF_writing | GTF_transitive))
308 return -EPERM;
309
310 if (gnttab_interface->update_subpage_entry == NULL)
311 return -ENOSYS;
312
313 gnttab_interface->update_subpage_entry(ref, domid, frame, flags,
314 page_off, length);
315
316 return 0;
317}
318EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_subpage_ref);
319
320int gnttab_grant_foreign_access_subpage(domid_t domid, unsigned long frame,
321 int flags, unsigned page_off,
322 unsigned length)
323{
324 int ref, rc;
325
326 ref = get_free_entries(1);
327 if (unlikely(ref < 0))
328 return -ENOSPC;
329
330 rc = gnttab_grant_foreign_access_subpage_ref(ref, domid, frame, flags,
331 page_off, length);
332 if (rc < 0) {
333 put_free_entry(ref);
334 return rc;
335 }
336
337 return ref;
338}
339EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_subpage);
340
341bool gnttab_subpage_grants_available(void)
342{
343 return gnttab_interface->update_subpage_entry != NULL;
344}
345EXPORT_SYMBOL_GPL(gnttab_subpage_grants_available);
346
347void gnttab_update_trans_entry_v2(grant_ref_t ref, domid_t domid,
348 int flags, domid_t trans_domid,
349 grant_ref_t trans_gref)
350{
351 gnttab_shared.v2[ref].transitive.trans_domid = trans_domid;
352 gnttab_shared.v2[ref].transitive.gref = trans_gref;
353 gnttab_shared.v2[ref].hdr.domid = domid;
354 wmb();
355 gnttab_shared.v2[ref].hdr.flags =
356 GTF_permit_access | GTF_transitive | flags;
357}
358
359int gnttab_grant_foreign_access_trans_ref(grant_ref_t ref, domid_t domid,
360 int flags, domid_t trans_domid,
361 grant_ref_t trans_gref)
362{
363 if (flags & (GTF_accept_transfer | GTF_reading |
364 GTF_writing | GTF_sub_page))
365 return -EPERM;
366
367 if (gnttab_interface->update_trans_entry == NULL)
368 return -ENOSYS;
369
370 gnttab_interface->update_trans_entry(ref, domid, flags, trans_domid,
371 trans_gref);
372
373 return 0;
374}
375EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_trans_ref);
376
377int gnttab_grant_foreign_access_trans(domid_t domid, int flags,
378 domid_t trans_domid,
379 grant_ref_t trans_gref)
380{
381 int ref, rc;
382
383 ref = get_free_entries(1);
384 if (unlikely(ref < 0))
385 return -ENOSPC;
386
387 rc = gnttab_grant_foreign_access_trans_ref(ref, domid, flags,
388 trans_domid, trans_gref);
389 if (rc < 0) {
390 put_free_entry(ref);
391 return rc;
392 }
393
394 return ref;
395}
396EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_trans);
397
398bool gnttab_trans_grants_available(void)
399{
400 return gnttab_interface->update_trans_entry != NULL;
401}
402EXPORT_SYMBOL_GPL(gnttab_trans_grants_available);
403
404static int gnttab_query_foreign_access_v1(grant_ref_t ref)
405{
406 return gnttab_shared.v1[ref].flags & (GTF_reading|GTF_writing);
407}
408
409static int gnttab_query_foreign_access_v2(grant_ref_t ref)
410{
411 return grstatus[ref] & (GTF_reading|GTF_writing);
412}
413
414int gnttab_query_foreign_access(grant_ref_t ref)
415{
416 return gnttab_interface->query_foreign_access(ref);
417}
418EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
419
420static int gnttab_end_foreign_access_ref_v1(grant_ref_t ref, int readonly)
421{
422 u16 flags, nflags;
423 u16 *pflags;
424
425 pflags = &gnttab_shared.v1[ref].flags;
426 nflags = *pflags;
427 do {
428 flags = nflags;
429 if (flags & (GTF_reading|GTF_writing)) {
430 printk(KERN_ALERT "WARNING: g.e. still in use!\n");
431 return 0;
432 }
433 } while ((nflags = sync_cmpxchg(pflags, flags, 0)) != flags);
434
435 return 1;
436}
437
438static int gnttab_end_foreign_access_ref_v2(grant_ref_t ref, int readonly)
439{
440 gnttab_shared.v2[ref].hdr.flags = 0;
441 mb();
442 if (grstatus[ref] & (GTF_reading|GTF_writing)) {
443 return 0;
444 } else {
445
446
447
448
449
450
451#ifdef CONFIG_X86
452 barrier();
453#else
454 mb();
455#endif
456 }
457
458 return 1;
459}
460
461int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
462{
463 return gnttab_interface->end_foreign_access_ref(ref, readonly);
464}
465EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
466
467void gnttab_end_foreign_access(grant_ref_t ref, int readonly,
468 unsigned long page)
469{
470 if (gnttab_end_foreign_access_ref(ref, readonly)) {
471 put_free_entry(ref);
472 if (page != 0)
473 free_page(page);
474 } else {
475
476
477 printk(KERN_WARNING
478 "WARNING: leaking g.e. and page still in use!\n");
479 }
480}
481EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
482
483int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
484{
485 int ref;
486
487 ref = get_free_entries(1);
488 if (unlikely(ref < 0))
489 return -ENOSPC;
490 gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
491
492 return ref;
493}
494EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
495
496void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
497 unsigned long pfn)
498{
499 gnttab_interface->update_entry(ref, domid, pfn, GTF_accept_transfer);
500}
501EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
502
503static unsigned long gnttab_end_foreign_transfer_ref_v1(grant_ref_t ref)
504{
505 unsigned long frame;
506 u16 flags;
507 u16 *pflags;
508
509 pflags = &gnttab_shared.v1[ref].flags;
510
511
512
513
514
515 while (!((flags = *pflags) & GTF_transfer_committed)) {
516 if (sync_cmpxchg(pflags, flags, 0) == flags)
517 return 0;
518 cpu_relax();
519 }
520
521
522 while (!(flags & GTF_transfer_completed)) {
523 flags = *pflags;
524 cpu_relax();
525 }
526
527 rmb();
528 frame = gnttab_shared.v1[ref].frame;
529 BUG_ON(frame == 0);
530
531 return frame;
532}
533
534static unsigned long gnttab_end_foreign_transfer_ref_v2(grant_ref_t ref)
535{
536 unsigned long frame;
537 u16 flags;
538 u16 *pflags;
539
540 pflags = &gnttab_shared.v2[ref].hdr.flags;
541
542
543
544
545
546 while (!((flags = *pflags) & GTF_transfer_committed)) {
547 if (sync_cmpxchg(pflags, flags, 0) == flags)
548 return 0;
549 cpu_relax();
550 }
551
552
553 while (!(flags & GTF_transfer_completed)) {
554 flags = *pflags;
555 cpu_relax();
556 }
557
558 rmb();
559 frame = gnttab_shared.v2[ref].full_page.frame;
560 BUG_ON(frame == 0);
561
562 return frame;
563}
564
565unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
566{
567 return gnttab_interface->end_foreign_transfer_ref(ref);
568}
569EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
570
571unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
572{
573 unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
574 put_free_entry(ref);
575 return frame;
576}
577EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
578
579void gnttab_free_grant_reference(grant_ref_t ref)
580{
581 put_free_entry(ref);
582}
583EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
584
585void gnttab_free_grant_references(grant_ref_t head)
586{
587 grant_ref_t ref;
588 unsigned long flags;
589 int count = 1;
590 if (head == GNTTAB_LIST_END)
591 return;
592 spin_lock_irqsave(&gnttab_list_lock, flags);
593 ref = head;
594 while (gnttab_entry(ref) != GNTTAB_LIST_END) {
595 ref = gnttab_entry(ref);
596 count++;
597 }
598 gnttab_entry(ref) = gnttab_free_head;
599 gnttab_free_head = head;
600 gnttab_free_count += count;
601 check_free_callbacks();
602 spin_unlock_irqrestore(&gnttab_list_lock, flags);
603}
604EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
605
606int gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
607{
608 int h = get_free_entries(count);
609
610 if (h < 0)
611 return -ENOSPC;
612
613 *head = h;
614
615 return 0;
616}
617EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
618
619int gnttab_empty_grant_references(const grant_ref_t *private_head)
620{
621 return (*private_head == GNTTAB_LIST_END);
622}
623EXPORT_SYMBOL_GPL(gnttab_empty_grant_references);
624
625int gnttab_claim_grant_reference(grant_ref_t *private_head)
626{
627 grant_ref_t g = *private_head;
628 if (unlikely(g == GNTTAB_LIST_END))
629 return -ENOSPC;
630 *private_head = gnttab_entry(g);
631 return g;
632}
633EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
634
635void gnttab_release_grant_reference(grant_ref_t *private_head,
636 grant_ref_t release)
637{
638 gnttab_entry(release) = *private_head;
639 *private_head = release;
640}
641EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
642
643void gnttab_request_free_callback(struct gnttab_free_callback *callback,
644 void (*fn)(void *), void *arg, u16 count)
645{
646 unsigned long flags;
647 spin_lock_irqsave(&gnttab_list_lock, flags);
648 if (callback->next)
649 goto out;
650 callback->fn = fn;
651 callback->arg = arg;
652 callback->count = count;
653 callback->next = gnttab_free_callback_list;
654 gnttab_free_callback_list = callback;
655 check_free_callbacks();
656out:
657 spin_unlock_irqrestore(&gnttab_list_lock, flags);
658}
659EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
660
661void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
662{
663 struct gnttab_free_callback **pcb;
664 unsigned long flags;
665
666 spin_lock_irqsave(&gnttab_list_lock, flags);
667 for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
668 if (*pcb == callback) {
669 *pcb = callback->next;
670 break;
671 }
672 }
673 spin_unlock_irqrestore(&gnttab_list_lock, flags);
674}
675EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
676
677static int grow_gnttab_list(unsigned int more_frames)
678{
679 unsigned int new_nr_grant_frames, extra_entries, i;
680 unsigned int nr_glist_frames, new_nr_glist_frames;
681
682 new_nr_grant_frames = nr_grant_frames + more_frames;
683 extra_entries = more_frames * GREFS_PER_GRANT_FRAME;
684
685 nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP;
686 new_nr_glist_frames =
687 (new_nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP;
688 for (i = nr_glist_frames; i < new_nr_glist_frames; i++) {
689 gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
690 if (!gnttab_list[i])
691 goto grow_nomem;
692 }
693
694
695 for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames;
696 i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
697 gnttab_entry(i) = i + 1;
698
699 gnttab_entry(i) = gnttab_free_head;
700 gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames;
701 gnttab_free_count += extra_entries;
702
703 nr_grant_frames = new_nr_grant_frames;
704
705 check_free_callbacks();
706
707 return 0;
708
709grow_nomem:
710 for ( ; i >= nr_glist_frames; i--)
711 free_page((unsigned long) gnttab_list[i]);
712 return -ENOMEM;
713}
714
715static unsigned int __max_nr_grant_frames(void)
716{
717 struct gnttab_query_size query;
718 int rc;
719
720 query.dom = DOMID_SELF;
721
722 rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
723 if ((rc < 0) || (query.status != GNTST_okay))
724 return 4;
725
726 return query.max_nr_frames;
727}
728
729unsigned int gnttab_max_grant_frames(void)
730{
731 unsigned int xen_max = __max_nr_grant_frames();
732
733 if (xen_max > boot_max_nr_grant_frames)
734 return boot_max_nr_grant_frames;
735 return xen_max;
736}
737EXPORT_SYMBOL_GPL(gnttab_max_grant_frames);
738
739int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
740 struct gnttab_map_grant_ref *kmap_ops,
741 struct page **pages, unsigned int count)
742{
743 int i, ret;
744 pte_t *pte;
745 unsigned long mfn;
746
747 ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map_ops, count);
748 if (ret)
749 return ret;
750
751 if (xen_feature(XENFEAT_auto_translated_physmap))
752 return ret;
753
754 for (i = 0; i < count; i++) {
755
756 if (map_ops[i].status)
757 continue;
758
759 if (map_ops[i].flags & GNTMAP_contains_pte) {
760 pte = (pte_t *) (mfn_to_virt(PFN_DOWN(map_ops[i].host_addr)) +
761 (map_ops[i].host_addr & ~PAGE_MASK));
762 mfn = pte_mfn(*pte);
763 } else {
764 mfn = PFN_DOWN(map_ops[i].dev_bus_addr);
765 }
766 ret = m2p_add_override(mfn, pages[i], kmap_ops ?
767 &kmap_ops[i] : NULL);
768 if (ret)
769 return ret;
770 }
771
772 return ret;
773}
774EXPORT_SYMBOL_GPL(gnttab_map_refs);
775
776int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
777 struct page **pages, unsigned int count, bool clear_pte)
778{
779 int i, ret;
780
781 ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap_ops, count);
782 if (ret)
783 return ret;
784
785 if (xen_feature(XENFEAT_auto_translated_physmap))
786 return ret;
787
788 for (i = 0; i < count; i++) {
789 ret = m2p_remove_override(pages[i], clear_pte);
790 if (ret)
791 return ret;
792 }
793
794 return ret;
795}
796EXPORT_SYMBOL_GPL(gnttab_unmap_refs);
797
798static unsigned nr_status_frames(unsigned nr_grant_frames)
799{
800 return (nr_grant_frames * GREFS_PER_GRANT_FRAME + SPP - 1) / SPP;
801}
802
803static int gnttab_map_frames_v1(unsigned long *frames, unsigned int nr_gframes)
804{
805 int rc;
806
807 rc = arch_gnttab_map_shared(frames, nr_gframes,
808 gnttab_max_grant_frames(),
809 &gnttab_shared.addr);
810 BUG_ON(rc);
811
812 return 0;
813}
814
815static void gnttab_unmap_frames_v1(void)
816{
817 arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames);
818}
819
820static int gnttab_map_frames_v2(unsigned long *frames, unsigned int nr_gframes)
821{
822 uint64_t *sframes;
823 unsigned int nr_sframes;
824 struct gnttab_get_status_frames getframes;
825 int rc;
826
827 nr_sframes = nr_status_frames(nr_gframes);
828
829
830
831
832 sframes = kmalloc(nr_sframes * sizeof(uint64_t), GFP_ATOMIC);
833 if (!sframes)
834 return -ENOMEM;
835
836 getframes.dom = DOMID_SELF;
837 getframes.nr_frames = nr_sframes;
838 set_xen_guest_handle(getframes.frame_list, sframes);
839
840 rc = HYPERVISOR_grant_table_op(GNTTABOP_get_status_frames,
841 &getframes, 1);
842 if (rc == -ENOSYS) {
843 kfree(sframes);
844 return -ENOSYS;
845 }
846
847 BUG_ON(rc || getframes.status);
848
849 rc = arch_gnttab_map_status(sframes, nr_sframes,
850 nr_status_frames(gnttab_max_grant_frames()),
851 &grstatus);
852 BUG_ON(rc);
853 kfree(sframes);
854
855 rc = arch_gnttab_map_shared(frames, nr_gframes,
856 gnttab_max_grant_frames(),
857 &gnttab_shared.addr);
858 BUG_ON(rc);
859
860 return 0;
861}
862
863static void gnttab_unmap_frames_v2(void)
864{
865 arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames);
866 arch_gnttab_unmap(grstatus, nr_status_frames(nr_grant_frames));
867}
868
869static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
870{
871 struct gnttab_setup_table setup;
872 unsigned long *frames;
873 unsigned int nr_gframes = end_idx + 1;
874 int rc;
875
876 if (xen_hvm_domain()) {
877 struct xen_add_to_physmap xatp;
878 unsigned int i = end_idx;
879 rc = 0;
880
881
882
883
884 do {
885 xatp.domid = DOMID_SELF;
886 xatp.idx = i;
887 xatp.space = XENMAPSPACE_grant_table;
888 xatp.gpfn = (xen_hvm_resume_frames >> PAGE_SHIFT) + i;
889 rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp);
890 if (rc != 0) {
891 printk(KERN_WARNING
892 "grant table add_to_physmap failed, err=%d\n", rc);
893 break;
894 }
895 } while (i-- > start_idx);
896
897 return rc;
898 }
899
900
901
902
903 frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
904 if (!frames)
905 return -ENOMEM;
906
907 setup.dom = DOMID_SELF;
908 setup.nr_frames = nr_gframes;
909 set_xen_guest_handle(setup.frame_list, frames);
910
911 rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
912 if (rc == -ENOSYS) {
913 kfree(frames);
914 return -ENOSYS;
915 }
916
917 BUG_ON(rc || setup.status);
918
919 rc = gnttab_interface->map_frames(frames, nr_gframes);
920
921 kfree(frames);
922
923 return rc;
924}
925
926static struct gnttab_ops gnttab_v1_ops = {
927 .map_frames = gnttab_map_frames_v1,
928 .unmap_frames = gnttab_unmap_frames_v1,
929 .update_entry = gnttab_update_entry_v1,
930 .end_foreign_access_ref = gnttab_end_foreign_access_ref_v1,
931 .end_foreign_transfer_ref = gnttab_end_foreign_transfer_ref_v1,
932 .query_foreign_access = gnttab_query_foreign_access_v1,
933};
934
935static struct gnttab_ops gnttab_v2_ops = {
936 .map_frames = gnttab_map_frames_v2,
937 .unmap_frames = gnttab_unmap_frames_v2,
938 .update_entry = gnttab_update_entry_v2,
939 .end_foreign_access_ref = gnttab_end_foreign_access_ref_v2,
940 .end_foreign_transfer_ref = gnttab_end_foreign_transfer_ref_v2,
941 .query_foreign_access = gnttab_query_foreign_access_v2,
942 .update_subpage_entry = gnttab_update_subpage_entry_v2,
943 .update_trans_entry = gnttab_update_trans_entry_v2,
944};
945
946static void gnttab_request_version(void)
947{
948 int rc;
949 struct gnttab_set_version gsv;
950
951 if (xen_hvm_domain())
952 gsv.version = 1;
953 else
954 gsv.version = 2;
955 rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gsv, 1);
956 if (rc == 0 && gsv.version == 2) {
957 grant_table_version = 2;
958 gnttab_interface = &gnttab_v2_ops;
959 } else if (grant_table_version == 2) {
960
961
962
963
964
965
966
967 panic("we need grant tables version 2, but only version 1 is available");
968 } else {
969 grant_table_version = 1;
970 gnttab_interface = &gnttab_v1_ops;
971 }
972 printk(KERN_INFO "Grant tables using version %d layout.\n",
973 grant_table_version);
974}
975
976int gnttab_resume(void)
977{
978 unsigned int max_nr_gframes;
979
980 gnttab_request_version();
981 max_nr_gframes = gnttab_max_grant_frames();
982 if (max_nr_gframes < nr_grant_frames)
983 return -ENOSYS;
984
985 if (xen_pv_domain())
986 return gnttab_map(0, nr_grant_frames - 1);
987
988 if (gnttab_shared.addr == NULL) {
989 gnttab_shared.addr = ioremap(xen_hvm_resume_frames,
990 PAGE_SIZE * max_nr_gframes);
991 if (gnttab_shared.addr == NULL) {
992 printk(KERN_WARNING
993 "Failed to ioremap gnttab share frames!");
994 return -ENOMEM;
995 }
996 }
997
998 gnttab_map(0, nr_grant_frames - 1);
999
1000 return 0;
1001}
1002
1003int gnttab_suspend(void)
1004{
1005 gnttab_interface->unmap_frames();
1006 return 0;
1007}
1008
1009static int gnttab_expand(unsigned int req_entries)
1010{
1011 int rc;
1012 unsigned int cur, extra;
1013
1014 cur = nr_grant_frames;
1015 extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) /
1016 GREFS_PER_GRANT_FRAME);
1017 if (cur + extra > gnttab_max_grant_frames())
1018 return -ENOSPC;
1019
1020 rc = gnttab_map(cur, cur + extra - 1);
1021 if (rc == 0)
1022 rc = grow_gnttab_list(extra);
1023
1024 return rc;
1025}
1026
1027int gnttab_init(void)
1028{
1029 int i;
1030 unsigned int max_nr_glist_frames, nr_glist_frames;
1031 unsigned int nr_init_grefs;
1032 int ret;
1033
1034 nr_grant_frames = 1;
1035 boot_max_nr_grant_frames = __max_nr_grant_frames();
1036
1037
1038
1039
1040 max_nr_glist_frames = (boot_max_nr_grant_frames *
1041 GREFS_PER_GRANT_FRAME / RPP);
1042
1043 gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
1044 GFP_KERNEL);
1045 if (gnttab_list == NULL)
1046 return -ENOMEM;
1047
1048 nr_glist_frames = (nr_grant_frames * GREFS_PER_GRANT_FRAME + RPP - 1) / RPP;
1049 for (i = 0; i < nr_glist_frames; i++) {
1050 gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
1051 if (gnttab_list[i] == NULL) {
1052 ret = -ENOMEM;
1053 goto ini_nomem;
1054 }
1055 }
1056
1057 if (gnttab_resume() < 0) {
1058 ret = -ENODEV;
1059 goto ini_nomem;
1060 }
1061
1062 nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME;
1063
1064 for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
1065 gnttab_entry(i) = i + 1;
1066
1067 gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
1068 gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
1069 gnttab_free_head = NR_RESERVED_ENTRIES;
1070
1071 printk("Grant table initialized\n");
1072 return 0;
1073
1074 ini_nomem:
1075 for (i--; i >= 0; i--)
1076 free_page((unsigned long)gnttab_list[i]);
1077 kfree(gnttab_list);
1078 return ret;
1079}
1080EXPORT_SYMBOL_GPL(gnttab_init);
1081
1082static int __devinit __gnttab_init(void)
1083{
1084
1085 if (xen_hvm_domain())
1086 return 0;
1087
1088 if (!xen_pv_domain())
1089 return -ENODEV;
1090
1091 return gnttab_init();
1092}
1093
1094core_initcall(__gnttab_init);
1095