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