hw/xen: xenpvh: Add prop to enable/disable the mapcache
Add a machine property to enable/disable the mapcache. Default it to enabled for backwards compatibility. Signed-off-by: Edgar E. Iglesias <edgar.iglesias@amd.com> Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
Edgar E. Iglesias committed
Jul 23, 2025 at 14:02 UTC
83d1d9a49e8eb970f87508ae4ce0f222084df365
2 files changed
+124
-11
hw/xen/xen-pvh-common.c
+122
-11
@@ -29,6 +29,69 @@ static const MemoryListener xen_memory_listener = {
29
.priority = MEMORY_LISTENER_PRIORITY_ACCEL,
30
};
31
32
+/*
33
+ * Map foreign RAM in bounded chunks so we don't build a PFN array for the
34
+ * entire guest size (which can be huge for large guests). We reserve a VA
35
+ * range once and then MAP_FIXED each chunk into place.
36
+ */
37
+#define XEN_PVH_MAP_CHUNK_PAGES 65535
38
+
39
+static void *xen_map_guest_ram(XenPVHMachineState *s,
40
+ uint64_t addr, uint64_t size)
41
+{
42
+ size_t total_pages = size >> XC_PAGE_SHIFT;
43
+ size_t chunk_pages = MIN(XEN_PVH_MAP_CHUNK_PAGES, total_pages);
44
+ g_autofree xen_pfn_t *pfns = NULL;
45
+ void *base = NULL;
46
+ size_t offset;
47
+
48
+ if (!total_pages) {
49
+ goto done;
50
+ }
51
+
52
+ base = mmap(NULL, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
53
+ if (base == MAP_FAILED) {
54
+ base = NULL;
55
+ goto done;
56
+ }
57
+
58
+ pfns = g_new0(xen_pfn_t, chunk_pages);
59
+ if (!pfns) {
60
+ munmap(base, size);
61
+ base = NULL;
62
+ goto done;
63
+ }
64
+
65
+ for (offset = 0; offset < total_pages; offset += chunk_pages) {
66
+ size_t num_pages = MIN(chunk_pages, total_pages - offset);
67
+ void *mapped;
68
+ size_t i;
69
+
70
+ for (i = 0; i < num_pages; i++) {
71
+ pfns[i] = (addr >> XC_PAGE_SHIFT) + offset + i;
72
+ }
73
+
74
+ mapped = xenforeignmemory_map2(
75
+ xen_fmem, xen_domid,
76
+ (uint8_t *)base + (offset << XC_PAGE_SHIFT),
77
+ PROT_READ | PROT_WRITE, MAP_FIXED,
78
+ num_pages, pfns, NULL);
79
+ if (!mapped) {
80
+ munmap(base, size);
81
+ base = NULL;
82
+ goto done;
83
+ }
84
+ }
85
+done:
86
+ if (!base) {
87
+ /* We can't recover from this. */
88
+ error_report("FATAL: Failed to foreign-map %" PRIx64 " - %" PRIx64,
89
+ addr, addr + size);
90
+ exit(EXIT_FAILURE);
91
+ }
92
+ return base;
93
+}
94
+
95
static void xen_pvh_init_ram(XenPVHMachineState *s,
96
MemoryRegion *sysmem)
97
{
@@ -45,22 +108,42 @@ static void xen_pvh_init_ram(XenPVHMachineState *s,
108
block_len = s->cfg.ram_high.base + ram_size[1];
109
}
110
48
- memory_region_init_ram(&xen_memory, NULL, "xen.ram", block_len,
49
- &error_fatal);
111
+ if (s->cfg.mapcache) {
112
+ memory_region_init_ram(&xen_memory, NULL, "xen.ram",
113
+ block_len, &error_fatal);
114
+ memory_region_init_alias(&s->ram.low, NULL, "xen.ram.lo", &xen_memory,
115
+ s->cfg.ram_low.base, ram_size[0]);
116
+ if (ram_size[1] > 0) {
117
+ memory_region_init_alias(&s->ram.high, NULL, "xen.ram.hi",
118
+ &xen_memory,
119
+ s->cfg.ram_high.base, ram_size[1]);
120
+ }
121
+ } else {
122
+ void *p;
123
+
124
+ p = xen_map_guest_ram(s, s->cfg.ram_low.base, ram_size[0]);
125
+ memory_region_init_ram_ptr(&s->ram.low, NULL, "xen.ram.lo",
126
+ ram_size[0], p);
127
+ if (ram_size[1] > 0) {
128
+ p = xen_map_guest_ram(s, s->cfg.ram_high.base, ram_size[1]);
129
+ memory_region_init_ram_ptr(&s->ram.high, NULL, "xen.ram.hi",
130
+ ram_size[1], p);
131
+ }
132
+ }
133
51
- memory_region_init_alias(&s->ram.low, NULL, "xen.ram.lo", &xen_memory,
52
- s->cfg.ram_low.base, ram_size[0]);
134
+ /* Map them onto QEMU's address-space. */
135
memory_region_add_subregion(sysmem, s->cfg.ram_low.base, &s->ram.low);
136
if (ram_size[1] > 0) {
55
- memory_region_init_alias(&s->ram.high, NULL, "xen.ram.hi", &xen_memory,
56
- s->cfg.ram_high.base, ram_size[1]);
137
memory_region_add_subregion(sysmem, s->cfg.ram_high.base, &s->ram.high);
138
}
139
60
- /* Setup support for grants. */
61
- memory_region_init_ram(&xen_grants, NULL, "xen.grants", block_len,
62
- &error_fatal);
63
- memory_region_add_subregion(sysmem, XEN_GRANT_ADDR_OFF, &xen_grants);
140
+ /* Grants are only supported when the mapcache is on. */
141
+ if (s->cfg.mapcache) {
142
+ /* Setup support for grants. */
143
+ memory_region_init_ram(&xen_grants, NULL, "xen.grants", block_len,
144
+ &error_fatal);
145
+ memory_region_add_subregion(sysmem, XEN_GRANT_ADDR_OFF, &xen_grants);
146
+ }
147
}
148
149
static void xen_set_irq(void *opaque, int irq, int level)
@@ -203,7 +286,7 @@ static void xen_pvh_init(MachineState *ms)
286
xen_register_ioreq(&s->ioreq, ms->smp.max_cpus,
287
xpc->handle_bufioreq,
288
&xen_memory_listener,
206
- true);
289
+ s->cfg.mapcache);
290
291
if (s->cfg.virtio_mmio_num) {
292
xen_create_virtio_mmio_devices(s);
@@ -285,6 +368,20 @@ XEN_PVH_PROP_MEMMAP(pci_ecam)
368
XEN_PVH_PROP_MEMMAP(pci_mmio)
369
XEN_PVH_PROP_MEMMAP(pci_mmio_high)
370
371
+static void xen_pvh_set_mapcache(Object *obj, bool value, Error **errp)
372
+{
373
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj);
374
+
375
+ xp->cfg.mapcache = value;
376
+}
377
+
378
+static bool xen_pvh_get_mapcache(Object *obj, Error **errp)
379
+{
380
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj);
381
+
382
+ return xp->cfg.mapcache;
383
+}
384
+
385
static void xen_pvh_set_pci_intx_irq_base(Object *obj, Visitor *v,
386
const char *name, void *opaque,
387
Error **errp)
@@ -338,6 +435,12 @@ do { \
435
OC_MEMMAP_PROP_SIZE(c, prop_name, name); \
436
} while (0)
437
438
+ object_class_property_add_bool(oc, "mapcache", xen_pvh_get_mapcache,
439
+ xen_pvh_set_mapcache);
440
+ object_class_property_set_description(oc, "mapcache",
441
+ "Set on/off to enable/disable the "
442
+ "mapcache");
443
+
444
/*
445
* We provide memmap properties to allow Xen to move things to other
446
* addresses for example when users need to accomodate the memory-map
@@ -377,6 +480,13 @@ do { \
480
#endif
481
}
482
483
+static void xen_pvh_instance_init(Object *obj)
484
+{
485
+ XenPVHMachineState *xp = XEN_PVH_MACHINE(obj);
486
+
487
+ xp->cfg.mapcache = true;
488
+}
489
+
490
static void xen_pvh_class_init(ObjectClass *oc, const void *data)
491
{
492
MachineClass *mc = MACHINE_CLASS(oc);
@@ -395,6 +505,7 @@ static const TypeInfo xen_pvh_info = {
505
.parent = TYPE_MACHINE,
506
.abstract = true,
507
.instance_size = sizeof(XenPVHMachineState),
508
+ .instance_init = xen_pvh_instance_init,
509
.class_size = sizeof(XenPVHMachineClass),
510
.class_init = xen_pvh_class_init,
511
};
include/hw/xen/xen-pvh-common.h
+2
@@ -84,6 +84,8 @@ struct XenPVHMachineState {
84
/* PCI */
85
MemMapEntry pci_ecam, pci_mmio, pci_mmio_high;
86
uint32_t pci_intx_irq_base;
87
+
88
+ bool mapcache;
89
} cfg;
90
};
91