Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | // SPDX-License-Identifier: GPL-2.0 OR MIT /****************************************************************************** * grant_table.c * x86 specific part * * Granting foreign access to our memory reservation. * * Copyright (c) 2005-2006, Christopher Clark * Copyright (c) 2004-2005, K A Fraser * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp> * VA Linux Systems Japan. Split out x86 specific part. */ #include <linux/sched.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <xen/interface/xen.h> #include <xen/page.h> #include <xen/grant_table.h> #include <xen/xen.h> static struct gnttab_vm_area { struct vm_struct *area; pte_t **ptes; int idx; } gnttab_shared_vm_area, gnttab_status_vm_area; int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes, unsigned long max_nr_gframes, void **__shared) { void *shared = *__shared; unsigned long addr; unsigned long i; if (shared == NULL) *__shared = shared = gnttab_shared_vm_area.area->addr; addr = (unsigned long)shared; for (i = 0; i < nr_gframes; i++) { set_pte_at(&init_mm, addr, gnttab_shared_vm_area.ptes[i], mfn_pte(frames[i], PAGE_KERNEL)); addr += PAGE_SIZE; } return 0; } int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes, unsigned long max_nr_gframes, grant_status_t **__shared) { grant_status_t *shared = *__shared; unsigned long addr; unsigned long i; if (shared == NULL) *__shared = shared = gnttab_status_vm_area.area->addr; addr = (unsigned long)shared; for (i = 0; i < nr_gframes; i++) { set_pte_at(&init_mm, addr, gnttab_status_vm_area.ptes[i], mfn_pte(frames[i], PAGE_KERNEL)); addr += PAGE_SIZE; } return 0; } void arch_gnttab_unmap(void *shared, unsigned long nr_gframes) { pte_t **ptes; unsigned long addr; unsigned long i; if (shared == gnttab_status_vm_area.area->addr) ptes = gnttab_status_vm_area.ptes; else ptes = gnttab_shared_vm_area.ptes; addr = (unsigned long)shared; for (i = 0; i < nr_gframes; i++) { set_pte_at(&init_mm, addr, ptes[i], __pte(0)); addr += PAGE_SIZE; } } static int gnttab_apply(pte_t *pte, unsigned long addr, void *data) { struct gnttab_vm_area *area = data; area->ptes[area->idx++] = pte; return 0; } static int arch_gnttab_valloc(struct gnttab_vm_area *area, unsigned nr_frames) { area->ptes = kmalloc_array(nr_frames, sizeof(*area->ptes), GFP_KERNEL); if (area->ptes == NULL) return -ENOMEM; area->area = get_vm_area(PAGE_SIZE * nr_frames, VM_IOREMAP); if (!area->area) goto out_free_ptes; if (apply_to_page_range(&init_mm, (unsigned long)area->area->addr, PAGE_SIZE * nr_frames, gnttab_apply, area)) goto out_free_vm_area; return 0; out_free_vm_area: free_vm_area(area->area); out_free_ptes: kfree(area->ptes); return -ENOMEM; } static void arch_gnttab_vfree(struct gnttab_vm_area *area) { free_vm_area(area->area); kfree(area->ptes); } int arch_gnttab_init(unsigned long nr_shared, unsigned long nr_status) { int ret; if (!xen_pv_domain()) return 0; ret = arch_gnttab_valloc(&gnttab_shared_vm_area, nr_shared); if (ret < 0) return ret; /* * Always allocate the space for the status frames in case * we're migrated to a host with V2 support. */ ret = arch_gnttab_valloc(&gnttab_status_vm_area, nr_status); if (ret < 0) goto err; return 0; err: arch_gnttab_vfree(&gnttab_shared_vm_area); return -ENOMEM; } #ifdef CONFIG_XEN_PVH #include <xen/events.h> #include <xen/xen-ops.h> static int __init xen_pvh_gnttab_setup(void) { if (!xen_pvh_domain()) return -ENODEV; xen_auto_xlat_grant_frames.count = gnttab_max_grant_frames(); return xen_xlate_map_ballooned_pages(&xen_auto_xlat_grant_frames.pfn, &xen_auto_xlat_grant_frames.vaddr, xen_auto_xlat_grant_frames.count); } /* Call it _before_ __gnttab_init as we need to initialize the * xen_auto_xlat_grant_frames first. */ core_initcall(xen_pvh_gnttab_setup); #endif |