0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #include <linux/sched.h>
0015 #include <linux/mm.h>
0016 #include <linux/slab.h>
0017 #include <linux/vmalloc.h>
0018
0019 #include <xen/interface/xen.h>
0020 #include <xen/page.h>
0021 #include <xen/grant_table.h>
0022 #include <xen/xen.h>
0023
0024
0025 static struct gnttab_vm_area {
0026 struct vm_struct *area;
0027 pte_t **ptes;
0028 int idx;
0029 } gnttab_shared_vm_area, gnttab_status_vm_area;
0030
0031 int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
0032 unsigned long max_nr_gframes,
0033 void **__shared)
0034 {
0035 void *shared = *__shared;
0036 unsigned long addr;
0037 unsigned long i;
0038
0039 if (shared == NULL)
0040 *__shared = shared = gnttab_shared_vm_area.area->addr;
0041
0042 addr = (unsigned long)shared;
0043
0044 for (i = 0; i < nr_gframes; i++) {
0045 set_pte_at(&init_mm, addr, gnttab_shared_vm_area.ptes[i],
0046 mfn_pte(frames[i], PAGE_KERNEL));
0047 addr += PAGE_SIZE;
0048 }
0049
0050 return 0;
0051 }
0052
0053 int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes,
0054 unsigned long max_nr_gframes,
0055 grant_status_t **__shared)
0056 {
0057 grant_status_t *shared = *__shared;
0058 unsigned long addr;
0059 unsigned long i;
0060
0061 if (shared == NULL)
0062 *__shared = shared = gnttab_status_vm_area.area->addr;
0063
0064 addr = (unsigned long)shared;
0065
0066 for (i = 0; i < nr_gframes; i++) {
0067 set_pte_at(&init_mm, addr, gnttab_status_vm_area.ptes[i],
0068 mfn_pte(frames[i], PAGE_KERNEL));
0069 addr += PAGE_SIZE;
0070 }
0071
0072 return 0;
0073 }
0074
0075 void arch_gnttab_unmap(void *shared, unsigned long nr_gframes)
0076 {
0077 pte_t **ptes;
0078 unsigned long addr;
0079 unsigned long i;
0080
0081 if (shared == gnttab_status_vm_area.area->addr)
0082 ptes = gnttab_status_vm_area.ptes;
0083 else
0084 ptes = gnttab_shared_vm_area.ptes;
0085
0086 addr = (unsigned long)shared;
0087
0088 for (i = 0; i < nr_gframes; i++) {
0089 set_pte_at(&init_mm, addr, ptes[i], __pte(0));
0090 addr += PAGE_SIZE;
0091 }
0092 }
0093
0094 static int gnttab_apply(pte_t *pte, unsigned long addr, void *data)
0095 {
0096 struct gnttab_vm_area *area = data;
0097
0098 area->ptes[area->idx++] = pte;
0099 return 0;
0100 }
0101
0102 static int arch_gnttab_valloc(struct gnttab_vm_area *area, unsigned nr_frames)
0103 {
0104 area->ptes = kmalloc_array(nr_frames, sizeof(*area->ptes), GFP_KERNEL);
0105 if (area->ptes == NULL)
0106 return -ENOMEM;
0107 area->area = get_vm_area(PAGE_SIZE * nr_frames, VM_IOREMAP);
0108 if (!area->area)
0109 goto out_free_ptes;
0110 if (apply_to_page_range(&init_mm, (unsigned long)area->area->addr,
0111 PAGE_SIZE * nr_frames, gnttab_apply, area))
0112 goto out_free_vm_area;
0113 return 0;
0114 out_free_vm_area:
0115 free_vm_area(area->area);
0116 out_free_ptes:
0117 kfree(area->ptes);
0118 return -ENOMEM;
0119 }
0120
0121 static void arch_gnttab_vfree(struct gnttab_vm_area *area)
0122 {
0123 free_vm_area(area->area);
0124 kfree(area->ptes);
0125 }
0126
0127 int arch_gnttab_init(unsigned long nr_shared, unsigned long nr_status)
0128 {
0129 int ret;
0130
0131 if (!xen_pv_domain())
0132 return 0;
0133
0134 ret = arch_gnttab_valloc(&gnttab_shared_vm_area, nr_shared);
0135 if (ret < 0)
0136 return ret;
0137
0138
0139
0140
0141
0142 ret = arch_gnttab_valloc(&gnttab_status_vm_area, nr_status);
0143 if (ret < 0)
0144 goto err;
0145
0146 return 0;
0147 err:
0148 arch_gnttab_vfree(&gnttab_shared_vm_area);
0149 return -ENOMEM;
0150 }
0151
0152 #ifdef CONFIG_XEN_PVH
0153 #include <xen/events.h>
0154 #include <xen/xen-ops.h>
0155 static int __init xen_pvh_gnttab_setup(void)
0156 {
0157 if (!xen_pvh_domain())
0158 return -ENODEV;
0159
0160 xen_auto_xlat_grant_frames.count = gnttab_max_grant_frames();
0161
0162 return xen_xlate_map_ballooned_pages(&xen_auto_xlat_grant_frames.pfn,
0163 &xen_auto_xlat_grant_frames.vaddr,
0164 xen_auto_xlat_grant_frames.count);
0165 }
0166
0167
0168 core_initcall(xen_pvh_gnttab_setup);
0169 #endif