1 /* 2 * QEMU Xen emulation: Shared/overlay pages 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/main-loop.h" 16 #include "qapi/error.h" 17 #include "qom/object.h" 18 #include "exec/target_page.h" 19 #include "exec/address-spaces.h" 20 #include "migration/vmstate.h" 21 22 #include "hw/sysbus.h" 23 #include "hw/xen/xen.h" 24 #include "xen_overlay.h" 25 26 #include "sysemu/kvm.h" 27 #include "sysemu/kvm_xen.h" 28 #include <linux/kvm.h> 29 30 #include "hw/xen/interface/memory.h" 31 32 33 #define TYPE_XEN_OVERLAY "xen-overlay" 34 OBJECT_DECLARE_SIMPLE_TYPE(XenOverlayState, XEN_OVERLAY) 35 36 #define XEN_PAGE_SHIFT 12 37 #define XEN_PAGE_SIZE (1ULL << XEN_PAGE_SHIFT) 38 39 struct XenOverlayState { 40 /*< private >*/ 41 SysBusDevice busdev; 42 /*< public >*/ 43 44 MemoryRegion shinfo_mem; 45 void *shinfo_ptr; 46 uint64_t shinfo_gpa; 47 }; 48 49 struct XenOverlayState *xen_overlay_singleton; 50 51 static void xen_overlay_do_map_page(MemoryRegion *page, uint64_t gpa) 52 { 53 /* 54 * Xen allows guests to map the same page as many times as it likes 55 * into guest physical frames. We don't, because it would be hard 56 * to track and restore them all. One mapping of each page is 57 * perfectly sufficient for all known guests... and we've tested 58 * that theory on a few now in other implementations. dwmw2. 59 */ 60 if (memory_region_is_mapped(page)) { 61 if (gpa == INVALID_GPA) { 62 memory_region_del_subregion(get_system_memory(), page); 63 } else { 64 /* Just move it */ 65 memory_region_set_address(page, gpa); 66 } 67 } else if (gpa != INVALID_GPA) { 68 memory_region_add_subregion_overlap(get_system_memory(), gpa, page, 0); 69 } 70 } 71 72 /* KVM is the only existing back end for now. Let's not overengineer it yet. */ 73 static int xen_overlay_set_be_shinfo(uint64_t gfn) 74 { 75 struct kvm_xen_hvm_attr xa = { 76 .type = KVM_XEN_ATTR_TYPE_SHARED_INFO, 77 .u.shared_info.gfn = gfn, 78 }; 79 80 return kvm_vm_ioctl(kvm_state, KVM_XEN_HVM_SET_ATTR, &xa); 81 } 82 83 84 static void xen_overlay_realize(DeviceState *dev, Error **errp) 85 { 86 XenOverlayState *s = XEN_OVERLAY(dev); 87 88 if (xen_mode != XEN_EMULATE) { 89 error_setg(errp, "Xen overlay page support is for Xen emulation"); 90 return; 91 } 92 93 memory_region_init_ram(&s->shinfo_mem, OBJECT(dev), "xen:shared_info", 94 XEN_PAGE_SIZE, &error_abort); 95 memory_region_set_enabled(&s->shinfo_mem, true); 96 97 s->shinfo_ptr = memory_region_get_ram_ptr(&s->shinfo_mem); 98 s->shinfo_gpa = INVALID_GPA; 99 memset(s->shinfo_ptr, 0, XEN_PAGE_SIZE); 100 } 101 102 static int xen_overlay_post_load(void *opaque, int version_id) 103 { 104 XenOverlayState *s = opaque; 105 106 if (s->shinfo_gpa != INVALID_GPA) { 107 xen_overlay_do_map_page(&s->shinfo_mem, s->shinfo_gpa); 108 xen_overlay_set_be_shinfo(s->shinfo_gpa >> XEN_PAGE_SHIFT); 109 } 110 111 return 0; 112 } 113 114 static bool xen_overlay_is_needed(void *opaque) 115 { 116 return xen_mode == XEN_EMULATE; 117 } 118 119 static const VMStateDescription xen_overlay_vmstate = { 120 .name = "xen_overlay", 121 .version_id = 1, 122 .minimum_version_id = 1, 123 .needed = xen_overlay_is_needed, 124 .post_load = xen_overlay_post_load, 125 .fields = (VMStateField[]) { 126 VMSTATE_UINT64(shinfo_gpa, XenOverlayState), 127 VMSTATE_END_OF_LIST() 128 } 129 }; 130 131 static void xen_overlay_reset(DeviceState *dev) 132 { 133 kvm_xen_soft_reset(); 134 } 135 136 static void xen_overlay_class_init(ObjectClass *klass, void *data) 137 { 138 DeviceClass *dc = DEVICE_CLASS(klass); 139 140 dc->reset = xen_overlay_reset; 141 dc->realize = xen_overlay_realize; 142 dc->vmsd = &xen_overlay_vmstate; 143 } 144 145 static const TypeInfo xen_overlay_info = { 146 .name = TYPE_XEN_OVERLAY, 147 .parent = TYPE_SYS_BUS_DEVICE, 148 .instance_size = sizeof(XenOverlayState), 149 .class_init = xen_overlay_class_init, 150 }; 151 152 void xen_overlay_create(void) 153 { 154 xen_overlay_singleton = XEN_OVERLAY(sysbus_create_simple(TYPE_XEN_OVERLAY, 155 -1, NULL)); 156 157 /* If xen_domid wasn't explicitly set, at least make sure it isn't zero. */ 158 if (xen_domid == DOMID_QEMU) { 159 xen_domid = 1; 160 }; 161 } 162 163 static void xen_overlay_register_types(void) 164 { 165 type_register_static(&xen_overlay_info); 166 } 167 168 type_init(xen_overlay_register_types) 169 170 int xen_overlay_map_shinfo_page(uint64_t gpa) 171 { 172 XenOverlayState *s = xen_overlay_singleton; 173 int ret; 174 175 if (!s) { 176 return -ENOENT; 177 } 178 179 assert(qemu_mutex_iothread_locked()); 180 181 if (s->shinfo_gpa) { 182 /* If removing shinfo page, turn the kernel magic off first */ 183 ret = xen_overlay_set_be_shinfo(INVALID_GFN); 184 if (ret) { 185 return ret; 186 } 187 } 188 189 xen_overlay_do_map_page(&s->shinfo_mem, gpa); 190 if (gpa != INVALID_GPA) { 191 ret = xen_overlay_set_be_shinfo(gpa >> XEN_PAGE_SHIFT); 192 if (ret) { 193 return ret; 194 } 195 } 196 s->shinfo_gpa = gpa; 197 198 return 0; 199 } 200 201 void *xen_overlay_get_shinfo_ptr(void) 202 { 203 XenOverlayState *s = xen_overlay_singleton; 204 205 if (!s) { 206 return NULL; 207 } 208 209 return s->shinfo_ptr; 210 } 211