|
36 | 36 |
|
37 | 37 | #include <linux/sched.h>
|
38 | 38 | #include <linux/mm.h>
|
| 39 | +#include <linux/slab.h> |
39 | 40 | #include <linux/vmalloc.h>
|
40 | 41 |
|
41 | 42 | #include <xen/interface/xen.h>
|
42 | 43 | #include <xen/page.h>
|
43 | 44 | #include <xen/grant_table.h>
|
| 45 | +#include <xen/xen.h> |
44 | 46 |
|
45 | 47 | #include <asm/pgtable.h>
|
46 | 48 |
|
47 |
| -static int map_pte_fn(pte_t *pte, struct page *pmd_page, |
48 |
| - unsigned long addr, void *data) |
| 49 | +static struct gnttab_vm_area { |
| 50 | + struct vm_struct *area; |
| 51 | + pte_t **ptes; |
| 52 | +} gnttab_shared_vm_area, gnttab_status_vm_area; |
| 53 | + |
| 54 | +int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes, |
| 55 | + unsigned long max_nr_gframes, |
| 56 | + void **__shared) |
49 | 57 | {
|
50 |
| - unsigned long **frames = (unsigned long **)data; |
| 58 | + void *shared = *__shared; |
| 59 | + unsigned long addr; |
| 60 | + unsigned long i; |
51 | 61 |
|
52 |
| - set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL)); |
53 |
| - (*frames)++; |
54 |
| - return 0; |
55 |
| -} |
| 62 | + if (shared == NULL) |
| 63 | + *__shared = shared = gnttab_shared_vm_area.area->addr; |
56 | 64 |
|
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 |
| - */ |
61 |
| -static 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 | + addr = (unsigned long)shared; |
| 66 | + |
| 67 | + for (i = 0; i < nr_gframes; i++) { |
| 68 | + set_pte_at(&init_mm, addr, gnttab_shared_vm_area.ptes[i], |
| 69 | + mfn_pte(frames[i], PAGE_KERNEL)); |
| 70 | + addr += PAGE_SIZE; |
| 71 | + } |
65 | 72 |
|
66 |
| - set_pte_at(&init_mm, addr, pte, mfn_pte((*frames)[0], PAGE_KERNEL)); |
67 |
| - (*frames)++; |
68 | 73 | return 0;
|
69 | 74 | }
|
70 | 75 |
|
71 |
| -static int unmap_pte_fn(pte_t *pte, struct page *pmd_page, |
72 |
| - unsigned long addr, void *data) |
| 76 | +int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes, |
| 77 | + unsigned long max_nr_gframes, |
| 78 | + grant_status_t **__shared) |
73 | 79 | {
|
| 80 | + grant_status_t *shared = *__shared; |
| 81 | + unsigned long addr; |
| 82 | + unsigned long i; |
| 83 | + |
| 84 | + if (shared == NULL) |
| 85 | + *__shared = shared = gnttab_status_vm_area.area->addr; |
| 86 | + |
| 87 | + addr = (unsigned long)shared; |
| 88 | + |
| 89 | + for (i = 0; i < nr_gframes; i++) { |
| 90 | + set_pte_at(&init_mm, addr, gnttab_status_vm_area.ptes[i], |
| 91 | + mfn_pte(frames[i], PAGE_KERNEL)); |
| 92 | + addr += PAGE_SIZE; |
| 93 | + } |
74 | 94 |
|
75 |
| - set_pte_at(&init_mm, addr, pte, __pte(0)); |
76 | 95 | return 0;
|
77 | 96 | }
|
78 | 97 |
|
79 |
| -int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes, |
80 |
| - unsigned long max_nr_gframes, |
81 |
| - void **__shared) |
| 98 | +void arch_gnttab_unmap(void *shared, unsigned long nr_gframes) |
82 | 99 | {
|
83 |
| - int rc; |
84 |
| - void *shared = *__shared; |
| 100 | + pte_t **ptes; |
| 101 | + unsigned long addr; |
| 102 | + unsigned long i; |
85 | 103 |
|
86 |
| - if (shared == NULL) { |
87 |
| - struct vm_struct *area = |
88 |
| - alloc_vm_area(PAGE_SIZE * max_nr_gframes, NULL); |
89 |
| - BUG_ON(area == NULL); |
90 |
| - shared = area->addr; |
91 |
| - *__shared = shared; |
92 |
| - } |
| 104 | + if (shared == gnttab_status_vm_area.area->addr) |
| 105 | + ptes = gnttab_status_vm_area.ptes; |
| 106 | + else |
| 107 | + ptes = gnttab_shared_vm_area.ptes; |
93 | 108 |
|
94 |
| - rc = apply_to_page_range(&init_mm, (unsigned long)shared, |
95 |
| - PAGE_SIZE * nr_gframes, |
96 |
| - map_pte_fn, &frames); |
97 |
| - return rc; |
| 109 | + addr = (unsigned long)shared; |
| 110 | + |
| 111 | + for (i = 0; i < nr_gframes; i++) { |
| 112 | + set_pte_at(&init_mm, addr, ptes[i], __pte(0)); |
| 113 | + addr += PAGE_SIZE; |
| 114 | + } |
98 | 115 | }
|
99 | 116 |
|
100 |
| -int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes, |
101 |
| - unsigned long max_nr_gframes, |
102 |
| - grant_status_t **__shared) |
| 117 | +static int arch_gnttab_valloc(struct gnttab_vm_area *area, unsigned nr_frames) |
103 | 118 | {
|
104 |
| - int rc; |
105 |
| - grant_status_t *shared = *__shared; |
| 119 | + area->ptes = kmalloc(sizeof(pte_t *) * nr_frames, GFP_KERNEL); |
| 120 | + if (area->ptes == NULL) |
| 121 | + return -ENOMEM; |
106 | 122 |
|
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; |
| 123 | + area->area = alloc_vm_area(PAGE_SIZE * nr_frames, area->ptes); |
| 124 | + if (area->area == NULL) { |
| 125 | + kfree(area->ptes); |
| 126 | + return -ENOMEM; |
115 | 127 | }
|
116 | 128 |
|
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; |
| 129 | + return 0; |
121 | 130 | }
|
122 | 131 |
|
123 |
| -void arch_gnttab_unmap(void *shared, unsigned long nr_gframes) |
| 132 | +static void arch_gnttab_vfree(struct gnttab_vm_area *area) |
| 133 | +{ |
| 134 | + free_vm_area(area->area); |
| 135 | + kfree(area->ptes); |
| 136 | +} |
| 137 | + |
| 138 | +int arch_gnttab_init(unsigned long nr_shared, unsigned long nr_status) |
124 | 139 | {
|
125 |
| - apply_to_page_range(&init_mm, (unsigned long)shared, |
126 |
| - PAGE_SIZE * nr_gframes, unmap_pte_fn, NULL); |
| 140 | + int ret; |
| 141 | + |
| 142 | + if (!xen_pv_domain()) |
| 143 | + return 0; |
| 144 | + |
| 145 | + ret = arch_gnttab_valloc(&gnttab_shared_vm_area, nr_shared); |
| 146 | + if (ret < 0) |
| 147 | + return ret; |
| 148 | + |
| 149 | + /* |
| 150 | + * Always allocate the space for the status frames in case |
| 151 | + * we're migrated to a host with V2 support. |
| 152 | + */ |
| 153 | + ret = arch_gnttab_valloc(&gnttab_status_vm_area, nr_status); |
| 154 | + if (ret < 0) |
| 155 | + goto err; |
| 156 | + |
| 157 | + return 0; |
| 158 | + err: |
| 159 | + arch_gnttab_vfree(&gnttab_shared_vm_area); |
| 160 | + return -ENOMEM; |
127 | 161 | }
|
| 162 | + |
128 | 163 | #ifdef CONFIG_XEN_PVH
|
129 | 164 | #include <xen/balloon.h>
|
130 | 165 | #include <xen/events.h>
|
131 |
| -#include <xen/xen.h> |
132 | 166 | #include <linux/slab.h>
|
133 | 167 | static int __init xlated_setup_gnttab_pages(void)
|
134 | 168 | {
|
|
0 commit comments