1 /* 2 * QEMU Xen emulation: Grant table support 3 * 4 * Copyright © 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 5 * 6 * Authors: David Woodhouse <dwmw2@infradead.org> 7 * 8 * This work is licensed under the terms of the GNU GPL, version 2 or later. 9 * See the COPYING file in the top-level directory. 10 */ 11 12 #include "qemu/osdep.h" 13 #include "qemu/host-utils.h" 14 #include "qemu/module.h" 15 #include "qemu/lockable.h" 16 #include "qemu/main-loop.h" 17 #include "qapi/error.h" 18 #include "qom/object.h" 19 #include "exec/target_page.h" 20 #include "exec/address-spaces.h" 21 #include "migration/vmstate.h" 22 23 #include "hw/sysbus.h" 24 #include "hw/xen/xen.h" 25 #include "xen_overlay.h" 26 #include "xen_gnttab.h" 27 28 #include "sysemu/kvm.h" 29 #include "sysemu/kvm_xen.h" 30 31 #include "hw/xen/interface/memory.h" 32 #include "hw/xen/interface/grant_table.h" 33 34 #define TYPE_XEN_GNTTAB "xen-gnttab" 35 OBJECT_DECLARE_SIMPLE_TYPE(XenGnttabState, XEN_GNTTAB) 36 37 #define XEN_PAGE_SHIFT 12 38 #define XEN_PAGE_SIZE (1ULL << XEN_PAGE_SHIFT) 39 40 #define ENTRIES_PER_FRAME_V1 (XEN_PAGE_SIZE / sizeof(grant_entry_v1_t)) 41 42 struct XenGnttabState { 43 /*< private >*/ 44 SysBusDevice busdev; 45 /*< public >*/ 46 47 QemuMutex gnt_lock; 48 49 uint32_t nr_frames; 50 uint32_t max_frames; 51 52 union { 53 grant_entry_v1_t *v1; 54 /* Theoretically, v2 support could be added here. */ 55 } entries; 56 57 MemoryRegion gnt_frames; 58 MemoryRegion *gnt_aliases; 59 uint64_t *gnt_frame_gpas; 60 }; 61 62 struct XenGnttabState *xen_gnttab_singleton; 63 64 static void xen_gnttab_realize(DeviceState *dev, Error **errp) 65 { 66 XenGnttabState *s = XEN_GNTTAB(dev); 67 int i; 68 69 if (xen_mode != XEN_EMULATE) { 70 error_setg(errp, "Xen grant table support is for Xen emulation"); 71 return; 72 } 73 s->nr_frames = 0; 74 s->max_frames = kvm_xen_get_gnttab_max_frames(); 75 memory_region_init_ram(&s->gnt_frames, OBJECT(dev), "xen:grant_table", 76 XEN_PAGE_SIZE * s->max_frames, &error_abort); 77 memory_region_set_enabled(&s->gnt_frames, true); 78 s->entries.v1 = memory_region_get_ram_ptr(&s->gnt_frames); 79 memset(s->entries.v1, 0, XEN_PAGE_SIZE * s->max_frames); 80 81 /* Create individual page-sizes aliases for overlays */ 82 s->gnt_aliases = (void *)g_new0(MemoryRegion, s->max_frames); 83 s->gnt_frame_gpas = (void *)g_new(uint64_t, s->max_frames); 84 for (i = 0; i < s->max_frames; i++) { 85 memory_region_init_alias(&s->gnt_aliases[i], OBJECT(dev), 86 NULL, &s->gnt_frames, 87 i * XEN_PAGE_SIZE, XEN_PAGE_SIZE); 88 s->gnt_frame_gpas[i] = INVALID_GPA; 89 } 90 91 qemu_mutex_init(&s->gnt_lock); 92 93 xen_gnttab_singleton = s; 94 } 95 96 static int xen_gnttab_post_load(void *opaque, int version_id) 97 { 98 XenGnttabState *s = XEN_GNTTAB(opaque); 99 uint32_t i; 100 101 for (i = 0; i < s->nr_frames; i++) { 102 if (s->gnt_frame_gpas[i] != INVALID_GPA) { 103 xen_overlay_do_map_page(&s->gnt_aliases[i], s->gnt_frame_gpas[i]); 104 } 105 } 106 return 0; 107 } 108 109 static bool xen_gnttab_is_needed(void *opaque) 110 { 111 return xen_mode == XEN_EMULATE; 112 } 113 114 static const VMStateDescription xen_gnttab_vmstate = { 115 .name = "xen_gnttab", 116 .version_id = 1, 117 .minimum_version_id = 1, 118 .needed = xen_gnttab_is_needed, 119 .post_load = xen_gnttab_post_load, 120 .fields = (VMStateField[]) { 121 VMSTATE_UINT32(nr_frames, XenGnttabState), 122 VMSTATE_VARRAY_UINT32(gnt_frame_gpas, XenGnttabState, nr_frames, 0, 123 vmstate_info_uint64, uint64_t), 124 VMSTATE_END_OF_LIST() 125 } 126 }; 127 128 static void xen_gnttab_class_init(ObjectClass *klass, void *data) 129 { 130 DeviceClass *dc = DEVICE_CLASS(klass); 131 132 dc->realize = xen_gnttab_realize; 133 dc->vmsd = &xen_gnttab_vmstate; 134 } 135 136 static const TypeInfo xen_gnttab_info = { 137 .name = TYPE_XEN_GNTTAB, 138 .parent = TYPE_SYS_BUS_DEVICE, 139 .instance_size = sizeof(XenGnttabState), 140 .class_init = xen_gnttab_class_init, 141 }; 142 143 void xen_gnttab_create(void) 144 { 145 xen_gnttab_singleton = XEN_GNTTAB(sysbus_create_simple(TYPE_XEN_GNTTAB, 146 -1, NULL)); 147 } 148 149 static void xen_gnttab_register_types(void) 150 { 151 type_register_static(&xen_gnttab_info); 152 } 153 154 type_init(xen_gnttab_register_types) 155 156 int xen_gnttab_map_page(uint64_t idx, uint64_t gfn) 157 { 158 XenGnttabState *s = xen_gnttab_singleton; 159 uint64_t gpa = gfn << XEN_PAGE_SHIFT; 160 161 if (!s) { 162 return -ENOTSUP; 163 } 164 165 if (idx >= s->max_frames) { 166 return -EINVAL; 167 } 168 169 QEMU_IOTHREAD_LOCK_GUARD(); 170 QEMU_LOCK_GUARD(&s->gnt_lock); 171 172 xen_overlay_do_map_page(&s->gnt_aliases[idx], gpa); 173 174 s->gnt_frame_gpas[idx] = gpa; 175 176 if (s->nr_frames <= idx) { 177 s->nr_frames = idx + 1; 178 } 179 180 return 0; 181 } 182 183 int xen_gnttab_set_version_op(struct gnttab_set_version *set) 184 { 185 int ret; 186 187 switch (set->version) { 188 case 1: 189 ret = 0; 190 break; 191 192 case 2: 193 /* Behave as before set_version was introduced. */ 194 ret = -ENOSYS; 195 break; 196 197 default: 198 ret = -EINVAL; 199 } 200 201 set->version = 1; 202 return ret; 203 } 204 205 int xen_gnttab_get_version_op(struct gnttab_get_version *get) 206 { 207 if (get->dom != DOMID_SELF && get->dom != xen_domid) { 208 return -ESRCH; 209 } 210 211 get->version = 1; 212 return 0; 213 } 214 215 int xen_gnttab_query_size_op(struct gnttab_query_size *size) 216 { 217 XenGnttabState *s = xen_gnttab_singleton; 218 219 if (!s) { 220 return -ENOTSUP; 221 } 222 223 if (size->dom != DOMID_SELF && size->dom != xen_domid) { 224 size->status = GNTST_bad_domain; 225 return 0; 226 } 227 228 size->status = GNTST_okay; 229 size->nr_frames = s->nr_frames; 230 size->max_nr_frames = s->max_frames; 231 return 0; 232 } 233