aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/xen/grant-table.c39
-rw-r--r--drivers/xen/grant-table.c171
-rw-r--r--include/xen/grant_table.h6
3 files changed, 209 insertions, 7 deletions
diff --git a/arch/x86/xen/grant-table.c b/arch/x86/xen/grant-table.c
index c6ab2e7ca3a6..65160a8a0ba3 100644
--- a/arch/x86/xen/grant-table.c
+++ b/arch/x86/xen/grant-table.c
@@ -54,6 +54,20 @@ static int map_pte_fn(pte_t *pte, struct page *pmd_page,
54 return 0; 54 return 0;
55} 55}
56 56
57/*
58 * This function is used to map shared frames to store grant status. It is
59 * different from map_pte_fn above, the frames type here is uint64_t.
60 */
61static int map_pte_fn_status(pte_t *pte, struct page *pmd_page,
62 unsigned long addr, void *data)
63{
64 uint64_t **frames = (uint64_t **)data;
65
66 set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL));
67 (*frames)++;
68 return 0;
69}
70
57static int unmap_pte_fn(pte_t *pte, struct page *pmd_page, 71static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
58 unsigned long addr, void *data) 72 unsigned long addr, void *data)
59{ 73{
@@ -83,7 +97,30 @@ int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
83 return rc; 97 return rc;
84} 98}
85 99
86void arch_gnttab_unmap_shared(void *shared, unsigned long nr_gframes) 100int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes,
101 unsigned long max_nr_gframes,
102 grant_status_t **__shared)
103{
104 int rc;
105 grant_status_t *shared = *__shared;
106
107 if (shared == NULL) {
108 /* No need to pass in PTE as we are going to do it
109 * in apply_to_page_range anyhow. */
110 struct vm_struct *area =
111 alloc_vm_area(PAGE_SIZE * max_nr_gframes, NULL);
112 BUG_ON(area == NULL);
113 shared = area->addr;
114 *__shared = shared;
115 }
116
117 rc = apply_to_page_range(&init_mm, (unsigned long)shared,
118 PAGE_SIZE * nr_gframes,
119 map_pte_fn_status, &frames);
120 return rc;
121}
122
123void arch_gnttab_unmap(void *shared, unsigned long nr_gframes)
87{ 124{
88 apply_to_page_range(&init_mm, (unsigned long)shared, 125 apply_to_page_range(&init_mm, (unsigned long)shared,
89 PAGE_SIZE * nr_gframes, unmap_pte_fn, NULL); 126 PAGE_SIZE * nr_gframes, unmap_pte_fn, NULL);
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index 0518d0404942..301869f60dc7 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -44,6 +44,7 @@
44#include <xen/page.h> 44#include <xen/page.h>
45#include <xen/grant_table.h> 45#include <xen/grant_table.h>
46#include <xen/interface/memory.h> 46#include <xen/interface/memory.h>
47#include <xen/hvc-console.h>
47#include <asm/xen/hypercall.h> 48#include <asm/xen/hypercall.h>
48 49
49#include <asm/pgtable.h> 50#include <asm/pgtable.h>
@@ -53,7 +54,10 @@
53/* External tools reserve first few grant table entries. */ 54/* External tools reserve first few grant table entries. */
54#define NR_RESERVED_ENTRIES 8 55#define NR_RESERVED_ENTRIES 8
55#define GNTTAB_LIST_END 0xffffffff 56#define GNTTAB_LIST_END 0xffffffff
56#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(struct grant_entry_v1)) 57#define GREFS_PER_GRANT_FRAME \
58(grant_table_version == 1 ? \
59(PAGE_SIZE / sizeof(struct grant_entry_v1)) : \
60(PAGE_SIZE / sizeof(union grant_entry_v2)))
57 61
58static grant_ref_t **gnttab_list; 62static grant_ref_t **gnttab_list;
59static unsigned int nr_grant_frames; 63static unsigned int nr_grant_frames;
@@ -66,6 +70,7 @@ EXPORT_SYMBOL_GPL(xen_hvm_resume_frames);
66 70
67static union { 71static union {
68 struct grant_entry_v1 *v1; 72 struct grant_entry_v1 *v1;
73 union grant_entry_v2 *v2;
69 void *addr; 74 void *addr;
70} gnttab_shared; 75} gnttab_shared;
71 76
@@ -120,6 +125,9 @@ struct gnttab_ops {
120 125
121static struct gnttab_ops *gnttab_interface; 126static struct gnttab_ops *gnttab_interface;
122 127
128/*This reflects status of grant entries, so act as a global value*/
129static grant_status_t *grstatus;
130
123static int grant_table_version; 131static int grant_table_version;
124 132
125static struct gnttab_free_callback *gnttab_free_callback_list; 133static struct gnttab_free_callback *gnttab_free_callback_list;
@@ -127,6 +135,7 @@ static struct gnttab_free_callback *gnttab_free_callback_list;
127static int gnttab_expand(unsigned int req_entries); 135static int gnttab_expand(unsigned int req_entries);
128 136
129#define RPP (PAGE_SIZE / sizeof(grant_ref_t)) 137#define RPP (PAGE_SIZE / sizeof(grant_ref_t))
138#define SPP (PAGE_SIZE / sizeof(grant_status_t))
130 139
131static inline grant_ref_t *__gnttab_entry(grant_ref_t entry) 140static inline grant_ref_t *__gnttab_entry(grant_ref_t entry)
132{ 141{
@@ -199,6 +208,7 @@ static void put_free_entry(grant_ref_t ref)
199} 208}
200 209
201/* 210/*
211 * Following applies to gnttab_update_entry_v1 and gnttab_update_entry_v2.
202 * Introducing a valid entry into the grant table: 212 * Introducing a valid entry into the grant table:
203 * 1. Write ent->domid. 213 * 1. Write ent->domid.
204 * 2. Write ent->frame: 214 * 2. Write ent->frame:
@@ -217,6 +227,15 @@ static void gnttab_update_entry_v1(grant_ref_t ref, domid_t domid,
217 gnttab_shared.v1[ref].flags = flags; 227 gnttab_shared.v1[ref].flags = flags;
218} 228}
219 229
230static void gnttab_update_entry_v2(grant_ref_t ref, domid_t domid,
231 unsigned long frame, unsigned flags)
232{
233 gnttab_shared.v2[ref].hdr.domid = domid;
234 gnttab_shared.v2[ref].full_page.frame = frame;
235 wmb();
236 gnttab_shared.v2[ref].hdr.flags = GTF_permit_access | flags;
237}
238
220/* 239/*
221 * Public grant-issuing interface functions 240 * Public grant-issuing interface functions
222 */ 241 */
@@ -248,6 +267,11 @@ static int gnttab_query_foreign_access_v1(grant_ref_t ref)
248 return gnttab_shared.v1[ref].flags & (GTF_reading|GTF_writing); 267 return gnttab_shared.v1[ref].flags & (GTF_reading|GTF_writing);
249} 268}
250 269
270static int gnttab_query_foreign_access_v2(grant_ref_t ref)
271{
272 return grstatus[ref] & (GTF_reading|GTF_writing);
273}
274
251int gnttab_query_foreign_access(grant_ref_t ref) 275int gnttab_query_foreign_access(grant_ref_t ref)
252{ 276{
253 return gnttab_interface->query_foreign_access(ref); 277 return gnttab_interface->query_foreign_access(ref);
@@ -272,6 +296,29 @@ static int gnttab_end_foreign_access_ref_v1(grant_ref_t ref, int readonly)
272 return 1; 296 return 1;
273} 297}
274 298
299static int gnttab_end_foreign_access_ref_v2(grant_ref_t ref, int readonly)
300{
301 gnttab_shared.v2[ref].hdr.flags = 0;
302 mb();
303 if (grstatus[ref] & (GTF_reading|GTF_writing)) {
304 return 0;
305 } else {
306 /* The read of grstatus needs to have acquire
307 semantics. On x86, reads already have
308 that, and we just need to protect against
309 compiler reorderings. On other
310 architectures we may need a full
311 barrier. */
312#ifdef CONFIG_X86
313 barrier();
314#else
315 mb();
316#endif
317 }
318
319 return 1;
320}
321
275int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly) 322int gnttab_end_foreign_access_ref(grant_ref_t ref, int readonly)
276{ 323{
277 return gnttab_interface->end_foreign_access_ref(ref, readonly); 324 return gnttab_interface->end_foreign_access_ref(ref, readonly);
@@ -345,6 +392,37 @@ static unsigned long gnttab_end_foreign_transfer_ref_v1(grant_ref_t ref)
345 return frame; 392 return frame;
346} 393}
347 394
395static unsigned long gnttab_end_foreign_transfer_ref_v2(grant_ref_t ref)
396{
397 unsigned long frame;
398 u16 flags;
399 u16 *pflags;
400
401 pflags = &gnttab_shared.v2[ref].hdr.flags;
402
403 /*
404 * If a transfer is not even yet started, try to reclaim the grant
405 * reference and return failure (== 0).
406 */
407 while (!((flags = *pflags) & GTF_transfer_committed)) {
408 if (sync_cmpxchg(pflags, flags, 0) == flags)
409 return 0;
410 cpu_relax();
411 }
412
413 /* If a transfer is in progress then wait until it is completed. */
414 while (!(flags & GTF_transfer_completed)) {
415 flags = *pflags;
416 cpu_relax();
417 }
418
419 rmb(); /* Read the frame number /after/ reading completion status. */
420 frame = gnttab_shared.v2[ref].full_page.frame;
421 BUG_ON(frame == 0);
422
423 return frame;
424}
425
348unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref) 426unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
349{ 427{
350 return gnttab_interface->end_foreign_transfer_ref(ref); 428 return gnttab_interface->end_foreign_transfer_ref(ref);
@@ -592,6 +670,11 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
592} 670}
593EXPORT_SYMBOL_GPL(gnttab_unmap_refs); 671EXPORT_SYMBOL_GPL(gnttab_unmap_refs);
594 672
673static unsigned nr_status_frames(unsigned nr_grant_frames)
674{
675 return (nr_grant_frames * GREFS_PER_GRANT_FRAME + SPP - 1) / SPP;
676}
677
595static int gnttab_map_frames_v1(unsigned long *frames, unsigned int nr_gframes) 678static int gnttab_map_frames_v1(unsigned long *frames, unsigned int nr_gframes)
596{ 679{
597 int rc; 680 int rc;
@@ -606,7 +689,56 @@ static int gnttab_map_frames_v1(unsigned long *frames, unsigned int nr_gframes)
606 689
607static void gnttab_unmap_frames_v1(void) 690static void gnttab_unmap_frames_v1(void)
608{ 691{
609 arch_gnttab_unmap_shared(gnttab_shared.addr, nr_grant_frames); 692 arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames);
693}
694
695static int gnttab_map_frames_v2(unsigned long *frames, unsigned int nr_gframes)
696{
697 uint64_t *sframes;
698 unsigned int nr_sframes;
699 struct gnttab_get_status_frames getframes;
700 int rc;
701
702 nr_sframes = nr_status_frames(nr_gframes);
703
704 /* No need for kzalloc as it is initialized in following hypercall
705 * GNTTABOP_get_status_frames.
706 */
707 sframes = kmalloc(nr_sframes * sizeof(uint64_t), GFP_ATOMIC);
708 if (!sframes)
709 return -ENOMEM;
710
711 getframes.dom = DOMID_SELF;
712 getframes.nr_frames = nr_sframes;
713 set_xen_guest_handle(getframes.frame_list, sframes);
714
715 rc = HYPERVISOR_grant_table_op(GNTTABOP_get_status_frames,
716 &getframes, 1);
717 if (rc == -ENOSYS) {
718 kfree(sframes);
719 return -ENOSYS;
720 }
721
722 BUG_ON(rc || getframes.status);
723
724 rc = arch_gnttab_map_status(sframes, nr_sframes,
725 nr_status_frames(gnttab_max_grant_frames()),
726 &grstatus);
727 BUG_ON(rc);
728 kfree(sframes);
729
730 rc = arch_gnttab_map_shared(frames, nr_gframes,
731 gnttab_max_grant_frames(),
732 &gnttab_shared.addr);
733 BUG_ON(rc);
734
735 return 0;
736}
737
738static void gnttab_unmap_frames_v2(void)
739{
740 arch_gnttab_unmap(gnttab_shared.addr, nr_grant_frames);
741 arch_gnttab_unmap(grstatus, nr_status_frames(nr_grant_frames));
610} 742}
611 743
612static int gnttab_map(unsigned int start_idx, unsigned int end_idx) 744static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
@@ -640,6 +772,9 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
640 return rc; 772 return rc;
641 } 773 }
642 774
775 /* No need for kzalloc as it is initialized in following hypercall
776 * GNTTABOP_setup_table.
777 */
643 frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC); 778 frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
644 if (!frames) 779 if (!frames)
645 return -ENOMEM; 780 return -ENOMEM;
@@ -672,10 +807,38 @@ static struct gnttab_ops gnttab_v1_ops = {
672 .query_foreign_access = gnttab_query_foreign_access_v1, 807 .query_foreign_access = gnttab_query_foreign_access_v1,
673}; 808};
674 809
810static struct gnttab_ops gnttab_v2_ops = {
811 .map_frames = gnttab_map_frames_v2,
812 .unmap_frames = gnttab_unmap_frames_v2,
813 .update_entry = gnttab_update_entry_v2,
814 .end_foreign_access_ref = gnttab_end_foreign_access_ref_v2,
815 .end_foreign_transfer_ref = gnttab_end_foreign_transfer_ref_v2,
816 .query_foreign_access = gnttab_query_foreign_access_v2,
817};
818
675static void gnttab_request_version(void) 819static void gnttab_request_version(void)
676{ 820{
677 grant_table_version = 1; 821 int rc;
678 gnttab_interface = &gnttab_v1_ops; 822 struct gnttab_set_version gsv;
823
824 gsv.version = 2;
825 rc = HYPERVISOR_grant_table_op(GNTTABOP_set_version, &gsv, 1);
826 if (rc == 0) {
827 grant_table_version = 2;
828 gnttab_interface = &gnttab_v2_ops;
829 } else if (grant_table_version == 2) {
830 /*
831 * If we've already used version 2 features,
832 * but then suddenly discover that they're not
833 * available (e.g. migrating to an older
834 * version of Xen), almost unbounded badness
835 * can happen.
836 */
837 panic("we need grant tables version 2, but only version 1 is available");
838 } else {
839 grant_table_version = 1;
840 gnttab_interface = &gnttab_v1_ops;
841 }
679 printk(KERN_INFO "Grant tables using version %d layout.\n", 842 printk(KERN_INFO "Grant tables using version %d layout.\n",
680 grant_table_version); 843 grant_table_version);
681} 844}
diff --git a/include/xen/grant_table.h b/include/xen/grant_table.h
index c7a40f8d455a..5494c402c83a 100644
--- a/include/xen/grant_table.h
+++ b/include/xen/grant_table.h
@@ -146,8 +146,10 @@ gnttab_set_unmap_op(struct gnttab_unmap_grant_ref *unmap, phys_addr_t addr,
146int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes, 146int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
147 unsigned long max_nr_gframes, 147 unsigned long max_nr_gframes,
148 void **__shared); 148 void **__shared);
149void arch_gnttab_unmap_shared(void *shared, 149int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes,
150 unsigned long nr_gframes); 150 unsigned long max_nr_gframes,
151 grant_status_t **__shared);
152void arch_gnttab_unmap(void *shared, unsigned long nr_gframes);
151 153
152extern unsigned long xen_hvm_resume_frames; 154extern unsigned long xen_hvm_resume_frames;
153unsigned int gnttab_max_grant_frames(void); 155unsigned int gnttab_max_grant_frames(void);