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 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | // SPDX-License-Identifier: GPL-2.0 /* * (C) 2006 - Cambridge University * (C) 2020 - EPAM Systems Inc. * * File: gnttab.c [1] * Author: Steven Smith (sos22@cam.ac.uk) * Changes: Grzegorz Milos (gm281@cam.ac.uk) * * Date: July 2006 * * Description: Simple grant tables implementation. About as stupid as it's * possible to be and still work. * * [1] - http://xenbits.xen.org/gitweb/?p=mini-os.git;a=summary */ #include <asm/global_data.h> #include <linux/compiler.h> #include <log.h> #include <malloc.h> #include <asm/armv8/mmu.h> #include <asm/io.h> #include <asm/xen/system.h> #include <linux/bug.h> #include <xen/gnttab.h> #include <xen/hvm.h> #include <xen/interface/memory.h> DECLARE_GLOBAL_DATA_PTR; #define NR_RESERVED_ENTRIES 8 /* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */ #define NR_GRANT_FRAMES 1 #define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(struct grant_entry_v1)) static struct grant_entry_v1 *gnttab_table; static grant_ref_t gnttab_list[NR_GRANT_ENTRIES]; static void put_free_entry(grant_ref_t ref) { unsigned long flags; local_irq_save(flags); gnttab_list[ref] = gnttab_list[0]; gnttab_list[0] = ref; local_irq_restore(flags); } static grant_ref_t get_free_entry(void) { unsigned int ref; unsigned long flags; local_irq_save(flags); ref = gnttab_list[0]; BUG_ON(ref < NR_RESERVED_ENTRIES || ref >= NR_GRANT_ENTRIES); gnttab_list[0] = gnttab_list[ref]; local_irq_restore(flags); return ref; } /** * gnttab_grant_access() - Allow access to the given frame. * The function creates an entry in the grant table according * to the specified parameters. * @domid: the id of the domain for which access is allowed * @frame: the number of the shared frame * @readonly: determines whether the frame is shared read-only or read-write * * Return: relevant grant reference */ grant_ref_t gnttab_grant_access(domid_t domid, unsigned long frame, int readonly) { grant_ref_t ref; ref = get_free_entry(); gnttab_table[ref].frame = frame; gnttab_table[ref].domid = domid; wmb(); readonly *= GTF_readonly; gnttab_table[ref].flags = GTF_permit_access | readonly; return ref; } /** * gnttab_end_access() - End of memory sharing. The function invalidates * the entry in the grant table. */ int gnttab_end_access(grant_ref_t ref) { u16 flags, nflags; BUG_ON(ref >= NR_GRANT_ENTRIES || ref < NR_RESERVED_ENTRIES); nflags = gnttab_table[ref].flags; do { flags = nflags; if ((flags) & (GTF_reading | GTF_writing)) { printf("WARNING: g.e. still in use! (%x)\n", flags); return 0; } } while ((nflags = synch_cmpxchg(&gnttab_table[ref].flags, flags, 0)) != flags); put_free_entry(ref); return 1; } grant_ref_t gnttab_alloc_and_grant(void **map) { unsigned long mfn; grant_ref_t gref; *map = (void *)memalign(PAGE_SIZE, PAGE_SIZE); mfn = virt_to_mfn(*map); gref = gnttab_grant_access(0, mfn, 0); return gref; } static const char * const gnttabop_error_msgs[] = GNTTABOP_error_msgs; const char *gnttabop_error(int16_t status) { status = -status; if (status < 0 || status >= ARRAY_SIZE(gnttabop_error_msgs)) return "bad status"; else return gnttabop_error_msgs[status]; } /* Get Xen's suggested physical page assignments for the grant table. */ void get_gnttab_base(phys_addr_t *gnttab_base, phys_size_t *gnttab_sz) { const void *blob = gd->fdt_blob; struct fdt_resource res; int mem; mem = fdt_node_offset_by_compatible(blob, -1, "xen,xen"); if (mem < 0) { printf("No xen,xen compatible found\n"); BUG(); } mem = fdt_get_resource(blob, mem, "reg", 0, &res); if (mem == -FDT_ERR_NOTFOUND) { printf("No grant table base in the device tree\n"); BUG(); } *gnttab_base = (phys_addr_t)res.start; if (gnttab_sz) *gnttab_sz = (phys_size_t)(res.end - res.start + 1); debug("FDT suggests grant table base at %llx\n", *gnttab_base); } void init_gnttab(void) { struct xen_add_to_physmap xatp; struct gnttab_setup_table setup; xen_pfn_t frames[NR_GRANT_FRAMES]; int i, rc; debug("%s\n", __func__); for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++) put_free_entry(i); get_gnttab_base((phys_addr_t *)&gnttab_table, NULL); for (i = 0; i < NR_GRANT_FRAMES; i++) { xatp.domid = DOMID_SELF; xatp.size = 0; xatp.space = XENMAPSPACE_grant_table; xatp.idx = i; xatp.gpfn = PFN_DOWN((unsigned long)gnttab_table) + i; rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp); if (rc) printf("XENMEM_add_to_physmap failed; status = %d\n", rc); BUG_ON(rc != 0); } setup.dom = DOMID_SELF; setup.nr_frames = NR_GRANT_FRAMES; set_xen_guest_handle(setup.frame_list, frames); } void fini_gnttab(void) { struct xen_remove_from_physmap xrtp; struct gnttab_setup_table setup; int i, rc; debug("%s\n", __func__); for (i = 0; i < NR_GRANT_FRAMES; i++) { xrtp.domid = DOMID_SELF; xrtp.gpfn = PFN_DOWN((unsigned long)gnttab_table) + i; rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrtp); if (rc) printf("XENMEM_remove_from_physmap failed; status = %d\n", rc); BUG_ON(rc != 0); } setup.dom = DOMID_SELF; setup.nr_frames = 0; } |