xref: /qemu/hw/i386/kvm/xen_gnttab.c (revision 28b7ae94a21d37f38f7b68a9f40fa521144898a6)
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