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 bool long_mode;
48 };
49
50 struct XenOverlayState *xen_overlay_singleton;
51
xen_overlay_do_map_page(MemoryRegion * page,uint64_t gpa)52 void xen_overlay_do_map_page(MemoryRegion *page, uint64_t gpa)
53 {
54 /*
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.
60 */
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);
67 }
68 } else if (gpa != INVALID_GPA) {
69 memory_region_add_subregion_overlap(get_system_memory(), gpa, page, 0);
70 }
71 }
72
73 /* KVM is the only existing back end for now. Let's not overengineer it yet. */
xen_overlay_set_be_shinfo(uint64_t gfn)74 static int xen_overlay_set_be_shinfo(uint64_t gfn)
75 {
76 struct kvm_xen_hvm_attr xa = {
77 .type = KVM_XEN_ATTR_TYPE_SHARED_INFO,
78 .u.shared_info.gfn = gfn,
79 };
80
81 return kvm_vm_ioctl(kvm_state, KVM_XEN_HVM_SET_ATTR, &xa);
82 }
83
84
xen_overlay_realize(DeviceState * dev,Error ** errp)85 static void xen_overlay_realize(DeviceState *dev, Error **errp)
86 {
87 XenOverlayState *s = XEN_OVERLAY(dev);
88
89 if (xen_mode != XEN_EMULATE) {
90 error_setg(errp, "Xen overlay page support is for Xen emulation");
91 return;
92 }
93
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);
97
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);
102 }
103
xen_overlay_pre_save(void * opaque)104 static int xen_overlay_pre_save(void *opaque)
105 {
106 /*
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.
111 */
112 return xen_sync_long_mode();
113 }
114
xen_overlay_post_load(void * opaque,int version_id)115 static int xen_overlay_post_load(void *opaque, int version_id)
116 {
117 XenOverlayState *s = opaque;
118
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);
122 }
123 if (s->long_mode) {
124 xen_set_long_mode(true);
125 }
126
127 return 0;
128 }
129
xen_overlay_is_needed(void * opaque)130 static bool xen_overlay_is_needed(void *opaque)
131 {
132 return xen_mode == XEN_EMULATE;
133 }
134
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()
146 }
147 };
148
xen_overlay_reset(DeviceState * dev)149 static void xen_overlay_reset(DeviceState *dev)
150 {
151 kvm_xen_soft_reset();
152 }
153
xen_overlay_class_init(ObjectClass * klass,void * data)154 static void xen_overlay_class_init(ObjectClass *klass, void *data)
155 {
156 DeviceClass *dc = DEVICE_CLASS(klass);
157
158 dc->reset = xen_overlay_reset;
159 dc->realize = xen_overlay_realize;
160 dc->vmsd = &xen_overlay_vmstate;
161 }
162
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,
168 };
169
xen_overlay_create(void)170 void xen_overlay_create(void)
171 {
172 xen_overlay_singleton = XEN_OVERLAY(sysbus_create_simple(TYPE_XEN_OVERLAY,
173 -1, NULL));
174
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;
178 };
179 }
180
xen_overlay_register_types(void)181 static void xen_overlay_register_types(void)
182 {
183 type_register_static(&xen_overlay_info);
184 }
185
type_init(xen_overlay_register_types)186 type_init(xen_overlay_register_types)
187
188 int xen_overlay_map_shinfo_page(uint64_t gpa)
189 {
190 XenOverlayState *s = xen_overlay_singleton;
191 int ret;
192
193 if (!s) {
194 return -ENOENT;
195 }
196
197 assert(bql_locked());
198
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;
204 }
205 }
206
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;
212 }
213 }
214 s->shinfo_gpa = gpa;
215
216 return 0;
217 }
218
xen_overlay_get_shinfo_ptr(void)219 void *xen_overlay_get_shinfo_ptr(void)
220 {
221 XenOverlayState *s = xen_overlay_singleton;
222
223 if (!s) {
224 return NULL;
225 }
226
227 return s->shinfo_ptr;
228 }
229
xen_sync_long_mode(void)230 int xen_sync_long_mode(void)
231 {
232 int ret;
233 struct kvm_xen_hvm_attr xa = {
234 .type = KVM_XEN_ATTR_TYPE_LONG_MODE,
235 };
236
237 if (!xen_overlay_singleton) {
238 return -ENOENT;
239 }
240
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;
244 }
245
246 return ret;
247 }
248
xen_set_long_mode(bool long_mode)249 int xen_set_long_mode(bool long_mode)
250 {
251 int ret;
252 struct kvm_xen_hvm_attr xa = {
253 .type = KVM_XEN_ATTR_TYPE_LONG_MODE,
254 .u.long_mode = long_mode,
255 };
256
257 if (!xen_overlay_singleton) {
258 return -ENOENT;
259 }
260
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;
264 }
265
266 return ret;
267 }
268
xen_is_long_mode(void)269 bool xen_is_long_mode(void)
270 {
271 return xen_overlay_singleton && xen_overlay_singleton->long_mode;
272 }
273