diff options
-rw-r--r-- | arch/arm/include/asm/xen/interface.h | 1 | ||||
-rw-r--r-- | arch/arm/xen/enlighten.c | 123 | ||||
-rw-r--r-- | arch/x86/include/asm/xen/interface.h | 1 | ||||
-rw-r--r-- | arch/x86/xen/Kconfig | 1 | ||||
-rw-r--r-- | arch/x86/xen/mmu.c | 17 | ||||
-rw-r--r-- | drivers/xen/Kconfig | 3 | ||||
-rw-r--r-- | drivers/xen/Makefile | 4 | ||||
-rw-r--r-- | drivers/xen/balloon.c | 5 | ||||
-rw-r--r-- | drivers/xen/privcmd.c | 72 | ||||
-rw-r--r-- | include/xen/interface/memory.h | 44 | ||||
-rw-r--r-- | include/xen/xen-ops.h | 8 |
11 files changed, 246 insertions, 33 deletions
diff --git a/arch/arm/include/asm/xen/interface.h b/arch/arm/include/asm/xen/interface.h index 5000397134b4..1151188bcd83 100644 --- a/arch/arm/include/asm/xen/interface.h +++ b/arch/arm/include/asm/xen/interface.h | |||
@@ -49,6 +49,7 @@ DEFINE_GUEST_HANDLE(void); | |||
49 | DEFINE_GUEST_HANDLE(uint64_t); | 49 | DEFINE_GUEST_HANDLE(uint64_t); |
50 | DEFINE_GUEST_HANDLE(uint32_t); | 50 | DEFINE_GUEST_HANDLE(uint32_t); |
51 | DEFINE_GUEST_HANDLE(xen_pfn_t); | 51 | DEFINE_GUEST_HANDLE(xen_pfn_t); |
52 | DEFINE_GUEST_HANDLE(xen_ulong_t); | ||
52 | 53 | ||
53 | /* Maximum number of virtual CPUs in multi-processor guests. */ | 54 | /* Maximum number of virtual CPUs in multi-processor guests. */ |
54 | #define MAX_VIRT_CPUS 1 | 55 | #define MAX_VIRT_CPUS 1 |
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c index 59bcb96ac369..f28fc1ac8760 100644 --- a/arch/arm/xen/enlighten.c +++ b/arch/arm/xen/enlighten.c | |||
@@ -8,6 +8,8 @@ | |||
8 | #include <xen/features.h> | 8 | #include <xen/features.h> |
9 | #include <xen/platform_pci.h> | 9 | #include <xen/platform_pci.h> |
10 | #include <xen/xenbus.h> | 10 | #include <xen/xenbus.h> |
11 | #include <xen/page.h> | ||
12 | #include <xen/xen-ops.h> | ||
11 | #include <asm/xen/hypervisor.h> | 13 | #include <asm/xen/hypervisor.h> |
12 | #include <asm/xen/hypercall.h> | 14 | #include <asm/xen/hypercall.h> |
13 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
@@ -17,6 +19,8 @@ | |||
17 | #include <linux/of_irq.h> | 19 | #include <linux/of_irq.h> |
18 | #include <linux/of_address.h> | 20 | #include <linux/of_address.h> |
19 | 21 | ||
22 | #include <linux/mm.h> | ||
23 | |||
20 | struct start_info _xen_start_info; | 24 | struct start_info _xen_start_info; |
21 | struct start_info *xen_start_info = &_xen_start_info; | 25 | struct start_info *xen_start_info = &_xen_start_info; |
22 | EXPORT_SYMBOL_GPL(xen_start_info); | 26 | EXPORT_SYMBOL_GPL(xen_start_info); |
@@ -29,6 +33,10 @@ struct shared_info *HYPERVISOR_shared_info = (void *)&xen_dummy_shared_info; | |||
29 | 33 | ||
30 | DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu); | 34 | DEFINE_PER_CPU(struct vcpu_info *, xen_vcpu); |
31 | 35 | ||
36 | /* These are unused until we support booting "pre-ballooned" */ | ||
37 | unsigned long xen_released_pages; | ||
38 | struct xen_memory_region xen_extra_mem[XEN_EXTRA_MEM_MAX_REGIONS] __initdata; | ||
39 | |||
32 | /* TODO: to be removed */ | 40 | /* TODO: to be removed */ |
33 | __read_mostly int xen_have_vector_callback; | 41 | __read_mostly int xen_have_vector_callback; |
34 | EXPORT_SYMBOL_GPL(xen_have_vector_callback); | 42 | EXPORT_SYMBOL_GPL(xen_have_vector_callback); |
@@ -38,15 +46,106 @@ EXPORT_SYMBOL_GPL(xen_platform_pci_unplug); | |||
38 | 46 | ||
39 | static __read_mostly int xen_events_irq = -1; | 47 | static __read_mostly int xen_events_irq = -1; |
40 | 48 | ||
49 | /* map fgmfn of domid to lpfn in the current domain */ | ||
50 | static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn, | ||
51 | unsigned int domid) | ||
52 | { | ||
53 | int rc; | ||
54 | struct xen_add_to_physmap_range xatp = { | ||
55 | .domid = DOMID_SELF, | ||
56 | .foreign_domid = domid, | ||
57 | .size = 1, | ||
58 | .space = XENMAPSPACE_gmfn_foreign, | ||
59 | }; | ||
60 | xen_ulong_t idx = fgmfn; | ||
61 | xen_pfn_t gpfn = lpfn; | ||
62 | |||
63 | set_xen_guest_handle(xatp.idxs, &idx); | ||
64 | set_xen_guest_handle(xatp.gpfns, &gpfn); | ||
65 | |||
66 | rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp); | ||
67 | if (rc) { | ||
68 | pr_warn("Failed to map pfn to mfn rc:%d pfn:%lx mfn:%lx\n", | ||
69 | rc, lpfn, fgmfn); | ||
70 | return 1; | ||
71 | } | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | struct remap_data { | ||
76 | xen_pfn_t fgmfn; /* foreign domain's gmfn */ | ||
77 | pgprot_t prot; | ||
78 | domid_t domid; | ||
79 | struct vm_area_struct *vma; | ||
80 | int index; | ||
81 | struct page **pages; | ||
82 | struct xen_remap_mfn_info *info; | ||
83 | }; | ||
84 | |||
85 | static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, | ||
86 | void *data) | ||
87 | { | ||
88 | struct remap_data *info = data; | ||
89 | struct page *page = info->pages[info->index++]; | ||
90 | unsigned long pfn = page_to_pfn(page); | ||
91 | pte_t pte = pfn_pte(pfn, info->prot); | ||
92 | |||
93 | if (map_foreign_page(pfn, info->fgmfn, info->domid)) | ||
94 | return -EFAULT; | ||
95 | set_pte_at(info->vma->vm_mm, addr, ptep, pte); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
41 | int xen_remap_domain_mfn_range(struct vm_area_struct *vma, | 100 | int xen_remap_domain_mfn_range(struct vm_area_struct *vma, |
42 | unsigned long addr, | 101 | unsigned long addr, |
43 | unsigned long mfn, int nr, | 102 | xen_pfn_t mfn, int nr, |
44 | pgprot_t prot, unsigned domid) | 103 | pgprot_t prot, unsigned domid, |
104 | struct page **pages) | ||
45 | { | 105 | { |
46 | return -ENOSYS; | 106 | int err; |
107 | struct remap_data data; | ||
108 | |||
109 | /* TBD: Batching, current sole caller only does page at a time */ | ||
110 | if (nr > 1) | ||
111 | return -EINVAL; | ||
112 | |||
113 | data.fgmfn = mfn; | ||
114 | data.prot = prot; | ||
115 | data.domid = domid; | ||
116 | data.vma = vma; | ||
117 | data.index = 0; | ||
118 | data.pages = pages; | ||
119 | err = apply_to_page_range(vma->vm_mm, addr, nr << PAGE_SHIFT, | ||
120 | remap_pte_fn, &data); | ||
121 | return err; | ||
47 | } | 122 | } |
48 | EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); | 123 | EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); |
49 | 124 | ||
125 | int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, | ||
126 | int nr, struct page **pages) | ||
127 | { | ||
128 | int i; | ||
129 | |||
130 | for (i = 0; i < nr; i++) { | ||
131 | struct xen_remove_from_physmap xrp; | ||
132 | unsigned long rc, pfn; | ||
133 | |||
134 | pfn = page_to_pfn(pages[i]); | ||
135 | |||
136 | xrp.domid = DOMID_SELF; | ||
137 | xrp.gpfn = pfn; | ||
138 | rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrp); | ||
139 | if (rc) { | ||
140 | pr_warn("Failed to unmap pfn:%lx rc:%ld\n", | ||
141 | pfn, rc); | ||
142 | return rc; | ||
143 | } | ||
144 | } | ||
145 | return 0; | ||
146 | } | ||
147 | EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range); | ||
148 | |||
50 | /* | 149 | /* |
51 | * see Documentation/devicetree/bindings/arm/xen.txt for the | 150 | * see Documentation/devicetree/bindings/arm/xen.txt for the |
52 | * documentation of the Xen Device Tree format. | 151 | * documentation of the Xen Device Tree format. |
@@ -148,21 +247,3 @@ static int __init xen_init_events(void) | |||
148 | return 0; | 247 | return 0; |
149 | } | 248 | } |
150 | postcore_initcall(xen_init_events); | 249 | postcore_initcall(xen_init_events); |
151 | |||
152 | /* XXX: only until balloon is properly working */ | ||
153 | int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem) | ||
154 | { | ||
155 | *pages = alloc_pages(highmem ? GFP_HIGHUSER : GFP_KERNEL, | ||
156 | get_order(nr_pages)); | ||
157 | if (*pages == NULL) | ||
158 | return -ENOMEM; | ||
159 | return 0; | ||
160 | } | ||
161 | EXPORT_SYMBOL_GPL(alloc_xenballooned_pages); | ||
162 | |||
163 | void free_xenballooned_pages(int nr_pages, struct page **pages) | ||
164 | { | ||
165 | kfree(*pages); | ||
166 | *pages = NULL; | ||
167 | } | ||
168 | EXPORT_SYMBOL_GPL(free_xenballooned_pages); | ||
diff --git a/arch/x86/include/asm/xen/interface.h b/arch/x86/include/asm/xen/interface.h index 54d52ff1304a..fd9cb7695b5f 100644 --- a/arch/x86/include/asm/xen/interface.h +++ b/arch/x86/include/asm/xen/interface.h | |||
@@ -63,6 +63,7 @@ DEFINE_GUEST_HANDLE(void); | |||
63 | DEFINE_GUEST_HANDLE(uint64_t); | 63 | DEFINE_GUEST_HANDLE(uint64_t); |
64 | DEFINE_GUEST_HANDLE(uint32_t); | 64 | DEFINE_GUEST_HANDLE(uint32_t); |
65 | DEFINE_GUEST_HANDLE(xen_pfn_t); | 65 | DEFINE_GUEST_HANDLE(xen_pfn_t); |
66 | DEFINE_GUEST_HANDLE(xen_ulong_t); | ||
66 | #endif | 67 | #endif |
67 | 68 | ||
68 | #ifndef HYPERVISOR_VIRT_START | 69 | #ifndef HYPERVISOR_VIRT_START |
diff --git a/arch/x86/xen/Kconfig b/arch/x86/xen/Kconfig index fdce49c7aff6..c31ee77e1ec1 100644 --- a/arch/x86/xen/Kconfig +++ b/arch/x86/xen/Kconfig | |||
@@ -6,6 +6,7 @@ config XEN | |||
6 | bool "Xen guest support" | 6 | bool "Xen guest support" |
7 | select PARAVIRT | 7 | select PARAVIRT |
8 | select PARAVIRT_CLOCK | 8 | select PARAVIRT_CLOCK |
9 | select XEN_HAVE_PVMMU | ||
9 | depends on X86_64 || (X86_32 && X86_PAE && !X86_VISWS) | 10 | depends on X86_64 || (X86_32 && X86_PAE && !X86_VISWS) |
10 | depends on X86_CMPXCHG && X86_TSC | 11 | depends on X86_CMPXCHG && X86_TSC |
11 | help | 12 | help |
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 6226c99729b9..fd8393f55069 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c | |||
@@ -2478,8 +2478,10 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token, | |||
2478 | 2478 | ||
2479 | int xen_remap_domain_mfn_range(struct vm_area_struct *vma, | 2479 | int xen_remap_domain_mfn_range(struct vm_area_struct *vma, |
2480 | unsigned long addr, | 2480 | unsigned long addr, |
2481 | unsigned long mfn, int nr, | 2481 | xen_pfn_t mfn, int nr, |
2482 | pgprot_t prot, unsigned domid) | 2482 | pgprot_t prot, unsigned domid, |
2483 | struct page **pages) | ||
2484 | |||
2483 | { | 2485 | { |
2484 | struct remap_data rmd; | 2486 | struct remap_data rmd; |
2485 | struct mmu_update mmu_update[REMAP_BATCH_SIZE]; | 2487 | struct mmu_update mmu_update[REMAP_BATCH_SIZE]; |
@@ -2523,3 +2525,14 @@ out: | |||
2523 | return err; | 2525 | return err; |
2524 | } | 2526 | } |
2525 | EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); | 2527 | EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); |
2528 | |||
2529 | /* Returns: 0 success */ | ||
2530 | int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, | ||
2531 | int numpgs, struct page **pages) | ||
2532 | { | ||
2533 | if (!pages || !xen_feature(XENFEAT_auto_translated_physmap)) | ||
2534 | return 0; | ||
2535 | |||
2536 | return -EINVAL; | ||
2537 | } | ||
2538 | EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range); | ||
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 126d8ce591ce..cabfa97f4674 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig | |||
@@ -206,4 +206,7 @@ config XEN_MCE_LOG | |||
206 | Allow kernel fetching MCE error from Xen platform and | 206 | Allow kernel fetching MCE error from Xen platform and |
207 | converting it into Linux mcelog format for mcelog tools | 207 | converting it into Linux mcelog format for mcelog tools |
208 | 208 | ||
209 | config XEN_HAVE_PVMMU | ||
210 | bool | ||
211 | |||
209 | endmenu | 212 | endmenu |
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 3c397170f39c..3ee2b91ca4e0 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile | |||
@@ -1,8 +1,8 @@ | |||
1 | ifneq ($(CONFIG_ARM),y) | 1 | ifneq ($(CONFIG_ARM),y) |
2 | obj-y += manage.o balloon.o | 2 | obj-y += manage.o |
3 | obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o | 3 | obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o |
4 | endif | 4 | endif |
5 | obj-y += grant-table.o features.o events.o | 5 | obj-y += grant-table.o features.o events.o balloon.o |
6 | obj-y += xenbus/ | 6 | obj-y += xenbus/ |
7 | 7 | ||
8 | nostackp := $(call cc-option, -fno-stack-protector) | 8 | nostackp := $(call cc-option, -fno-stack-protector) |
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index d6886d90ccfd..a56776dbe095 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c | |||
@@ -359,6 +359,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages) | |||
359 | 359 | ||
360 | set_phys_to_machine(pfn, frame_list[i]); | 360 | set_phys_to_machine(pfn, frame_list[i]); |
361 | 361 | ||
362 | #ifdef CONFIG_XEN_HAVE_PVMMU | ||
362 | /* Link back into the page tables if not highmem. */ | 363 | /* Link back into the page tables if not highmem. */ |
363 | if (xen_pv_domain() && !PageHighMem(page)) { | 364 | if (xen_pv_domain() && !PageHighMem(page)) { |
364 | int ret; | 365 | int ret; |
@@ -368,6 +369,7 @@ static enum bp_state increase_reservation(unsigned long nr_pages) | |||
368 | 0); | 369 | 0); |
369 | BUG_ON(ret); | 370 | BUG_ON(ret); |
370 | } | 371 | } |
372 | #endif | ||
371 | 373 | ||
372 | /* Relinquish the page back to the allocator. */ | 374 | /* Relinquish the page back to the allocator. */ |
373 | ClearPageReserved(page); | 375 | ClearPageReserved(page); |
@@ -416,13 +418,14 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) | |||
416 | 418 | ||
417 | scrub_page(page); | 419 | scrub_page(page); |
418 | 420 | ||
421 | #ifdef CONFIG_XEN_HAVE_PVMMU | ||
419 | if (xen_pv_domain() && !PageHighMem(page)) { | 422 | if (xen_pv_domain() && !PageHighMem(page)) { |
420 | ret = HYPERVISOR_update_va_mapping( | 423 | ret = HYPERVISOR_update_va_mapping( |
421 | (unsigned long)__va(pfn << PAGE_SHIFT), | 424 | (unsigned long)__va(pfn << PAGE_SHIFT), |
422 | __pte_ma(0), 0); | 425 | __pte_ma(0), 0); |
423 | BUG_ON(ret); | 426 | BUG_ON(ret); |
424 | } | 427 | } |
425 | 428 | #endif | |
426 | } | 429 | } |
427 | 430 | ||
428 | /* Ensure that ballooned highmem pages don't have kmaps. */ | 431 | /* Ensure that ballooned highmem pages don't have kmaps. */ |
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 8adb9cc267f9..b9d08987a5a5 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c | |||
@@ -33,11 +33,14 @@ | |||
33 | #include <xen/features.h> | 33 | #include <xen/features.h> |
34 | #include <xen/page.h> | 34 | #include <xen/page.h> |
35 | #include <xen/xen-ops.h> | 35 | #include <xen/xen-ops.h> |
36 | #include <xen/balloon.h> | ||
36 | 37 | ||
37 | #include "privcmd.h" | 38 | #include "privcmd.h" |
38 | 39 | ||
39 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
40 | 41 | ||
42 | #define PRIV_VMA_LOCKED ((void *)1) | ||
43 | |||
41 | #ifndef HAVE_ARCH_PRIVCMD_MMAP | 44 | #ifndef HAVE_ARCH_PRIVCMD_MMAP |
42 | static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma); | 45 | static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma); |
43 | #endif | 46 | #endif |
@@ -178,7 +181,7 @@ static int mmap_mfn_range(void *data, void *state) | |||
178 | msg->va & PAGE_MASK, | 181 | msg->va & PAGE_MASK, |
179 | msg->mfn, msg->npages, | 182 | msg->mfn, msg->npages, |
180 | vma->vm_page_prot, | 183 | vma->vm_page_prot, |
181 | st->domain); | 184 | st->domain, NULL); |
182 | if (rc < 0) | 185 | if (rc < 0) |
183 | return rc; | 186 | return rc; |
184 | 187 | ||
@@ -199,6 +202,10 @@ static long privcmd_ioctl_mmap(void __user *udata) | |||
199 | if (!xen_initial_domain()) | 202 | if (!xen_initial_domain()) |
200 | return -EPERM; | 203 | return -EPERM; |
201 | 204 | ||
205 | /* We only support privcmd_ioctl_mmap_batch for auto translated. */ | ||
206 | if (xen_feature(XENFEAT_auto_translated_physmap)) | ||
207 | return -ENOSYS; | ||
208 | |||
202 | if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd))) | 209 | if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd))) |
203 | return -EFAULT; | 210 | return -EFAULT; |
204 | 211 | ||
@@ -246,6 +253,7 @@ struct mmap_batch_state { | |||
246 | domid_t domain; | 253 | domid_t domain; |
247 | unsigned long va; | 254 | unsigned long va; |
248 | struct vm_area_struct *vma; | 255 | struct vm_area_struct *vma; |
256 | int index; | ||
249 | /* A tristate: | 257 | /* A tristate: |
250 | * 0 for no errors | 258 | * 0 for no errors |
251 | * 1 if at least one error has happened (and no | 259 | * 1 if at least one error has happened (and no |
@@ -260,14 +268,24 @@ struct mmap_batch_state { | |||
260 | xen_pfn_t __user *user_mfn; | 268 | xen_pfn_t __user *user_mfn; |
261 | }; | 269 | }; |
262 | 270 | ||
271 | /* auto translated dom0 note: if domU being created is PV, then mfn is | ||
272 | * mfn(addr on bus). If it's auto xlated, then mfn is pfn (input to HAP). | ||
273 | */ | ||
263 | static int mmap_batch_fn(void *data, void *state) | 274 | static int mmap_batch_fn(void *data, void *state) |
264 | { | 275 | { |
265 | xen_pfn_t *mfnp = data; | 276 | xen_pfn_t *mfnp = data; |
266 | struct mmap_batch_state *st = state; | 277 | struct mmap_batch_state *st = state; |
278 | struct vm_area_struct *vma = st->vma; | ||
279 | struct page **pages = vma->vm_private_data; | ||
280 | struct page *cur_page = NULL; | ||
267 | int ret; | 281 | int ret; |
268 | 282 | ||
283 | if (xen_feature(XENFEAT_auto_translated_physmap)) | ||
284 | cur_page = pages[st->index++]; | ||
285 | |||
269 | ret = xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp, 1, | 286 | ret = xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp, 1, |
270 | st->vma->vm_page_prot, st->domain); | 287 | st->vma->vm_page_prot, st->domain, |
288 | &cur_page); | ||
271 | 289 | ||
272 | /* Store error code for second pass. */ | 290 | /* Store error code for second pass. */ |
273 | *(st->err++) = ret; | 291 | *(st->err++) = ret; |
@@ -303,6 +321,32 @@ static int mmap_return_errors_v1(void *data, void *state) | |||
303 | return __put_user(*mfnp, st->user_mfn++); | 321 | return __put_user(*mfnp, st->user_mfn++); |
304 | } | 322 | } |
305 | 323 | ||
324 | /* Allocate pfns that are then mapped with gmfns from foreign domid. Update | ||
325 | * the vma with the page info to use later. | ||
326 | * Returns: 0 if success, otherwise -errno | ||
327 | */ | ||
328 | static int alloc_empty_pages(struct vm_area_struct *vma, int numpgs) | ||
329 | { | ||
330 | int rc; | ||
331 | struct page **pages; | ||
332 | |||
333 | pages = kcalloc(numpgs, sizeof(pages[0]), GFP_KERNEL); | ||
334 | if (pages == NULL) | ||
335 | return -ENOMEM; | ||
336 | |||
337 | rc = alloc_xenballooned_pages(numpgs, pages, 0); | ||
338 | if (rc != 0) { | ||
339 | pr_warn("%s Could not alloc %d pfns rc:%d\n", __func__, | ||
340 | numpgs, rc); | ||
341 | kfree(pages); | ||
342 | return -ENOMEM; | ||
343 | } | ||
344 | BUG_ON(vma->vm_private_data != PRIV_VMA_LOCKED); | ||
345 | vma->vm_private_data = pages; | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
306 | static struct vm_operations_struct privcmd_vm_ops; | 350 | static struct vm_operations_struct privcmd_vm_ops; |
307 | 351 | ||
308 | static long privcmd_ioctl_mmap_batch(void __user *udata, int version) | 352 | static long privcmd_ioctl_mmap_batch(void __user *udata, int version) |
@@ -370,10 +414,18 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) | |||
370 | up_write(&mm->mmap_sem); | 414 | up_write(&mm->mmap_sem); |
371 | goto out; | 415 | goto out; |
372 | } | 416 | } |
417 | if (xen_feature(XENFEAT_auto_translated_physmap)) { | ||
418 | ret = alloc_empty_pages(vma, m.num); | ||
419 | if (ret < 0) { | ||
420 | up_write(&mm->mmap_sem); | ||
421 | goto out; | ||
422 | } | ||
423 | } | ||
373 | 424 | ||
374 | state.domain = m.dom; | 425 | state.domain = m.dom; |
375 | state.vma = vma; | 426 | state.vma = vma; |
376 | state.va = m.addr; | 427 | state.va = m.addr; |
428 | state.index = 0; | ||
377 | state.global_error = 0; | 429 | state.global_error = 0; |
378 | state.err = err_array; | 430 | state.err = err_array; |
379 | 431 | ||
@@ -438,6 +490,19 @@ static long privcmd_ioctl(struct file *file, | |||
438 | return ret; | 490 | return ret; |
439 | } | 491 | } |
440 | 492 | ||
493 | static void privcmd_close(struct vm_area_struct *vma) | ||
494 | { | ||
495 | struct page **pages = vma->vm_private_data; | ||
496 | int numpgs = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; | ||
497 | |||
498 | if (!xen_feature(XENFEAT_auto_translated_physmap || !numpgs || !pages)) | ||
499 | return; | ||
500 | |||
501 | xen_unmap_domain_mfn_range(vma, numpgs, pages); | ||
502 | free_xenballooned_pages(numpgs, pages); | ||
503 | kfree(pages); | ||
504 | } | ||
505 | |||
441 | static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 506 | static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
442 | { | 507 | { |
443 | printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n", | 508 | printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n", |
@@ -448,6 +513,7 @@ static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
448 | } | 513 | } |
449 | 514 | ||
450 | static struct vm_operations_struct privcmd_vm_ops = { | 515 | static struct vm_operations_struct privcmd_vm_ops = { |
516 | .close = privcmd_close, | ||
451 | .fault = privcmd_fault | 517 | .fault = privcmd_fault |
452 | }; | 518 | }; |
453 | 519 | ||
@@ -465,7 +531,7 @@ static int privcmd_mmap(struct file *file, struct vm_area_struct *vma) | |||
465 | 531 | ||
466 | static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma) | 532 | static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma) |
467 | { | 533 | { |
468 | return (xchg(&vma->vm_private_data, (void *)1) == NULL); | 534 | return !cmpxchg(&vma->vm_private_data, NULL, PRIV_VMA_LOCKED); |
469 | } | 535 | } |
470 | 536 | ||
471 | const struct file_operations xen_privcmd_fops = { | 537 | const struct file_operations xen_privcmd_fops = { |
diff --git a/include/xen/interface/memory.h b/include/xen/interface/memory.h index 90712e2072d5..b40a4315cb8b 100644 --- a/include/xen/interface/memory.h +++ b/include/xen/interface/memory.h | |||
@@ -153,6 +153,14 @@ struct xen_machphys_mapping { | |||
153 | }; | 153 | }; |
154 | DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mapping_t); | 154 | DEFINE_GUEST_HANDLE_STRUCT(xen_machphys_mapping_t); |
155 | 155 | ||
156 | #define XENMAPSPACE_shared_info 0 /* shared info page */ | ||
157 | #define XENMAPSPACE_grant_table 1 /* grant table page */ | ||
158 | #define XENMAPSPACE_gmfn 2 /* GMFN */ | ||
159 | #define XENMAPSPACE_gmfn_range 3 /* GMFN range, XENMEM_add_to_physmap only. */ | ||
160 | #define XENMAPSPACE_gmfn_foreign 4 /* GMFN from another dom, | ||
161 | * XENMEM_add_to_physmap_range only. | ||
162 | */ | ||
163 | |||
156 | /* | 164 | /* |
157 | * Sets the GPFN at which a particular page appears in the specified guest's | 165 | * Sets the GPFN at which a particular page appears in the specified guest's |
158 | * pseudophysical address space. | 166 | * pseudophysical address space. |
@@ -167,8 +175,6 @@ struct xen_add_to_physmap { | |||
167 | uint16_t size; | 175 | uint16_t size; |
168 | 176 | ||
169 | /* Source mapping space. */ | 177 | /* Source mapping space. */ |
170 | #define XENMAPSPACE_shared_info 0 /* shared info page */ | ||
171 | #define XENMAPSPACE_grant_table 1 /* grant table page */ | ||
172 | unsigned int space; | 178 | unsigned int space; |
173 | 179 | ||
174 | /* Index into source mapping space. */ | 180 | /* Index into source mapping space. */ |
@@ -182,6 +188,24 @@ DEFINE_GUEST_HANDLE_STRUCT(xen_add_to_physmap); | |||
182 | /*** REMOVED ***/ | 188 | /*** REMOVED ***/ |
183 | /*#define XENMEM_translate_gpfn_list 8*/ | 189 | /*#define XENMEM_translate_gpfn_list 8*/ |
184 | 190 | ||
191 | #define XENMEM_add_to_physmap_range 23 | ||
192 | struct xen_add_to_physmap_range { | ||
193 | /* Which domain to change the mapping for. */ | ||
194 | domid_t domid; | ||
195 | uint16_t space; /* => enum phys_map_space */ | ||
196 | |||
197 | /* Number of pages to go through */ | ||
198 | uint16_t size; | ||
199 | domid_t foreign_domid; /* IFF gmfn_foreign */ | ||
200 | |||
201 | /* Indexes into space being mapped. */ | ||
202 | GUEST_HANDLE(xen_ulong_t) idxs; | ||
203 | |||
204 | /* GPFN in domid where the source mapping page should appear. */ | ||
205 | GUEST_HANDLE(xen_pfn_t) gpfns; | ||
206 | }; | ||
207 | DEFINE_GUEST_HANDLE_STRUCT(xen_add_to_physmap_range); | ||
208 | |||
185 | /* | 209 | /* |
186 | * Returns the pseudo-physical memory map as it was when the domain | 210 | * Returns the pseudo-physical memory map as it was when the domain |
187 | * was started (specified by XENMEM_set_memory_map). | 211 | * was started (specified by XENMEM_set_memory_map). |
@@ -217,4 +241,20 @@ DEFINE_GUEST_HANDLE_STRUCT(xen_memory_map); | |||
217 | * during a driver critical region. | 241 | * during a driver critical region. |
218 | */ | 242 | */ |
219 | extern spinlock_t xen_reservation_lock; | 243 | extern spinlock_t xen_reservation_lock; |
244 | |||
245 | /* | ||
246 | * Unmaps the page appearing at a particular GPFN from the specified guest's | ||
247 | * pseudophysical address space. | ||
248 | * arg == addr of xen_remove_from_physmap_t. | ||
249 | */ | ||
250 | #define XENMEM_remove_from_physmap 15 | ||
251 | struct xen_remove_from_physmap { | ||
252 | /* Which domain to change the mapping for. */ | ||
253 | domid_t domid; | ||
254 | |||
255 | /* GPFN of the current mapping of the page. */ | ||
256 | xen_pfn_t gpfn; | ||
257 | }; | ||
258 | DEFINE_GUEST_HANDLE_STRUCT(xen_remove_from_physmap); | ||
259 | |||
220 | #endif /* __XEN_PUBLIC_MEMORY_H__ */ | 260 | #endif /* __XEN_PUBLIC_MEMORY_H__ */ |
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 6170abd53d0b..d6fe062cad6b 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define INCLUDE_XEN_OPS_H | 2 | #define INCLUDE_XEN_OPS_H |
3 | 3 | ||
4 | #include <linux/percpu.h> | 4 | #include <linux/percpu.h> |
5 | #include <asm/xen/interface.h> | ||
5 | 6 | ||
6 | DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu); | 7 | DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu); |
7 | 8 | ||
@@ -26,8 +27,11 @@ void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order); | |||
26 | struct vm_area_struct; | 27 | struct vm_area_struct; |
27 | int xen_remap_domain_mfn_range(struct vm_area_struct *vma, | 28 | int xen_remap_domain_mfn_range(struct vm_area_struct *vma, |
28 | unsigned long addr, | 29 | unsigned long addr, |
29 | unsigned long mfn, int nr, | 30 | xen_pfn_t mfn, int nr, |
30 | pgprot_t prot, unsigned domid); | 31 | pgprot_t prot, unsigned domid, |
32 | struct page **pages); | ||
33 | int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, | ||
34 | int numpgs, struct page **pages); | ||
31 | 35 | ||
32 | bool xen_running_on_version_or_later(unsigned int major, unsigned int minor); | 36 | bool xen_running_on_version_or_later(unsigned int major, unsigned int minor); |
33 | #endif /* INCLUDE_XEN_OPS_H */ | 37 | #endif /* INCLUDE_XEN_OPS_H */ |