xref: /openbmc/qemu/hw/i386/kvm/xen_overlay.c (revision e53c136f)
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 
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. */
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 
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 
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 
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 
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 
149 static void xen_overlay_reset(DeviceState *dev)
150 {
151     kvm_xen_soft_reset();
152 }
153 
154 static void xen_overlay_class_init(ObjectClass *klass, void *data)
155 {
156     DeviceClass *dc = DEVICE_CLASS(klass);
157 
158     device_class_set_legacy_reset(dc, 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 
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 
181 static void xen_overlay_register_types(void)
182 {
183     type_register_static(&xen_overlay_info);
184 }
185 
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 
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 
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 
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 
269 bool xen_is_long_mode(void)
270 {
271     return xen_overlay_singleton && xen_overlay_singleton->long_mode;
272 }
273