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 25 static struct gnttab_vm_area { 26 struct vm_struct *area; 27 pte_t **ptes; 28 } gnttab_shared_vm_area, gnttab_status_vm_area; 29 30 int arch_gnttab_map_shared(unsigned long *frames, unsigned long nr_gframes, 31 unsigned long max_nr_gframes, 32 void **__shared) 33 { 34 void *shared = *__shared; 35 unsigned long addr; 36 unsigned long i; 37 38 if (shared == NULL) 39 *__shared = shared = gnttab_shared_vm_area.area->addr; 40 41 addr = (unsigned long)shared; 42 43 for (i = 0; i < nr_gframes; i++) { 44 set_pte_at(&init_mm, addr, gnttab_shared_vm_area.ptes[i], 45 mfn_pte(frames[i], PAGE_KERNEL)); 46 addr += PAGE_SIZE; 47 } 48 49 return 0; 50 } 51 52 int arch_gnttab_map_status(uint64_t *frames, unsigned long nr_gframes, 53 unsigned long max_nr_gframes, 54 grant_status_t **__shared) 55 { 56 grant_status_t *shared = *__shared; 57 unsigned long addr; 58 unsigned long i; 59 60 if (shared == NULL) 61 *__shared = shared = gnttab_status_vm_area.area->addr; 62 63 addr = (unsigned long)shared; 64 65 for (i = 0; i < nr_gframes; i++) { 66 set_pte_at(&init_mm, addr, gnttab_status_vm_area.ptes[i], 67 mfn_pte(frames[i], PAGE_KERNEL)); 68 addr += PAGE_SIZE; 69 } 70 71 return 0; 72 } 73 74 void arch_gnttab_unmap(void *shared, unsigned long nr_gframes) 75 { 76 pte_t **ptes; 77 unsigned long addr; 78 unsigned long i; 79 80 if (shared == gnttab_status_vm_area.area->addr) 81 ptes = gnttab_status_vm_area.ptes; 82 else 83 ptes = gnttab_shared_vm_area.ptes; 84 85 addr = (unsigned long)shared; 86 87 for (i = 0; i < nr_gframes; i++) { 88 set_pte_at(&init_mm, addr, ptes[i], __pte(0)); 89 addr += PAGE_SIZE; 90 } 91 } 92 93 static int arch_gnttab_valloc(struct gnttab_vm_area *area, unsigned nr_frames) 94 { 95 area->ptes = kmalloc_array(nr_frames, sizeof(*area->ptes), GFP_KERNEL); 96 if (area->ptes == NULL) 97 return -ENOMEM; 98 99 area->area = alloc_vm_area(PAGE_SIZE * nr_frames, area->ptes); 100 if (area->area == NULL) { 101 kfree(area->ptes); 102 return -ENOMEM; 103 } 104 105 return 0; 106 } 107 108 static void arch_gnttab_vfree(struct gnttab_vm_area *area) 109 { 110 free_vm_area(area->area); 111 kfree(area->ptes); 112 } 113 114 int arch_gnttab_init(unsigned long nr_shared, unsigned long nr_status) 115 { 116 int ret; 117 118 if (!xen_pv_domain()) 119 return 0; 120 121 ret = arch_gnttab_valloc(&gnttab_shared_vm_area, nr_shared); 122 if (ret < 0) 123 return ret; 124 125 /* 126 * Always allocate the space for the status frames in case 127 * we're migrated to a host with V2 support. 128 */ 129 ret = arch_gnttab_valloc(&gnttab_status_vm_area, nr_status); 130 if (ret < 0) 131 goto err; 132 133 return 0; 134 err: 135 arch_gnttab_vfree(&gnttab_shared_vm_area); 136 return -ENOMEM; 137 } 138 139 #ifdef CONFIG_XEN_PVH 140 #include <xen/events.h> 141 #include <xen/xen-ops.h> 142 static int __init xen_pvh_gnttab_setup(void) 143 { 144 if (!xen_pvh_domain()) 145 return -ENODEV; 146 147 xen_auto_xlat_grant_frames.count = gnttab_max_grant_frames(); 148 149 return xen_xlate_map_ballooned_pages(&xen_auto_xlat_grant_frames.pfn, 150 &xen_auto_xlat_grant_frames.vaddr, 151 xen_auto_xlat_grant_frames.count); 152 } 153 /* Call it _before_ __gnttab_init as we need to initialize the 154 * xen_auto_xlat_grant_frames first. */ 155 core_initcall(xen_pvh_gnttab_setup); 156 #endif 157