Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR MIT
0002 /******************************************************************************
0003  * grant_table.c
0004  * x86 specific part
0005  *
0006  * Granting foreign access to our memory reservation.
0007  *
0008  * Copyright (c) 2005-2006, Christopher Clark
0009  * Copyright (c) 2004-2005, K A Fraser
0010  * Copyright (c) 2008 Isaku Yamahata <yamahata at valinux co jp>
0011  *                    VA Linux Systems Japan. Split out x86 specific part.
0012  */
0013 
0014 #include <linux/sched.h>
0015 #include <linux/mm.h>
0016 #include <linux/slab.h>
0017 #include <linux/vmalloc.h>
0018 
0019 #include <xen/interface/xen.h>
0020 #include <xen/page.h>
0021 #include <xen/grant_table.h>
0022 #include <xen/xen.h>
0023 
0024 
0025 static struct gnttab_vm_area {
0026     struct vm_struct *area;
0027     pte_t **ptes;
0028     int idx;
0029 } gnttab_shared_vm_area, gnttab_status_vm_area;
0030 
0031 int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes,
0032                unsigned long max_nr_gframes,
0033                void **__shared)
0034 {
0035     void *shared = *__shared;
0036     unsigned long addr;
0037     unsigned long i;
0038 
0039     if (shared == NULL)
0040         *__shared = shared = gnttab_shared_vm_area.area->addr;
0041 
0042     addr = (unsigned long)shared;
0043 
0044     for (i = 0; i < nr_gframes; i++) {
0045         set_pte_at(&init_mm, addr, gnttab_shared_vm_area.ptes[i],
0046                mfn_pte(frames[i], PAGE_KERNEL));
0047         addr += PAGE_SIZE;
0048     }
0049 
0050     return 0;
0051 }
0052 
0053 int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes,
0054                unsigned long max_nr_gframes,
0055                grant_status_t **__shared)
0056 {
0057     grant_status_t *shared = *__shared;
0058     unsigned long addr;
0059     unsigned long i;
0060 
0061     if (shared == NULL)
0062         *__shared = shared = gnttab_status_vm_area.area->addr;
0063 
0064     addr = (unsigned long)shared;
0065 
0066     for (i = 0; i < nr_gframes; i++) {
0067         set_pte_at(&init_mm, addr, gnttab_status_vm_area.ptes[i],
0068                mfn_pte(frames[i], PAGE_KERNEL));
0069         addr += PAGE_SIZE;
0070     }
0071 
0072     return 0;
0073 }
0074 
0075 void arch_gnttab_unmap(void *shared, unsigned long nr_gframes)
0076 {
0077     pte_t **ptes;
0078     unsigned long addr;
0079     unsigned long i;
0080 
0081     if (shared == gnttab_status_vm_area.area->addr)
0082         ptes = gnttab_status_vm_area.ptes;
0083     else
0084         ptes = gnttab_shared_vm_area.ptes;
0085 
0086     addr = (unsigned long)shared;
0087 
0088     for (i = 0; i < nr_gframes; i++) {
0089         set_pte_at(&init_mm, addr, ptes[i], __pte(0));
0090         addr += PAGE_SIZE;
0091     }
0092 }
0093 
0094 static int gnttab_apply(pte_t *pte, unsigned long addr, void *data)
0095 {
0096     struct gnttab_vm_area *area = data;
0097 
0098     area->ptes[area->idx++] = pte;
0099     return 0;
0100 }
0101 
0102 static int arch_gnttab_valloc(struct gnttab_vm_area *area, unsigned nr_frames)
0103 {
0104     area->ptes = kmalloc_array(nr_frames, sizeof(*area->ptes), GFP_KERNEL);
0105     if (area->ptes == NULL)
0106         return -ENOMEM;
0107     area->area = get_vm_area(PAGE_SIZE * nr_frames, VM_IOREMAP);
0108     if (!area->area)
0109         goto out_free_ptes;
0110     if (apply_to_page_range(&init_mm, (unsigned long)area->area->addr,
0111             PAGE_SIZE * nr_frames, gnttab_apply, area))
0112         goto out_free_vm_area;
0113     return 0;
0114 out_free_vm_area:
0115     free_vm_area(area->area);
0116 out_free_ptes:
0117     kfree(area->ptes);
0118     return -ENOMEM;
0119 }
0120 
0121 static void arch_gnttab_vfree(struct gnttab_vm_area *area)
0122 {
0123     free_vm_area(area->area);
0124     kfree(area->ptes);
0125 }
0126 
0127 int arch_gnttab_init(unsigned long nr_shared, unsigned long nr_status)
0128 {
0129     int ret;
0130 
0131     if (!xen_pv_domain())
0132         return 0;
0133 
0134     ret = arch_gnttab_valloc(&gnttab_shared_vm_area, nr_shared);
0135     if (ret < 0)
0136         return ret;
0137 
0138     /*
0139      * Always allocate the space for the status frames in case
0140      * we're migrated to a host with V2 support.
0141      */
0142     ret = arch_gnttab_valloc(&gnttab_status_vm_area, nr_status);
0143     if (ret < 0)
0144         goto err;
0145 
0146     return 0;
0147 err:
0148     arch_gnttab_vfree(&gnttab_shared_vm_area);
0149     return -ENOMEM;
0150 }
0151 
0152 #ifdef CONFIG_XEN_PVH
0153 #include <xen/events.h>
0154 #include <xen/xen-ops.h>
0155 static int __init xen_pvh_gnttab_setup(void)
0156 {
0157     if (!xen_pvh_domain())
0158         return -ENODEV;
0159 
0160     xen_auto_xlat_grant_frames.count = gnttab_max_grant_frames();
0161 
0162     return xen_xlate_map_ballooned_pages(&xen_auto_xlat_grant_frames.pfn,
0163                          &xen_auto_xlat_grant_frames.vaddr,
0164                          xen_auto_xlat_grant_frames.count);
0165 }
0166 /* Call it _before_ __gnttab_init as we need to initialize the
0167  * xen_auto_xlat_grant_frames first. */
0168 core_initcall(xen_pvh_gnttab_setup);
0169 #endif