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