Merge tag 'v9.0.0-rc3'
[qemu/ar7.git] / hw / i386 / kvm / xen_overlay.c
blobc68e78ac5ce2eded9ea56c0b3a788d6b2ea8b81b
1 /*
2 * QEMU Xen emulation: Shared/overlay pages support
4 * Copyright © 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
6 * Authors: David Woodhouse <dwmw2@infradead.org>
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.
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"
22 #include "hw/sysbus.h"
23 #include "hw/xen/xen.h"
24 #include "xen_overlay.h"
26 #include "sysemu/kvm.h"
27 #include "sysemu/kvm_xen.h"
28 #include <linux/kvm.h>
30 #include "hw/xen/interface/memory.h"
33 #define TYPE_XEN_OVERLAY "xen-overlay"
34 OBJECT_DECLARE_SIMPLE_TYPE(XenOverlayState, XEN_OVERLAY)
36 #define XEN_PAGE_SHIFT 12
37 #define XEN_PAGE_SIZE (1ULL << XEN_PAGE_SHIFT)
39 struct XenOverlayState {
40 /*< private >*/
41 SysBusDevice busdev;
42 /*< public >*/
44 MemoryRegion shinfo_mem;
45 void *shinfo_ptr;
46 uint64_t shinfo_gpa;
47 bool long_mode;
50 struct XenOverlayState *xen_overlay_singleton;
52 void xen_overlay_do_map_page(MemoryRegion *page, uint64_t gpa)
55 * Xen allows guests to map the same page as many times as it likes
56 * into guest physical frames. We don't, because it would be hard
57 * to track and restore them all. One mapping of each page is
58 * perfectly sufficient for all known guests... and we've tested
59 * that theory on a few now in other implementations. dwmw2.
61 if (memory_region_is_mapped(page)) {
62 if (gpa == INVALID_GPA) {
63 memory_region_del_subregion(get_system_memory(), page);
64 } else {
65 /* Just move it */
66 memory_region_set_address(page, gpa);
68 } else if (gpa != INVALID_GPA) {
69 memory_region_add_subregion_overlap(get_system_memory(), gpa, page, 0);
73 /* KVM is the only existing back end for now. Let's not overengineer it yet. */
74 static int xen_overlay_set_be_shinfo(uint64_t gfn)
76 struct kvm_xen_hvm_attr xa = {
77 .type = KVM_XEN_ATTR_TYPE_SHARED_INFO,
78 .u.shared_info.gfn = gfn,
81 return kvm_vm_ioctl(kvm_state, KVM_XEN_HVM_SET_ATTR, &xa);
85 static void xen_overlay_realize(DeviceState *dev, Error **errp)
87 XenOverlayState *s = XEN_OVERLAY(dev);
89 if (xen_mode != XEN_EMULATE) {
90 error_setg(errp, "Xen overlay page support is for Xen emulation");
91 return;
94 memory_region_init_ram(&s->shinfo_mem, OBJECT(dev), "xen:shared_info",
95 XEN_PAGE_SIZE, &error_abort);
96 memory_region_set_enabled(&s->shinfo_mem, true);
98 s->shinfo_ptr = memory_region_get_ram_ptr(&s->shinfo_mem);
99 s->shinfo_gpa = INVALID_GPA;
100 s->long_mode = false;
101 memset(s->shinfo_ptr, 0, XEN_PAGE_SIZE);
104 static int xen_overlay_pre_save(void *opaque)
107 * Fetch the kernel's idea of long_mode to avoid the race condition
108 * where the guest has set the hypercall page up in 64-bit mode but
109 * not yet made a hypercall by the time migration happens, so qemu
110 * hasn't yet noticed.
112 return xen_sync_long_mode();
115 static int xen_overlay_post_load(void *opaque, int version_id)
117 XenOverlayState *s = opaque;
119 if (s->shinfo_gpa != INVALID_GPA) {
120 xen_overlay_do_map_page(&s->shinfo_mem, s->shinfo_gpa);
121 xen_overlay_set_be_shinfo(s->shinfo_gpa >> XEN_PAGE_SHIFT);
123 if (s->long_mode) {
124 xen_set_long_mode(true);
127 return 0;
130 static bool xen_overlay_is_needed(void *opaque)
132 return xen_mode == XEN_EMULATE;
135 static const VMStateDescription xen_overlay_vmstate = {
136 .name = "xen_overlay",
137 .version_id = 1,
138 .minimum_version_id = 1,
139 .needed = xen_overlay_is_needed,
140 .pre_save = xen_overlay_pre_save,
141 .post_load = xen_overlay_post_load,
142 .fields = (const VMStateField[]) {
143 VMSTATE_UINT64(shinfo_gpa, XenOverlayState),
144 VMSTATE_BOOL(long_mode, XenOverlayState),
145 VMSTATE_END_OF_LIST()
149 static void xen_overlay_reset(DeviceState *dev)
151 kvm_xen_soft_reset();
154 static void xen_overlay_class_init(ObjectClass *klass, void *data)
156 DeviceClass *dc = DEVICE_CLASS(klass);
158 dc->reset = xen_overlay_reset;
159 dc->realize = xen_overlay_realize;
160 dc->vmsd = &xen_overlay_vmstate;
163 static const TypeInfo xen_overlay_info = {
164 .name = TYPE_XEN_OVERLAY,
165 .parent = TYPE_SYS_BUS_DEVICE,
166 .instance_size = sizeof(XenOverlayState),
167 .class_init = xen_overlay_class_init,
170 void xen_overlay_create(void)
172 xen_overlay_singleton = XEN_OVERLAY(sysbus_create_simple(TYPE_XEN_OVERLAY,
173 -1, NULL));
175 /* If xen_domid wasn't explicitly set, at least make sure it isn't zero. */
176 if (xen_domid == DOMID_QEMU) {
177 xen_domid = 1;
181 static void xen_overlay_register_types(void)
183 type_register_static(&xen_overlay_info);
186 type_init(xen_overlay_register_types)
188 int xen_overlay_map_shinfo_page(uint64_t gpa)
190 XenOverlayState *s = xen_overlay_singleton;
191 int ret;
193 if (!s) {
194 return -ENOENT;
197 assert(bql_locked());
199 if (s->shinfo_gpa) {
200 /* If removing shinfo page, turn the kernel magic off first */
201 ret = xen_overlay_set_be_shinfo(INVALID_GFN);
202 if (ret) {
203 return ret;
207 xen_overlay_do_map_page(&s->shinfo_mem, gpa);
208 if (gpa != INVALID_GPA) {
209 ret = xen_overlay_set_be_shinfo(gpa >> XEN_PAGE_SHIFT);
210 if (ret) {
211 return ret;
214 s->shinfo_gpa = gpa;
216 return 0;
219 void *xen_overlay_get_shinfo_ptr(void)
221 XenOverlayState *s = xen_overlay_singleton;
223 if (!s) {
224 return NULL;
227 return s->shinfo_ptr;
230 int xen_sync_long_mode(void)
232 int ret;
233 struct kvm_xen_hvm_attr xa = {
234 .type = KVM_XEN_ATTR_TYPE_LONG_MODE,
237 if (!xen_overlay_singleton) {
238 return -ENOENT;
241 ret = kvm_vm_ioctl(kvm_state, KVM_XEN_HVM_GET_ATTR, &xa);
242 if (!ret) {
243 xen_overlay_singleton->long_mode = xa.u.long_mode;
246 return ret;
249 int xen_set_long_mode(bool long_mode)
251 int ret;
252 struct kvm_xen_hvm_attr xa = {
253 .type = KVM_XEN_ATTR_TYPE_LONG_MODE,
254 .u.long_mode = long_mode,
257 if (!xen_overlay_singleton) {
258 return -ENOENT;
261 ret = kvm_vm_ioctl(kvm_state, KVM_XEN_HVM_SET_ATTR, &xa);
262 if (!ret) {
263 xen_overlay_singleton->long_mode = xa.u.long_mode;
266 return ret;
269 bool xen_is_long_mode(void)
271 return xen_overlay_singleton && xen_overlay_singleton->long_mode;