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 */ |
