18d7f2e76SPhilippe Mathieu-Daudé /*
28d7f2e76SPhilippe Mathieu-Daudé * QEMU memory mapping
38d7f2e76SPhilippe Mathieu-Daudé *
48d7f2e76SPhilippe Mathieu-Daudé * Copyright Fujitsu, Corp. 2011, 2012
58d7f2e76SPhilippe Mathieu-Daudé *
68d7f2e76SPhilippe Mathieu-Daudé * Authors:
78d7f2e76SPhilippe Mathieu-Daudé * Wen Congyang <wency@cn.fujitsu.com>
88d7f2e76SPhilippe Mathieu-Daudé *
98d7f2e76SPhilippe Mathieu-Daudé * This work is licensed under the terms of the GNU GPL, version 2 or later.
108d7f2e76SPhilippe Mathieu-Daudé * See the COPYING file in the top-level directory.
118d7f2e76SPhilippe Mathieu-Daudé *
128d7f2e76SPhilippe Mathieu-Daudé */
138d7f2e76SPhilippe Mathieu-Daudé
148d7f2e76SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
15*13c59a0eSYao Xingtao #include "qemu/range.h"
168d7f2e76SPhilippe Mathieu-Daudé #include "qapi/error.h"
178d7f2e76SPhilippe Mathieu-Daudé
188d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/memory_mapping.h"
198d7f2e76SPhilippe Mathieu-Daudé #include "exec/memory.h"
208d7f2e76SPhilippe Mathieu-Daudé #include "exec/address-spaces.h"
218d7f2e76SPhilippe Mathieu-Daudé #include "hw/core/cpu.h"
228d7f2e76SPhilippe Mathieu-Daudé
238d7f2e76SPhilippe Mathieu-Daudé //#define DEBUG_GUEST_PHYS_REGION_ADD
248d7f2e76SPhilippe Mathieu-Daudé
memory_mapping_list_add_mapping_sorted(MemoryMappingList * list,MemoryMapping * mapping)258d7f2e76SPhilippe Mathieu-Daudé static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list,
268d7f2e76SPhilippe Mathieu-Daudé MemoryMapping *mapping)
278d7f2e76SPhilippe Mathieu-Daudé {
288d7f2e76SPhilippe Mathieu-Daudé MemoryMapping *p;
298d7f2e76SPhilippe Mathieu-Daudé
308d7f2e76SPhilippe Mathieu-Daudé QTAILQ_FOREACH(p, &list->head, next) {
318d7f2e76SPhilippe Mathieu-Daudé if (p->phys_addr >= mapping->phys_addr) {
328d7f2e76SPhilippe Mathieu-Daudé QTAILQ_INSERT_BEFORE(p, mapping, next);
338d7f2e76SPhilippe Mathieu-Daudé return;
348d7f2e76SPhilippe Mathieu-Daudé }
358d7f2e76SPhilippe Mathieu-Daudé }
368d7f2e76SPhilippe Mathieu-Daudé QTAILQ_INSERT_TAIL(&list->head, mapping, next);
378d7f2e76SPhilippe Mathieu-Daudé }
388d7f2e76SPhilippe Mathieu-Daudé
create_new_memory_mapping(MemoryMappingList * list,hwaddr phys_addr,hwaddr virt_addr,ram_addr_t length)398d7f2e76SPhilippe Mathieu-Daudé static void create_new_memory_mapping(MemoryMappingList *list,
408d7f2e76SPhilippe Mathieu-Daudé hwaddr phys_addr,
418d7f2e76SPhilippe Mathieu-Daudé hwaddr virt_addr,
428d7f2e76SPhilippe Mathieu-Daudé ram_addr_t length)
438d7f2e76SPhilippe Mathieu-Daudé {
448d7f2e76SPhilippe Mathieu-Daudé MemoryMapping *memory_mapping;
458d7f2e76SPhilippe Mathieu-Daudé
468d7f2e76SPhilippe Mathieu-Daudé memory_mapping = g_new(MemoryMapping, 1);
478d7f2e76SPhilippe Mathieu-Daudé memory_mapping->phys_addr = phys_addr;
488d7f2e76SPhilippe Mathieu-Daudé memory_mapping->virt_addr = virt_addr;
498d7f2e76SPhilippe Mathieu-Daudé memory_mapping->length = length;
508d7f2e76SPhilippe Mathieu-Daudé list->last_mapping = memory_mapping;
518d7f2e76SPhilippe Mathieu-Daudé list->num++;
528d7f2e76SPhilippe Mathieu-Daudé memory_mapping_list_add_mapping_sorted(list, memory_mapping);
538d7f2e76SPhilippe Mathieu-Daudé }
548d7f2e76SPhilippe Mathieu-Daudé
mapping_contiguous(MemoryMapping * map,hwaddr phys_addr,hwaddr virt_addr)558d7f2e76SPhilippe Mathieu-Daudé static inline bool mapping_contiguous(MemoryMapping *map,
568d7f2e76SPhilippe Mathieu-Daudé hwaddr phys_addr,
578d7f2e76SPhilippe Mathieu-Daudé hwaddr virt_addr)
588d7f2e76SPhilippe Mathieu-Daudé {
598d7f2e76SPhilippe Mathieu-Daudé return phys_addr == map->phys_addr + map->length &&
608d7f2e76SPhilippe Mathieu-Daudé virt_addr == map->virt_addr + map->length;
618d7f2e76SPhilippe Mathieu-Daudé }
628d7f2e76SPhilippe Mathieu-Daudé
638d7f2e76SPhilippe Mathieu-Daudé /*
648d7f2e76SPhilippe Mathieu-Daudé * [map->phys_addr, map->phys_addr + map->length) and
658d7f2e76SPhilippe Mathieu-Daudé * [phys_addr, phys_addr + length) have intersection?
668d7f2e76SPhilippe Mathieu-Daudé */
mapping_have_same_region(MemoryMapping * map,hwaddr phys_addr,ram_addr_t length)678d7f2e76SPhilippe Mathieu-Daudé static inline bool mapping_have_same_region(MemoryMapping *map,
688d7f2e76SPhilippe Mathieu-Daudé hwaddr phys_addr,
698d7f2e76SPhilippe Mathieu-Daudé ram_addr_t length)
708d7f2e76SPhilippe Mathieu-Daudé {
718d7f2e76SPhilippe Mathieu-Daudé return !(phys_addr + length < map->phys_addr ||
728d7f2e76SPhilippe Mathieu-Daudé phys_addr >= map->phys_addr + map->length);
738d7f2e76SPhilippe Mathieu-Daudé }
748d7f2e76SPhilippe Mathieu-Daudé
758d7f2e76SPhilippe Mathieu-Daudé /*
768d7f2e76SPhilippe Mathieu-Daudé * [map->phys_addr, map->phys_addr + map->length) and
778d7f2e76SPhilippe Mathieu-Daudé * [phys_addr, phys_addr + length) have intersection. The virtual address in the
788d7f2e76SPhilippe Mathieu-Daudé * intersection are the same?
798d7f2e76SPhilippe Mathieu-Daudé */
mapping_conflict(MemoryMapping * map,hwaddr phys_addr,hwaddr virt_addr)808d7f2e76SPhilippe Mathieu-Daudé static inline bool mapping_conflict(MemoryMapping *map,
818d7f2e76SPhilippe Mathieu-Daudé hwaddr phys_addr,
828d7f2e76SPhilippe Mathieu-Daudé hwaddr virt_addr)
838d7f2e76SPhilippe Mathieu-Daudé {
848d7f2e76SPhilippe Mathieu-Daudé return virt_addr - map->virt_addr != phys_addr - map->phys_addr;
858d7f2e76SPhilippe Mathieu-Daudé }
868d7f2e76SPhilippe Mathieu-Daudé
878d7f2e76SPhilippe Mathieu-Daudé /*
888d7f2e76SPhilippe Mathieu-Daudé * [map->virt_addr, map->virt_addr + map->length) and
898d7f2e76SPhilippe Mathieu-Daudé * [virt_addr, virt_addr + length) have intersection. And the physical address
908d7f2e76SPhilippe Mathieu-Daudé * in the intersection are the same.
918d7f2e76SPhilippe Mathieu-Daudé */
mapping_merge(MemoryMapping * map,hwaddr virt_addr,ram_addr_t length)928d7f2e76SPhilippe Mathieu-Daudé static inline void mapping_merge(MemoryMapping *map,
938d7f2e76SPhilippe Mathieu-Daudé hwaddr virt_addr,
948d7f2e76SPhilippe Mathieu-Daudé ram_addr_t length)
958d7f2e76SPhilippe Mathieu-Daudé {
968d7f2e76SPhilippe Mathieu-Daudé if (virt_addr < map->virt_addr) {
978d7f2e76SPhilippe Mathieu-Daudé map->length += map->virt_addr - virt_addr;
988d7f2e76SPhilippe Mathieu-Daudé map->virt_addr = virt_addr;
998d7f2e76SPhilippe Mathieu-Daudé }
1008d7f2e76SPhilippe Mathieu-Daudé
1018d7f2e76SPhilippe Mathieu-Daudé if ((virt_addr + length) >
1028d7f2e76SPhilippe Mathieu-Daudé (map->virt_addr + map->length)) {
1038d7f2e76SPhilippe Mathieu-Daudé map->length = virt_addr + length - map->virt_addr;
1048d7f2e76SPhilippe Mathieu-Daudé }
1058d7f2e76SPhilippe Mathieu-Daudé }
1068d7f2e76SPhilippe Mathieu-Daudé
memory_mapping_list_add_merge_sorted(MemoryMappingList * list,hwaddr phys_addr,hwaddr virt_addr,ram_addr_t length)1078d7f2e76SPhilippe Mathieu-Daudé void memory_mapping_list_add_merge_sorted(MemoryMappingList *list,
1088d7f2e76SPhilippe Mathieu-Daudé hwaddr phys_addr,
1098d7f2e76SPhilippe Mathieu-Daudé hwaddr virt_addr,
1108d7f2e76SPhilippe Mathieu-Daudé ram_addr_t length)
1118d7f2e76SPhilippe Mathieu-Daudé {
1128d7f2e76SPhilippe Mathieu-Daudé MemoryMapping *memory_mapping, *last_mapping;
1138d7f2e76SPhilippe Mathieu-Daudé
1148d7f2e76SPhilippe Mathieu-Daudé if (QTAILQ_EMPTY(&list->head)) {
1158d7f2e76SPhilippe Mathieu-Daudé create_new_memory_mapping(list, phys_addr, virt_addr, length);
1168d7f2e76SPhilippe Mathieu-Daudé return;
1178d7f2e76SPhilippe Mathieu-Daudé }
1188d7f2e76SPhilippe Mathieu-Daudé
1198d7f2e76SPhilippe Mathieu-Daudé last_mapping = list->last_mapping;
1208d7f2e76SPhilippe Mathieu-Daudé if (last_mapping) {
1218d7f2e76SPhilippe Mathieu-Daudé if (mapping_contiguous(last_mapping, phys_addr, virt_addr)) {
1228d7f2e76SPhilippe Mathieu-Daudé last_mapping->length += length;
1238d7f2e76SPhilippe Mathieu-Daudé return;
1248d7f2e76SPhilippe Mathieu-Daudé }
1258d7f2e76SPhilippe Mathieu-Daudé }
1268d7f2e76SPhilippe Mathieu-Daudé
1278d7f2e76SPhilippe Mathieu-Daudé QTAILQ_FOREACH(memory_mapping, &list->head, next) {
1288d7f2e76SPhilippe Mathieu-Daudé if (mapping_contiguous(memory_mapping, phys_addr, virt_addr)) {
1298d7f2e76SPhilippe Mathieu-Daudé memory_mapping->length += length;
1308d7f2e76SPhilippe Mathieu-Daudé list->last_mapping = memory_mapping;
1318d7f2e76SPhilippe Mathieu-Daudé return;
1328d7f2e76SPhilippe Mathieu-Daudé }
1338d7f2e76SPhilippe Mathieu-Daudé
1348d7f2e76SPhilippe Mathieu-Daudé if (phys_addr + length < memory_mapping->phys_addr) {
1358d7f2e76SPhilippe Mathieu-Daudé /* create a new region before memory_mapping */
1368d7f2e76SPhilippe Mathieu-Daudé break;
1378d7f2e76SPhilippe Mathieu-Daudé }
1388d7f2e76SPhilippe Mathieu-Daudé
1398d7f2e76SPhilippe Mathieu-Daudé if (mapping_have_same_region(memory_mapping, phys_addr, length)) {
1408d7f2e76SPhilippe Mathieu-Daudé if (mapping_conflict(memory_mapping, phys_addr, virt_addr)) {
1418d7f2e76SPhilippe Mathieu-Daudé continue;
1428d7f2e76SPhilippe Mathieu-Daudé }
1438d7f2e76SPhilippe Mathieu-Daudé
1448d7f2e76SPhilippe Mathieu-Daudé /* merge this region into memory_mapping */
1458d7f2e76SPhilippe Mathieu-Daudé mapping_merge(memory_mapping, virt_addr, length);
1468d7f2e76SPhilippe Mathieu-Daudé list->last_mapping = memory_mapping;
1478d7f2e76SPhilippe Mathieu-Daudé return;
1488d7f2e76SPhilippe Mathieu-Daudé }
1498d7f2e76SPhilippe Mathieu-Daudé }
1508d7f2e76SPhilippe Mathieu-Daudé
1518d7f2e76SPhilippe Mathieu-Daudé /* this region can not be merged into any existed memory mapping. */
1528d7f2e76SPhilippe Mathieu-Daudé create_new_memory_mapping(list, phys_addr, virt_addr, length);
1538d7f2e76SPhilippe Mathieu-Daudé }
1548d7f2e76SPhilippe Mathieu-Daudé
memory_mapping_list_free(MemoryMappingList * list)1558d7f2e76SPhilippe Mathieu-Daudé void memory_mapping_list_free(MemoryMappingList *list)
1568d7f2e76SPhilippe Mathieu-Daudé {
1578d7f2e76SPhilippe Mathieu-Daudé MemoryMapping *p, *q;
1588d7f2e76SPhilippe Mathieu-Daudé
1598d7f2e76SPhilippe Mathieu-Daudé QTAILQ_FOREACH_SAFE(p, &list->head, next, q) {
1608d7f2e76SPhilippe Mathieu-Daudé QTAILQ_REMOVE(&list->head, p, next);
1618d7f2e76SPhilippe Mathieu-Daudé g_free(p);
1628d7f2e76SPhilippe Mathieu-Daudé }
1638d7f2e76SPhilippe Mathieu-Daudé
1648d7f2e76SPhilippe Mathieu-Daudé list->num = 0;
1658d7f2e76SPhilippe Mathieu-Daudé list->last_mapping = NULL;
1668d7f2e76SPhilippe Mathieu-Daudé }
1678d7f2e76SPhilippe Mathieu-Daudé
memory_mapping_list_init(MemoryMappingList * list)1688d7f2e76SPhilippe Mathieu-Daudé void memory_mapping_list_init(MemoryMappingList *list)
1698d7f2e76SPhilippe Mathieu-Daudé {
1708d7f2e76SPhilippe Mathieu-Daudé list->num = 0;
1718d7f2e76SPhilippe Mathieu-Daudé list->last_mapping = NULL;
1728d7f2e76SPhilippe Mathieu-Daudé QTAILQ_INIT(&list->head);
1738d7f2e76SPhilippe Mathieu-Daudé }
1748d7f2e76SPhilippe Mathieu-Daudé
guest_phys_blocks_free(GuestPhysBlockList * list)1758d7f2e76SPhilippe Mathieu-Daudé void guest_phys_blocks_free(GuestPhysBlockList *list)
1768d7f2e76SPhilippe Mathieu-Daudé {
1778d7f2e76SPhilippe Mathieu-Daudé GuestPhysBlock *p, *q;
1788d7f2e76SPhilippe Mathieu-Daudé
1798d7f2e76SPhilippe Mathieu-Daudé QTAILQ_FOREACH_SAFE(p, &list->head, next, q) {
1808d7f2e76SPhilippe Mathieu-Daudé QTAILQ_REMOVE(&list->head, p, next);
1818d7f2e76SPhilippe Mathieu-Daudé memory_region_unref(p->mr);
1828d7f2e76SPhilippe Mathieu-Daudé g_free(p);
1838d7f2e76SPhilippe Mathieu-Daudé }
1848d7f2e76SPhilippe Mathieu-Daudé list->num = 0;
1858d7f2e76SPhilippe Mathieu-Daudé }
1868d7f2e76SPhilippe Mathieu-Daudé
guest_phys_blocks_init(GuestPhysBlockList * list)1878d7f2e76SPhilippe Mathieu-Daudé void guest_phys_blocks_init(GuestPhysBlockList *list)
1888d7f2e76SPhilippe Mathieu-Daudé {
1898d7f2e76SPhilippe Mathieu-Daudé list->num = 0;
1908d7f2e76SPhilippe Mathieu-Daudé QTAILQ_INIT(&list->head);
1918d7f2e76SPhilippe Mathieu-Daudé }
1928d7f2e76SPhilippe Mathieu-Daudé
1938d7f2e76SPhilippe Mathieu-Daudé typedef struct GuestPhysListener {
1948d7f2e76SPhilippe Mathieu-Daudé GuestPhysBlockList *list;
1958d7f2e76SPhilippe Mathieu-Daudé MemoryListener listener;
1968d7f2e76SPhilippe Mathieu-Daudé } GuestPhysListener;
1978d7f2e76SPhilippe Mathieu-Daudé
guest_phys_block_add_section(GuestPhysListener * g,MemoryRegionSection * section)1988d7f2e76SPhilippe Mathieu-Daudé static void guest_phys_block_add_section(GuestPhysListener *g,
1998d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *section)
2008d7f2e76SPhilippe Mathieu-Daudé {
2018d7f2e76SPhilippe Mathieu-Daudé const hwaddr target_start = section->offset_within_address_space;
2028d7f2e76SPhilippe Mathieu-Daudé const hwaddr target_end = target_start + int128_get64(section->size);
2038d7f2e76SPhilippe Mathieu-Daudé uint8_t *host_addr = memory_region_get_ram_ptr(section->mr) +
2048d7f2e76SPhilippe Mathieu-Daudé section->offset_within_region;
2058d7f2e76SPhilippe Mathieu-Daudé GuestPhysBlock *predecessor = NULL;
2068d7f2e76SPhilippe Mathieu-Daudé
2078d7f2e76SPhilippe Mathieu-Daudé /* find continuity in guest physical address space */
2088d7f2e76SPhilippe Mathieu-Daudé if (!QTAILQ_EMPTY(&g->list->head)) {
2098d7f2e76SPhilippe Mathieu-Daudé hwaddr predecessor_size;
2108d7f2e76SPhilippe Mathieu-Daudé
2118d7f2e76SPhilippe Mathieu-Daudé predecessor = QTAILQ_LAST(&g->list->head);
2128d7f2e76SPhilippe Mathieu-Daudé predecessor_size = predecessor->target_end - predecessor->target_start;
2138d7f2e76SPhilippe Mathieu-Daudé
2148d7f2e76SPhilippe Mathieu-Daudé /* the memory API guarantees monotonically increasing traversal */
2158d7f2e76SPhilippe Mathieu-Daudé g_assert(predecessor->target_end <= target_start);
2168d7f2e76SPhilippe Mathieu-Daudé
2178d7f2e76SPhilippe Mathieu-Daudé /* we want continuity in both guest-physical and host-virtual memory */
2188d7f2e76SPhilippe Mathieu-Daudé if (predecessor->target_end < target_start ||
2198d7f2e76SPhilippe Mathieu-Daudé predecessor->host_addr + predecessor_size != host_addr ||
2208d7f2e76SPhilippe Mathieu-Daudé predecessor->mr != section->mr) {
2218d7f2e76SPhilippe Mathieu-Daudé predecessor = NULL;
2228d7f2e76SPhilippe Mathieu-Daudé }
2238d7f2e76SPhilippe Mathieu-Daudé }
2248d7f2e76SPhilippe Mathieu-Daudé
2258d7f2e76SPhilippe Mathieu-Daudé if (predecessor == NULL) {
2268d7f2e76SPhilippe Mathieu-Daudé /* isolated mapping, allocate it and add it to the list */
2278d7f2e76SPhilippe Mathieu-Daudé GuestPhysBlock *block = g_malloc0(sizeof *block);
2288d7f2e76SPhilippe Mathieu-Daudé
2298d7f2e76SPhilippe Mathieu-Daudé block->target_start = target_start;
2308d7f2e76SPhilippe Mathieu-Daudé block->target_end = target_end;
2318d7f2e76SPhilippe Mathieu-Daudé block->host_addr = host_addr;
2328d7f2e76SPhilippe Mathieu-Daudé block->mr = section->mr;
2338d7f2e76SPhilippe Mathieu-Daudé memory_region_ref(section->mr);
2348d7f2e76SPhilippe Mathieu-Daudé
2358d7f2e76SPhilippe Mathieu-Daudé QTAILQ_INSERT_TAIL(&g->list->head, block, next);
2368d7f2e76SPhilippe Mathieu-Daudé ++g->list->num;
2378d7f2e76SPhilippe Mathieu-Daudé } else {
2388d7f2e76SPhilippe Mathieu-Daudé /* expand predecessor until @target_end; predecessor's start doesn't
2398d7f2e76SPhilippe Mathieu-Daudé * change
2408d7f2e76SPhilippe Mathieu-Daudé */
2418d7f2e76SPhilippe Mathieu-Daudé predecessor->target_end = target_end;
2428d7f2e76SPhilippe Mathieu-Daudé }
2438d7f2e76SPhilippe Mathieu-Daudé
2448d7f2e76SPhilippe Mathieu-Daudé #ifdef DEBUG_GUEST_PHYS_REGION_ADD
2458d7f2e76SPhilippe Mathieu-Daudé fprintf(stderr, "%s: target_start=" HWADDR_FMT_plx " target_end="
2468d7f2e76SPhilippe Mathieu-Daudé HWADDR_FMT_plx ": %s (count: %u)\n", __func__, target_start,
2478d7f2e76SPhilippe Mathieu-Daudé target_end, predecessor ? "joined" : "added", g->list->num);
2488d7f2e76SPhilippe Mathieu-Daudé #endif
2498d7f2e76SPhilippe Mathieu-Daudé }
2508d7f2e76SPhilippe Mathieu-Daudé
guest_phys_ram_populate_cb(MemoryRegionSection * section,void * opaque)2518d7f2e76SPhilippe Mathieu-Daudé static int guest_phys_ram_populate_cb(MemoryRegionSection *section,
2528d7f2e76SPhilippe Mathieu-Daudé void *opaque)
2538d7f2e76SPhilippe Mathieu-Daudé {
2548d7f2e76SPhilippe Mathieu-Daudé GuestPhysListener *g = opaque;
2558d7f2e76SPhilippe Mathieu-Daudé
2568d7f2e76SPhilippe Mathieu-Daudé guest_phys_block_add_section(g, section);
2578d7f2e76SPhilippe Mathieu-Daudé return 0;
2588d7f2e76SPhilippe Mathieu-Daudé }
2598d7f2e76SPhilippe Mathieu-Daudé
guest_phys_blocks_region_add(MemoryListener * listener,MemoryRegionSection * section)2608d7f2e76SPhilippe Mathieu-Daudé static void guest_phys_blocks_region_add(MemoryListener *listener,
2618d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *section)
2628d7f2e76SPhilippe Mathieu-Daudé {
2638d7f2e76SPhilippe Mathieu-Daudé GuestPhysListener *g = container_of(listener, GuestPhysListener, listener);
2648d7f2e76SPhilippe Mathieu-Daudé
2658d7f2e76SPhilippe Mathieu-Daudé /* we only care about RAM */
2668d7f2e76SPhilippe Mathieu-Daudé if (!memory_region_is_ram(section->mr) ||
2678d7f2e76SPhilippe Mathieu-Daudé memory_region_is_ram_device(section->mr) ||
2688d7f2e76SPhilippe Mathieu-Daudé memory_region_is_nonvolatile(section->mr)) {
2698d7f2e76SPhilippe Mathieu-Daudé return;
2708d7f2e76SPhilippe Mathieu-Daudé }
2718d7f2e76SPhilippe Mathieu-Daudé
2728d7f2e76SPhilippe Mathieu-Daudé /* for special sparse regions, only add populated parts */
2738d7f2e76SPhilippe Mathieu-Daudé if (memory_region_has_ram_discard_manager(section->mr)) {
2748d7f2e76SPhilippe Mathieu-Daudé RamDiscardManager *rdm;
2758d7f2e76SPhilippe Mathieu-Daudé
2768d7f2e76SPhilippe Mathieu-Daudé rdm = memory_region_get_ram_discard_manager(section->mr);
2778d7f2e76SPhilippe Mathieu-Daudé ram_discard_manager_replay_populated(rdm, section,
2788d7f2e76SPhilippe Mathieu-Daudé guest_phys_ram_populate_cb, g);
2798d7f2e76SPhilippe Mathieu-Daudé return;
2808d7f2e76SPhilippe Mathieu-Daudé }
2818d7f2e76SPhilippe Mathieu-Daudé
2828d7f2e76SPhilippe Mathieu-Daudé guest_phys_block_add_section(g, section);
2838d7f2e76SPhilippe Mathieu-Daudé }
2848d7f2e76SPhilippe Mathieu-Daudé
guest_phys_blocks_append(GuestPhysBlockList * list)2858d7f2e76SPhilippe Mathieu-Daudé void guest_phys_blocks_append(GuestPhysBlockList *list)
2868d7f2e76SPhilippe Mathieu-Daudé {
2878d7f2e76SPhilippe Mathieu-Daudé GuestPhysListener g = { 0 };
2888d7f2e76SPhilippe Mathieu-Daudé
2898d7f2e76SPhilippe Mathieu-Daudé g.list = list;
2908d7f2e76SPhilippe Mathieu-Daudé g.listener.region_add = &guest_phys_blocks_region_add;
2918d7f2e76SPhilippe Mathieu-Daudé memory_listener_register(&g.listener, &address_space_memory);
2928d7f2e76SPhilippe Mathieu-Daudé memory_listener_unregister(&g.listener);
2938d7f2e76SPhilippe Mathieu-Daudé }
2948d7f2e76SPhilippe Mathieu-Daudé
find_paging_enabled_cpu(void)29547538e44SMarc-André Lureau static CPUState *find_paging_enabled_cpu(void)
2968d7f2e76SPhilippe Mathieu-Daudé {
2978d7f2e76SPhilippe Mathieu-Daudé CPUState *cpu;
2988d7f2e76SPhilippe Mathieu-Daudé
2998d7f2e76SPhilippe Mathieu-Daudé CPU_FOREACH(cpu) {
3008d7f2e76SPhilippe Mathieu-Daudé if (cpu_paging_enabled(cpu)) {
3018d7f2e76SPhilippe Mathieu-Daudé return cpu;
3028d7f2e76SPhilippe Mathieu-Daudé }
3038d7f2e76SPhilippe Mathieu-Daudé }
3048d7f2e76SPhilippe Mathieu-Daudé
3058d7f2e76SPhilippe Mathieu-Daudé return NULL;
3068d7f2e76SPhilippe Mathieu-Daudé }
3078d7f2e76SPhilippe Mathieu-Daudé
qemu_get_guest_memory_mapping(MemoryMappingList * list,const GuestPhysBlockList * guest_phys_blocks,Error ** errp)3088a5b974bSMarc-André Lureau bool qemu_get_guest_memory_mapping(MemoryMappingList *list,
3098d7f2e76SPhilippe Mathieu-Daudé const GuestPhysBlockList *guest_phys_blocks,
3108d7f2e76SPhilippe Mathieu-Daudé Error **errp)
3118d7f2e76SPhilippe Mathieu-Daudé {
3128a5b974bSMarc-André Lureau ERRP_GUARD();
3138d7f2e76SPhilippe Mathieu-Daudé CPUState *cpu, *first_paging_enabled_cpu;
3148d7f2e76SPhilippe Mathieu-Daudé GuestPhysBlock *block;
3158d7f2e76SPhilippe Mathieu-Daudé ram_addr_t offset, length;
3168d7f2e76SPhilippe Mathieu-Daudé
31747538e44SMarc-André Lureau first_paging_enabled_cpu = find_paging_enabled_cpu();
3188d7f2e76SPhilippe Mathieu-Daudé if (first_paging_enabled_cpu) {
3198d7f2e76SPhilippe Mathieu-Daudé for (cpu = first_paging_enabled_cpu; cpu != NULL;
3208d7f2e76SPhilippe Mathieu-Daudé cpu = CPU_NEXT(cpu)) {
3218a5b974bSMarc-André Lureau if (!cpu_get_memory_mapping(cpu, list, errp)) {
3228a5b974bSMarc-André Lureau return false;
3238d7f2e76SPhilippe Mathieu-Daudé }
3248d7f2e76SPhilippe Mathieu-Daudé }
3258a5b974bSMarc-André Lureau return true;
3268d7f2e76SPhilippe Mathieu-Daudé }
3278d7f2e76SPhilippe Mathieu-Daudé
3288d7f2e76SPhilippe Mathieu-Daudé /*
3298d7f2e76SPhilippe Mathieu-Daudé * If the guest doesn't use paging, the virtual address is equal to physical
3308d7f2e76SPhilippe Mathieu-Daudé * address.
3318d7f2e76SPhilippe Mathieu-Daudé */
3328d7f2e76SPhilippe Mathieu-Daudé QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) {
3338d7f2e76SPhilippe Mathieu-Daudé offset = block->target_start;
3348d7f2e76SPhilippe Mathieu-Daudé length = block->target_end - block->target_start;
3358d7f2e76SPhilippe Mathieu-Daudé create_new_memory_mapping(list, offset, offset, length);
3368d7f2e76SPhilippe Mathieu-Daudé }
3378a5b974bSMarc-André Lureau return true;
3388d7f2e76SPhilippe Mathieu-Daudé }
3398d7f2e76SPhilippe Mathieu-Daudé
qemu_get_guest_simple_memory_mapping(MemoryMappingList * list,const GuestPhysBlockList * guest_phys_blocks)3408d7f2e76SPhilippe Mathieu-Daudé void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list,
3418d7f2e76SPhilippe Mathieu-Daudé const GuestPhysBlockList *guest_phys_blocks)
3428d7f2e76SPhilippe Mathieu-Daudé {
3438d7f2e76SPhilippe Mathieu-Daudé GuestPhysBlock *block;
3448d7f2e76SPhilippe Mathieu-Daudé
3458d7f2e76SPhilippe Mathieu-Daudé QTAILQ_FOREACH(block, &guest_phys_blocks->head, next) {
3468d7f2e76SPhilippe Mathieu-Daudé create_new_memory_mapping(list, block->target_start, 0,
3478d7f2e76SPhilippe Mathieu-Daudé block->target_end - block->target_start);
3488d7f2e76SPhilippe Mathieu-Daudé }
3498d7f2e76SPhilippe Mathieu-Daudé }
3508d7f2e76SPhilippe Mathieu-Daudé
memory_mapping_filter(MemoryMappingList * list,int64_t begin,int64_t length)3518d7f2e76SPhilippe Mathieu-Daudé void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
3528d7f2e76SPhilippe Mathieu-Daudé int64_t length)
3538d7f2e76SPhilippe Mathieu-Daudé {
3548d7f2e76SPhilippe Mathieu-Daudé MemoryMapping *cur, *next;
3558d7f2e76SPhilippe Mathieu-Daudé
3568d7f2e76SPhilippe Mathieu-Daudé QTAILQ_FOREACH_SAFE(cur, &list->head, next, next) {
357*13c59a0eSYao Xingtao if (!ranges_overlap(cur->phys_addr, cur->length, begin, length)) {
3588d7f2e76SPhilippe Mathieu-Daudé QTAILQ_REMOVE(&list->head, cur, next);
3598d7f2e76SPhilippe Mathieu-Daudé g_free(cur);
3608d7f2e76SPhilippe Mathieu-Daudé list->num--;
3618d7f2e76SPhilippe Mathieu-Daudé continue;
3628d7f2e76SPhilippe Mathieu-Daudé }
3638d7f2e76SPhilippe Mathieu-Daudé
3648d7f2e76SPhilippe Mathieu-Daudé if (cur->phys_addr < begin) {
3658d7f2e76SPhilippe Mathieu-Daudé cur->length -= begin - cur->phys_addr;
3668d7f2e76SPhilippe Mathieu-Daudé if (cur->virt_addr) {
3678d7f2e76SPhilippe Mathieu-Daudé cur->virt_addr += begin - cur->phys_addr;
3688d7f2e76SPhilippe Mathieu-Daudé }
3698d7f2e76SPhilippe Mathieu-Daudé cur->phys_addr = begin;
3708d7f2e76SPhilippe Mathieu-Daudé }
3718d7f2e76SPhilippe Mathieu-Daudé
3728d7f2e76SPhilippe Mathieu-Daudé if (cur->phys_addr + cur->length > begin + length) {
3738d7f2e76SPhilippe Mathieu-Daudé cur->length -= cur->phys_addr + cur->length - begin - length;
3748d7f2e76SPhilippe Mathieu-Daudé }
3758d7f2e76SPhilippe Mathieu-Daudé }
3768d7f2e76SPhilippe Mathieu-Daudé }
377