@samitouri / QOSamiQemu / commits / 83d1d9a49e

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