1// SPDX-License-Identifier: GPL-2.0 2/* 3 * (C) 2006 - Cambridge University 4 * (C) 2020 - EPAM Systems Inc. 5 * 6 * File: gnttab.c [1] 7 * Author: Steven Smith (sos22@cam.ac.uk) 8 * Changes: Grzegorz Milos (gm281@cam.ac.uk) 9 * 10 * Date: July 2006 11 * 12 * Description: Simple grant tables implementation. About as stupid as it's 13 * possible to be and still work. 14 * 15 * [1] - http://xenbits.xen.org/gitweb/?p=mini-os.git;a=summary 16 */ 17#include <common.h> 18#include <asm/global_data.h> 19#include <linux/compiler.h> 20#include <log.h> 21#include <malloc.h> 22 23#include <asm/armv8/mmu.h> 24#include <asm/io.h> 25#include <asm/xen/system.h> 26 27#include <linux/bug.h> 28 29#include <xen/gnttab.h> 30#include <xen/hvm.h> 31 32#include <xen/interface/memory.h> 33 34DECLARE_GLOBAL_DATA_PTR; 35 36#define NR_RESERVED_ENTRIES 8 37 38/* NR_GRANT_FRAMES must be less than or equal to that configured in Xen */ 39#define NR_GRANT_FRAMES 1 40#define NR_GRANT_ENTRIES (NR_GRANT_FRAMES * PAGE_SIZE / sizeof(struct grant_entry_v1)) 41 42static struct grant_entry_v1 *gnttab_table; 43static grant_ref_t gnttab_list[NR_GRANT_ENTRIES]; 44 45static void put_free_entry(grant_ref_t ref) 46{ 47 unsigned long flags; 48 49 local_irq_save(flags); 50 gnttab_list[ref] = gnttab_list[0]; 51 gnttab_list[0] = ref; 52 local_irq_restore(flags); 53} 54 55static grant_ref_t get_free_entry(void) 56{ 57 unsigned int ref; 58 unsigned long flags; 59 60 local_irq_save(flags); 61 ref = gnttab_list[0]; 62 BUG_ON(ref < NR_RESERVED_ENTRIES || ref >= NR_GRANT_ENTRIES); 63 gnttab_list[0] = gnttab_list[ref]; 64 local_irq_restore(flags); 65 return ref; 66} 67 68/** 69 * gnttab_grant_access() - Allow access to the given frame. 70 * The function creates an entry in the grant table according 71 * to the specified parameters. 72 * @domid: the id of the domain for which access is allowed 73 * @frame: the number of the shared frame 74 * @readonly: determines whether the frame is shared read-only or read-write 75 * 76 * Return: relevant grant reference 77 */ 78grant_ref_t gnttab_grant_access(domid_t domid, unsigned long frame, int readonly) 79{ 80 grant_ref_t ref; 81 82 ref = get_free_entry(); 83 gnttab_table[ref].frame = frame; 84 gnttab_table[ref].domid = domid; 85 wmb(); 86 readonly *= GTF_readonly; 87 gnttab_table[ref].flags = GTF_permit_access | readonly; 88 89 return ref; 90} 91 92/** 93 * gnttab_end_access() - End of memory sharing. The function invalidates 94 * the entry in the grant table. 95 */ 96int gnttab_end_access(grant_ref_t ref) 97{ 98 u16 flags, nflags; 99 100 BUG_ON(ref >= NR_GRANT_ENTRIES || ref < NR_RESERVED_ENTRIES); 101 102 nflags = gnttab_table[ref].flags; 103 do { 104 flags = nflags; 105 if ((flags) & (GTF_reading | GTF_writing)) { 106 printf("WARNING: g.e. still in use! (%x)\n", flags); 107 return 0; 108 } 109 } while ((nflags = synch_cmpxchg(&gnttab_table[ref].flags, flags, 0)) != 110 flags); 111 112 put_free_entry(ref); 113 return 1; 114} 115 116grant_ref_t gnttab_alloc_and_grant(void **map) 117{ 118 unsigned long mfn; 119 grant_ref_t gref; 120 121 *map = (void *)memalign(PAGE_SIZE, PAGE_SIZE); 122 mfn = virt_to_mfn(*map); 123 gref = gnttab_grant_access(0, mfn, 0); 124 return gref; 125} 126 127static const char * const gnttabop_error_msgs[] = GNTTABOP_error_msgs; 128 129const char *gnttabop_error(int16_t status) 130{ 131 status = -status; 132 if (status < 0 || status >= ARRAY_SIZE(gnttabop_error_msgs)) 133 return "bad status"; 134 else 135 return gnttabop_error_msgs[status]; 136} 137 138/* Get Xen's suggested physical page assignments for the grant table. */ 139void get_gnttab_base(phys_addr_t *gnttab_base, phys_size_t *gnttab_sz) 140{ 141 const void *blob = gd->fdt_blob; 142 struct fdt_resource res; 143 int mem; 144 145 mem = fdt_node_offset_by_compatible(blob, -1, "xen,xen"); 146 if (mem < 0) { 147 printf("No xen,xen compatible found\n"); 148 BUG(); 149 } 150 151 mem = fdt_get_resource(blob, mem, "reg", 0, &res); 152 if (mem == -FDT_ERR_NOTFOUND) { 153 printf("No grant table base in the device tree\n"); 154 BUG(); 155 } 156 157 *gnttab_base = (phys_addr_t)res.start; 158 if (gnttab_sz) 159 *gnttab_sz = (phys_size_t)(res.end - res.start + 1); 160 161 debug("FDT suggests grant table base at %llx\n", 162 *gnttab_base); 163} 164 165void init_gnttab(void) 166{ 167 struct xen_add_to_physmap xatp; 168 struct gnttab_setup_table setup; 169 xen_pfn_t frames[NR_GRANT_FRAMES]; 170 int i, rc; 171 172 debug("%s\n", __func__); 173 174 for (i = NR_RESERVED_ENTRIES; i < NR_GRANT_ENTRIES; i++) 175 put_free_entry(i); 176 177 get_gnttab_base((phys_addr_t *)&gnttab_table, NULL); 178 179 for (i = 0; i < NR_GRANT_FRAMES; i++) { 180 xatp.domid = DOMID_SELF; 181 xatp.size = 0; 182 xatp.space = XENMAPSPACE_grant_table; 183 xatp.idx = i; 184 xatp.gpfn = PFN_DOWN((unsigned long)gnttab_table) + i; 185 rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp); 186 if (rc) 187 printf("XENMEM_add_to_physmap failed; status = %d\n", 188 rc); 189 BUG_ON(rc != 0); 190 } 191 192 setup.dom = DOMID_SELF; 193 setup.nr_frames = NR_GRANT_FRAMES; 194 set_xen_guest_handle(setup.frame_list, frames); 195} 196 197void fini_gnttab(void) 198{ 199 struct xen_remove_from_physmap xrtp; 200 struct gnttab_setup_table setup; 201 int i, rc; 202 203 debug("%s\n", __func__); 204 205 for (i = 0; i < NR_GRANT_FRAMES; i++) { 206 xrtp.domid = DOMID_SELF; 207 xrtp.gpfn = PFN_DOWN((unsigned long)gnttab_table) + i; 208 rc = HYPERVISOR_memory_op(XENMEM_remove_from_physmap, &xrtp); 209 if (rc) 210 printf("XENMEM_remove_from_physmap failed; status = %d\n", 211 rc); 212 BUG_ON(rc != 0); 213 } 214 215 setup.dom = DOMID_SELF; 216 setup.nr_frames = 0; 217} 218