uboot/drivers/xen/gnttab.c
<<
>>
Prefs
   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
 219