18d7f2e76SPhilippe Mathieu-Daudé /*
28d7f2e76SPhilippe Mathieu-Daudé * RAM allocation and memory access
38d7f2e76SPhilippe Mathieu-Daudé *
48d7f2e76SPhilippe Mathieu-Daudé * Copyright (c) 2003 Fabrice Bellard
58d7f2e76SPhilippe Mathieu-Daudé *
68d7f2e76SPhilippe Mathieu-Daudé * This library is free software; you can redistribute it and/or
78d7f2e76SPhilippe Mathieu-Daudé * modify it under the terms of the GNU Lesser General Public
88d7f2e76SPhilippe Mathieu-Daudé * License as published by the Free Software Foundation; either
98d7f2e76SPhilippe Mathieu-Daudé * version 2.1 of the License, or (at your option) any later version.
108d7f2e76SPhilippe Mathieu-Daudé *
118d7f2e76SPhilippe Mathieu-Daudé * This library is distributed in the hope that it will be useful,
128d7f2e76SPhilippe Mathieu-Daudé * but WITHOUT ANY WARRANTY; without even the implied warranty of
138d7f2e76SPhilippe Mathieu-Daudé * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
148d7f2e76SPhilippe Mathieu-Daudé * Lesser General Public License for more details.
158d7f2e76SPhilippe Mathieu-Daudé *
168d7f2e76SPhilippe Mathieu-Daudé * You should have received a copy of the GNU Lesser General Public
178d7f2e76SPhilippe Mathieu-Daudé * License along with this library; if not, see <http://www.gnu.org/licenses/>.
188d7f2e76SPhilippe Mathieu-Daudé */
198d7f2e76SPhilippe Mathieu-Daudé
208d7f2e76SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
218d7f2e76SPhilippe Mathieu-Daudé #include "exec/page-vary.h"
228d7f2e76SPhilippe Mathieu-Daudé #include "qapi/error.h"
238d7f2e76SPhilippe Mathieu-Daudé
248d7f2e76SPhilippe Mathieu-Daudé #include "qemu/cutils.h"
258d7f2e76SPhilippe Mathieu-Daudé #include "qemu/cacheflush.h"
268d7f2e76SPhilippe Mathieu-Daudé #include "qemu/hbitmap.h"
278d7f2e76SPhilippe Mathieu-Daudé #include "qemu/madvise.h"
28d5e26819SPhilippe Mathieu-Daudé #include "qemu/lockable.h"
298d7f2e76SPhilippe Mathieu-Daudé
308d7f2e76SPhilippe Mathieu-Daudé #ifdef CONFIG_TCG
318d7f2e76SPhilippe Mathieu-Daudé #include "hw/core/tcg-cpu-ops.h"
328d7f2e76SPhilippe Mathieu-Daudé #endif /* CONFIG_TCG */
338d7f2e76SPhilippe Mathieu-Daudé
348d7f2e76SPhilippe Mathieu-Daudé #include "exec/exec-all.h"
3574781c08SPhilippe Mathieu-Daudé #include "exec/page-protection.h"
368d7f2e76SPhilippe Mathieu-Daudé #include "exec/target_page.h"
378d7f2e76SPhilippe Mathieu-Daudé #include "hw/qdev-core.h"
388d7f2e76SPhilippe Mathieu-Daudé #include "hw/qdev-properties.h"
398d7f2e76SPhilippe Mathieu-Daudé #include "hw/boards.h"
405d5bb9c8SPhilippe Mathieu-Daudé #include "sysemu/xen.h"
418d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/kvm.h"
428d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/tcg.h"
438d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/qtest.h"
448d7f2e76SPhilippe Mathieu-Daudé #include "qemu/timer.h"
458d7f2e76SPhilippe Mathieu-Daudé #include "qemu/config-file.h"
468d7f2e76SPhilippe Mathieu-Daudé #include "qemu/error-report.h"
478d7f2e76SPhilippe Mathieu-Daudé #include "qemu/qemu-print.h"
488d7f2e76SPhilippe Mathieu-Daudé #include "qemu/log.h"
498d7f2e76SPhilippe Mathieu-Daudé #include "qemu/memalign.h"
508d7f2e76SPhilippe Mathieu-Daudé #include "exec/memory.h"
518d7f2e76SPhilippe Mathieu-Daudé #include "exec/ioport.h"
528d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/dma.h"
538d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/hostmem.h"
548d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/hw_accel.h"
558d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/xen-mapcache.h"
56d44fe13bSAlex Bennée #include "trace.h"
578d7f2e76SPhilippe Mathieu-Daudé
588d7f2e76SPhilippe Mathieu-Daudé #ifdef CONFIG_FALLOCATE_PUNCH_HOLE
598d7f2e76SPhilippe Mathieu-Daudé #include <linux/falloc.h>
608d7f2e76SPhilippe Mathieu-Daudé #endif
618d7f2e76SPhilippe Mathieu-Daudé
628d7f2e76SPhilippe Mathieu-Daudé #include "qemu/rcu_queue.h"
638d7f2e76SPhilippe Mathieu-Daudé #include "qemu/main-loop.h"
648d7f2e76SPhilippe Mathieu-Daudé #include "exec/translate-all.h"
658d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/replay.h"
668d7f2e76SPhilippe Mathieu-Daudé
678d7f2e76SPhilippe Mathieu-Daudé #include "exec/memory-internal.h"
688d7f2e76SPhilippe Mathieu-Daudé #include "exec/ram_addr.h"
698d7f2e76SPhilippe Mathieu-Daudé
708d7f2e76SPhilippe Mathieu-Daudé #include "qemu/pmem.h"
718d7f2e76SPhilippe Mathieu-Daudé
728d7f2e76SPhilippe Mathieu-Daudé #include "migration/vmstate.h"
738d7f2e76SPhilippe Mathieu-Daudé
748d7f2e76SPhilippe Mathieu-Daudé #include "qemu/range.h"
758d7f2e76SPhilippe Mathieu-Daudé #ifndef _WIN32
768d7f2e76SPhilippe Mathieu-Daudé #include "qemu/mmap-alloc.h"
778d7f2e76SPhilippe Mathieu-Daudé #endif
788d7f2e76SPhilippe Mathieu-Daudé
798d7f2e76SPhilippe Mathieu-Daudé #include "monitor/monitor.h"
808d7f2e76SPhilippe Mathieu-Daudé
818d7f2e76SPhilippe Mathieu-Daudé #ifdef CONFIG_LIBDAXCTL
828d7f2e76SPhilippe Mathieu-Daudé #include <daxctl/libdaxctl.h>
838d7f2e76SPhilippe Mathieu-Daudé #endif
848d7f2e76SPhilippe Mathieu-Daudé
858d7f2e76SPhilippe Mathieu-Daudé //#define DEBUG_SUBPAGE
868d7f2e76SPhilippe Mathieu-Daudé
878d7f2e76SPhilippe Mathieu-Daudé /* ram_list is read under rcu_read_lock()/rcu_read_unlock(). Writes
888d7f2e76SPhilippe Mathieu-Daudé * are protected by the ramlist lock.
898d7f2e76SPhilippe Mathieu-Daudé */
908d7f2e76SPhilippe Mathieu-Daudé RAMList ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list.blocks) };
918d7f2e76SPhilippe Mathieu-Daudé
928d7f2e76SPhilippe Mathieu-Daudé static MemoryRegion *system_memory;
938d7f2e76SPhilippe Mathieu-Daudé static MemoryRegion *system_io;
948d7f2e76SPhilippe Mathieu-Daudé
958d7f2e76SPhilippe Mathieu-Daudé AddressSpace address_space_io;
968d7f2e76SPhilippe Mathieu-Daudé AddressSpace address_space_memory;
978d7f2e76SPhilippe Mathieu-Daudé
988d7f2e76SPhilippe Mathieu-Daudé static MemoryRegion io_mem_unassigned;
998d7f2e76SPhilippe Mathieu-Daudé
1008d7f2e76SPhilippe Mathieu-Daudé typedef struct PhysPageEntry PhysPageEntry;
1018d7f2e76SPhilippe Mathieu-Daudé
1028d7f2e76SPhilippe Mathieu-Daudé struct PhysPageEntry {
1038d7f2e76SPhilippe Mathieu-Daudé /* How many bits skip to next level (in units of L2_SIZE). 0 for a leaf. */
1048d7f2e76SPhilippe Mathieu-Daudé uint32_t skip : 6;
1058d7f2e76SPhilippe Mathieu-Daudé /* index into phys_sections (!skip) or phys_map_nodes (skip) */
1068d7f2e76SPhilippe Mathieu-Daudé uint32_t ptr : 26;
1078d7f2e76SPhilippe Mathieu-Daudé };
1088d7f2e76SPhilippe Mathieu-Daudé
1098d7f2e76SPhilippe Mathieu-Daudé #define PHYS_MAP_NODE_NIL (((uint32_t)~0) >> 6)
1108d7f2e76SPhilippe Mathieu-Daudé
1118d7f2e76SPhilippe Mathieu-Daudé /* Size of the L2 (and L3, etc) page tables. */
1128d7f2e76SPhilippe Mathieu-Daudé #define ADDR_SPACE_BITS 64
1138d7f2e76SPhilippe Mathieu-Daudé
1148d7f2e76SPhilippe Mathieu-Daudé #define P_L2_BITS 9
1158d7f2e76SPhilippe Mathieu-Daudé #define P_L2_SIZE (1 << P_L2_BITS)
1168d7f2e76SPhilippe Mathieu-Daudé
1178d7f2e76SPhilippe Mathieu-Daudé #define P_L2_LEVELS (((ADDR_SPACE_BITS - TARGET_PAGE_BITS - 1) / P_L2_BITS) + 1)
1188d7f2e76SPhilippe Mathieu-Daudé
1198d7f2e76SPhilippe Mathieu-Daudé typedef PhysPageEntry Node[P_L2_SIZE];
1208d7f2e76SPhilippe Mathieu-Daudé
1218d7f2e76SPhilippe Mathieu-Daudé typedef struct PhysPageMap {
1228d7f2e76SPhilippe Mathieu-Daudé struct rcu_head rcu;
1238d7f2e76SPhilippe Mathieu-Daudé
1248d7f2e76SPhilippe Mathieu-Daudé unsigned sections_nb;
1258d7f2e76SPhilippe Mathieu-Daudé unsigned sections_nb_alloc;
1268d7f2e76SPhilippe Mathieu-Daudé unsigned nodes_nb;
1278d7f2e76SPhilippe Mathieu-Daudé unsigned nodes_nb_alloc;
1288d7f2e76SPhilippe Mathieu-Daudé Node *nodes;
1298d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *sections;
1308d7f2e76SPhilippe Mathieu-Daudé } PhysPageMap;
1318d7f2e76SPhilippe Mathieu-Daudé
1328d7f2e76SPhilippe Mathieu-Daudé struct AddressSpaceDispatch {
1338d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *mru_section;
1348d7f2e76SPhilippe Mathieu-Daudé /* This is a multi-level map on the physical address space.
1358d7f2e76SPhilippe Mathieu-Daudé * The bottom level has pointers to MemoryRegionSections.
1368d7f2e76SPhilippe Mathieu-Daudé */
1378d7f2e76SPhilippe Mathieu-Daudé PhysPageEntry phys_map;
1388d7f2e76SPhilippe Mathieu-Daudé PhysPageMap map;
1398d7f2e76SPhilippe Mathieu-Daudé };
1408d7f2e76SPhilippe Mathieu-Daudé
1418d7f2e76SPhilippe Mathieu-Daudé #define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
1428d7f2e76SPhilippe Mathieu-Daudé typedef struct subpage_t {
1438d7f2e76SPhilippe Mathieu-Daudé MemoryRegion iomem;
1448d7f2e76SPhilippe Mathieu-Daudé FlatView *fv;
1458d7f2e76SPhilippe Mathieu-Daudé hwaddr base;
1468d7f2e76SPhilippe Mathieu-Daudé uint16_t sub_section[];
1478d7f2e76SPhilippe Mathieu-Daudé } subpage_t;
1488d7f2e76SPhilippe Mathieu-Daudé
1498d7f2e76SPhilippe Mathieu-Daudé #define PHYS_SECTION_UNASSIGNED 0
1508d7f2e76SPhilippe Mathieu-Daudé
1518d7f2e76SPhilippe Mathieu-Daudé static void io_mem_init(void);
1528d7f2e76SPhilippe Mathieu-Daudé static void memory_map_init(void);
1538d7f2e76SPhilippe Mathieu-Daudé static void tcg_log_global_after_sync(MemoryListener *listener);
1548d7f2e76SPhilippe Mathieu-Daudé static void tcg_commit(MemoryListener *listener);
1558d7f2e76SPhilippe Mathieu-Daudé
1568d7f2e76SPhilippe Mathieu-Daudé /**
1578d7f2e76SPhilippe Mathieu-Daudé * CPUAddressSpace: all the information a CPU needs about an AddressSpace
1588d7f2e76SPhilippe Mathieu-Daudé * @cpu: the CPU whose AddressSpace this is
1598d7f2e76SPhilippe Mathieu-Daudé * @as: the AddressSpace itself
1608d7f2e76SPhilippe Mathieu-Daudé * @memory_dispatch: its dispatch pointer (cached, RCU protected)
1618d7f2e76SPhilippe Mathieu-Daudé * @tcg_as_listener: listener for tracking changes to the AddressSpace
1628d7f2e76SPhilippe Mathieu-Daudé */
16315d62536SPaolo Bonzini typedef struct CPUAddressSpace {
1648d7f2e76SPhilippe Mathieu-Daudé CPUState *cpu;
1658d7f2e76SPhilippe Mathieu-Daudé AddressSpace *as;
1668d7f2e76SPhilippe Mathieu-Daudé struct AddressSpaceDispatch *memory_dispatch;
1678d7f2e76SPhilippe Mathieu-Daudé MemoryListener tcg_as_listener;
16815d62536SPaolo Bonzini } CPUAddressSpace;
1698d7f2e76SPhilippe Mathieu-Daudé
1708d7f2e76SPhilippe Mathieu-Daudé struct DirtyBitmapSnapshot {
1718d7f2e76SPhilippe Mathieu-Daudé ram_addr_t start;
1728d7f2e76SPhilippe Mathieu-Daudé ram_addr_t end;
1738d7f2e76SPhilippe Mathieu-Daudé unsigned long dirty[];
1748d7f2e76SPhilippe Mathieu-Daudé };
1758d7f2e76SPhilippe Mathieu-Daudé
phys_map_node_reserve(PhysPageMap * map,unsigned nodes)1768d7f2e76SPhilippe Mathieu-Daudé static void phys_map_node_reserve(PhysPageMap *map, unsigned nodes)
1778d7f2e76SPhilippe Mathieu-Daudé {
1788d7f2e76SPhilippe Mathieu-Daudé static unsigned alloc_hint = 16;
1798d7f2e76SPhilippe Mathieu-Daudé if (map->nodes_nb + nodes > map->nodes_nb_alloc) {
1808d7f2e76SPhilippe Mathieu-Daudé map->nodes_nb_alloc = MAX(alloc_hint, map->nodes_nb + nodes);
1818d7f2e76SPhilippe Mathieu-Daudé map->nodes = g_renew(Node, map->nodes, map->nodes_nb_alloc);
1828d7f2e76SPhilippe Mathieu-Daudé alloc_hint = map->nodes_nb_alloc;
1838d7f2e76SPhilippe Mathieu-Daudé }
1848d7f2e76SPhilippe Mathieu-Daudé }
1858d7f2e76SPhilippe Mathieu-Daudé
phys_map_node_alloc(PhysPageMap * map,bool leaf)1868d7f2e76SPhilippe Mathieu-Daudé static uint32_t phys_map_node_alloc(PhysPageMap *map, bool leaf)
1878d7f2e76SPhilippe Mathieu-Daudé {
1888d7f2e76SPhilippe Mathieu-Daudé unsigned i;
1898d7f2e76SPhilippe Mathieu-Daudé uint32_t ret;
1908d7f2e76SPhilippe Mathieu-Daudé PhysPageEntry e;
1918d7f2e76SPhilippe Mathieu-Daudé PhysPageEntry *p;
1928d7f2e76SPhilippe Mathieu-Daudé
1938d7f2e76SPhilippe Mathieu-Daudé ret = map->nodes_nb++;
1948d7f2e76SPhilippe Mathieu-Daudé p = map->nodes[ret];
1958d7f2e76SPhilippe Mathieu-Daudé assert(ret != PHYS_MAP_NODE_NIL);
1968d7f2e76SPhilippe Mathieu-Daudé assert(ret != map->nodes_nb_alloc);
1978d7f2e76SPhilippe Mathieu-Daudé
1988d7f2e76SPhilippe Mathieu-Daudé e.skip = leaf ? 0 : 1;
1998d7f2e76SPhilippe Mathieu-Daudé e.ptr = leaf ? PHYS_SECTION_UNASSIGNED : PHYS_MAP_NODE_NIL;
2008d7f2e76SPhilippe Mathieu-Daudé for (i = 0; i < P_L2_SIZE; ++i) {
2018d7f2e76SPhilippe Mathieu-Daudé memcpy(&p[i], &e, sizeof(e));
2028d7f2e76SPhilippe Mathieu-Daudé }
2038d7f2e76SPhilippe Mathieu-Daudé return ret;
2048d7f2e76SPhilippe Mathieu-Daudé }
2058d7f2e76SPhilippe Mathieu-Daudé
phys_page_set_level(PhysPageMap * map,PhysPageEntry * lp,hwaddr * index,uint64_t * nb,uint16_t leaf,int level)2068d7f2e76SPhilippe Mathieu-Daudé static void phys_page_set_level(PhysPageMap *map, PhysPageEntry *lp,
2078d7f2e76SPhilippe Mathieu-Daudé hwaddr *index, uint64_t *nb, uint16_t leaf,
2088d7f2e76SPhilippe Mathieu-Daudé int level)
2098d7f2e76SPhilippe Mathieu-Daudé {
2108d7f2e76SPhilippe Mathieu-Daudé PhysPageEntry *p;
2118d7f2e76SPhilippe Mathieu-Daudé hwaddr step = (hwaddr)1 << (level * P_L2_BITS);
2128d7f2e76SPhilippe Mathieu-Daudé
2138d7f2e76SPhilippe Mathieu-Daudé if (lp->skip && lp->ptr == PHYS_MAP_NODE_NIL) {
2148d7f2e76SPhilippe Mathieu-Daudé lp->ptr = phys_map_node_alloc(map, level == 0);
2158d7f2e76SPhilippe Mathieu-Daudé }
2168d7f2e76SPhilippe Mathieu-Daudé p = map->nodes[lp->ptr];
2178d7f2e76SPhilippe Mathieu-Daudé lp = &p[(*index >> (level * P_L2_BITS)) & (P_L2_SIZE - 1)];
2188d7f2e76SPhilippe Mathieu-Daudé
2198d7f2e76SPhilippe Mathieu-Daudé while (*nb && lp < &p[P_L2_SIZE]) {
2208d7f2e76SPhilippe Mathieu-Daudé if ((*index & (step - 1)) == 0 && *nb >= step) {
2218d7f2e76SPhilippe Mathieu-Daudé lp->skip = 0;
2228d7f2e76SPhilippe Mathieu-Daudé lp->ptr = leaf;
2238d7f2e76SPhilippe Mathieu-Daudé *index += step;
2248d7f2e76SPhilippe Mathieu-Daudé *nb -= step;
2258d7f2e76SPhilippe Mathieu-Daudé } else {
2268d7f2e76SPhilippe Mathieu-Daudé phys_page_set_level(map, lp, index, nb, leaf, level - 1);
2278d7f2e76SPhilippe Mathieu-Daudé }
2288d7f2e76SPhilippe Mathieu-Daudé ++lp;
2298d7f2e76SPhilippe Mathieu-Daudé }
2308d7f2e76SPhilippe Mathieu-Daudé }
2318d7f2e76SPhilippe Mathieu-Daudé
phys_page_set(AddressSpaceDispatch * d,hwaddr index,uint64_t nb,uint16_t leaf)2328d7f2e76SPhilippe Mathieu-Daudé static void phys_page_set(AddressSpaceDispatch *d,
2338d7f2e76SPhilippe Mathieu-Daudé hwaddr index, uint64_t nb,
2348d7f2e76SPhilippe Mathieu-Daudé uint16_t leaf)
2358d7f2e76SPhilippe Mathieu-Daudé {
2368d7f2e76SPhilippe Mathieu-Daudé /* Wildly overreserve - it doesn't matter much. */
2378d7f2e76SPhilippe Mathieu-Daudé phys_map_node_reserve(&d->map, 3 * P_L2_LEVELS);
2388d7f2e76SPhilippe Mathieu-Daudé
2398d7f2e76SPhilippe Mathieu-Daudé phys_page_set_level(&d->map, &d->phys_map, &index, &nb, leaf, P_L2_LEVELS - 1);
2408d7f2e76SPhilippe Mathieu-Daudé }
2418d7f2e76SPhilippe Mathieu-Daudé
2428d7f2e76SPhilippe Mathieu-Daudé /* Compact a non leaf page entry. Simply detect that the entry has a single child,
2438d7f2e76SPhilippe Mathieu-Daudé * and update our entry so we can skip it and go directly to the destination.
2448d7f2e76SPhilippe Mathieu-Daudé */
phys_page_compact(PhysPageEntry * lp,Node * nodes)2458d7f2e76SPhilippe Mathieu-Daudé static void phys_page_compact(PhysPageEntry *lp, Node *nodes)
2468d7f2e76SPhilippe Mathieu-Daudé {
2478d7f2e76SPhilippe Mathieu-Daudé unsigned valid_ptr = P_L2_SIZE;
2488d7f2e76SPhilippe Mathieu-Daudé int valid = 0;
2498d7f2e76SPhilippe Mathieu-Daudé PhysPageEntry *p;
2508d7f2e76SPhilippe Mathieu-Daudé int i;
2518d7f2e76SPhilippe Mathieu-Daudé
2528d7f2e76SPhilippe Mathieu-Daudé if (lp->ptr == PHYS_MAP_NODE_NIL) {
2538d7f2e76SPhilippe Mathieu-Daudé return;
2548d7f2e76SPhilippe Mathieu-Daudé }
2558d7f2e76SPhilippe Mathieu-Daudé
2568d7f2e76SPhilippe Mathieu-Daudé p = nodes[lp->ptr];
2578d7f2e76SPhilippe Mathieu-Daudé for (i = 0; i < P_L2_SIZE; i++) {
2588d7f2e76SPhilippe Mathieu-Daudé if (p[i].ptr == PHYS_MAP_NODE_NIL) {
2598d7f2e76SPhilippe Mathieu-Daudé continue;
2608d7f2e76SPhilippe Mathieu-Daudé }
2618d7f2e76SPhilippe Mathieu-Daudé
2628d7f2e76SPhilippe Mathieu-Daudé valid_ptr = i;
2638d7f2e76SPhilippe Mathieu-Daudé valid++;
2648d7f2e76SPhilippe Mathieu-Daudé if (p[i].skip) {
2658d7f2e76SPhilippe Mathieu-Daudé phys_page_compact(&p[i], nodes);
2668d7f2e76SPhilippe Mathieu-Daudé }
2678d7f2e76SPhilippe Mathieu-Daudé }
2688d7f2e76SPhilippe Mathieu-Daudé
2698d7f2e76SPhilippe Mathieu-Daudé /* We can only compress if there's only one child. */
2708d7f2e76SPhilippe Mathieu-Daudé if (valid != 1) {
2718d7f2e76SPhilippe Mathieu-Daudé return;
2728d7f2e76SPhilippe Mathieu-Daudé }
2738d7f2e76SPhilippe Mathieu-Daudé
2748d7f2e76SPhilippe Mathieu-Daudé assert(valid_ptr < P_L2_SIZE);
2758d7f2e76SPhilippe Mathieu-Daudé
2768d7f2e76SPhilippe Mathieu-Daudé /* Don't compress if it won't fit in the # of bits we have. */
2778d7f2e76SPhilippe Mathieu-Daudé if (P_L2_LEVELS >= (1 << 6) &&
2788d7f2e76SPhilippe Mathieu-Daudé lp->skip + p[valid_ptr].skip >= (1 << 6)) {
2798d7f2e76SPhilippe Mathieu-Daudé return;
2808d7f2e76SPhilippe Mathieu-Daudé }
2818d7f2e76SPhilippe Mathieu-Daudé
2828d7f2e76SPhilippe Mathieu-Daudé lp->ptr = p[valid_ptr].ptr;
2838d7f2e76SPhilippe Mathieu-Daudé if (!p[valid_ptr].skip) {
2848d7f2e76SPhilippe Mathieu-Daudé /* If our only child is a leaf, make this a leaf. */
2858d7f2e76SPhilippe Mathieu-Daudé /* By design, we should have made this node a leaf to begin with so we
2868d7f2e76SPhilippe Mathieu-Daudé * should never reach here.
2878d7f2e76SPhilippe Mathieu-Daudé * But since it's so simple to handle this, let's do it just in case we
2888d7f2e76SPhilippe Mathieu-Daudé * change this rule.
2898d7f2e76SPhilippe Mathieu-Daudé */
2908d7f2e76SPhilippe Mathieu-Daudé lp->skip = 0;
2918d7f2e76SPhilippe Mathieu-Daudé } else {
2928d7f2e76SPhilippe Mathieu-Daudé lp->skip += p[valid_ptr].skip;
2938d7f2e76SPhilippe Mathieu-Daudé }
2948d7f2e76SPhilippe Mathieu-Daudé }
2958d7f2e76SPhilippe Mathieu-Daudé
address_space_dispatch_compact(AddressSpaceDispatch * d)2968d7f2e76SPhilippe Mathieu-Daudé void address_space_dispatch_compact(AddressSpaceDispatch *d)
2978d7f2e76SPhilippe Mathieu-Daudé {
2988d7f2e76SPhilippe Mathieu-Daudé if (d->phys_map.skip) {
2998d7f2e76SPhilippe Mathieu-Daudé phys_page_compact(&d->phys_map, d->map.nodes);
3008d7f2e76SPhilippe Mathieu-Daudé }
3018d7f2e76SPhilippe Mathieu-Daudé }
3028d7f2e76SPhilippe Mathieu-Daudé
section_covers_addr(const MemoryRegionSection * section,hwaddr addr)3038d7f2e76SPhilippe Mathieu-Daudé static inline bool section_covers_addr(const MemoryRegionSection *section,
3048d7f2e76SPhilippe Mathieu-Daudé hwaddr addr)
3058d7f2e76SPhilippe Mathieu-Daudé {
3068d7f2e76SPhilippe Mathieu-Daudé /* Memory topology clips a memory region to [0, 2^64); size.hi > 0 means
3078d7f2e76SPhilippe Mathieu-Daudé * the section must cover the entire address space.
3088d7f2e76SPhilippe Mathieu-Daudé */
3098d7f2e76SPhilippe Mathieu-Daudé return int128_gethi(section->size) ||
3108d7f2e76SPhilippe Mathieu-Daudé range_covers_byte(section->offset_within_address_space,
3118d7f2e76SPhilippe Mathieu-Daudé int128_getlo(section->size), addr);
3128d7f2e76SPhilippe Mathieu-Daudé }
3138d7f2e76SPhilippe Mathieu-Daudé
phys_page_find(AddressSpaceDispatch * d,hwaddr addr)3148d7f2e76SPhilippe Mathieu-Daudé static MemoryRegionSection *phys_page_find(AddressSpaceDispatch *d, hwaddr addr)
3158d7f2e76SPhilippe Mathieu-Daudé {
3168d7f2e76SPhilippe Mathieu-Daudé PhysPageEntry lp = d->phys_map, *p;
3178d7f2e76SPhilippe Mathieu-Daudé Node *nodes = d->map.nodes;
3188d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *sections = d->map.sections;
3198d7f2e76SPhilippe Mathieu-Daudé hwaddr index = addr >> TARGET_PAGE_BITS;
3208d7f2e76SPhilippe Mathieu-Daudé int i;
3218d7f2e76SPhilippe Mathieu-Daudé
3228d7f2e76SPhilippe Mathieu-Daudé for (i = P_L2_LEVELS; lp.skip && (i -= lp.skip) >= 0;) {
3238d7f2e76SPhilippe Mathieu-Daudé if (lp.ptr == PHYS_MAP_NODE_NIL) {
3248d7f2e76SPhilippe Mathieu-Daudé return §ions[PHYS_SECTION_UNASSIGNED];
3258d7f2e76SPhilippe Mathieu-Daudé }
3268d7f2e76SPhilippe Mathieu-Daudé p = nodes[lp.ptr];
3278d7f2e76SPhilippe Mathieu-Daudé lp = p[(index >> (i * P_L2_BITS)) & (P_L2_SIZE - 1)];
3288d7f2e76SPhilippe Mathieu-Daudé }
3298d7f2e76SPhilippe Mathieu-Daudé
3308d7f2e76SPhilippe Mathieu-Daudé if (section_covers_addr(§ions[lp.ptr], addr)) {
3318d7f2e76SPhilippe Mathieu-Daudé return §ions[lp.ptr];
3328d7f2e76SPhilippe Mathieu-Daudé } else {
3338d7f2e76SPhilippe Mathieu-Daudé return §ions[PHYS_SECTION_UNASSIGNED];
3348d7f2e76SPhilippe Mathieu-Daudé }
3358d7f2e76SPhilippe Mathieu-Daudé }
3368d7f2e76SPhilippe Mathieu-Daudé
3378d7f2e76SPhilippe Mathieu-Daudé /* Called from RCU critical section */
address_space_lookup_region(AddressSpaceDispatch * d,hwaddr addr,bool resolve_subpage)3388d7f2e76SPhilippe Mathieu-Daudé static MemoryRegionSection *address_space_lookup_region(AddressSpaceDispatch *d,
3398d7f2e76SPhilippe Mathieu-Daudé hwaddr addr,
3408d7f2e76SPhilippe Mathieu-Daudé bool resolve_subpage)
3418d7f2e76SPhilippe Mathieu-Daudé {
3428d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *section = qatomic_read(&d->mru_section);
3438d7f2e76SPhilippe Mathieu-Daudé subpage_t *subpage;
3448d7f2e76SPhilippe Mathieu-Daudé
3458d7f2e76SPhilippe Mathieu-Daudé if (!section || section == &d->map.sections[PHYS_SECTION_UNASSIGNED] ||
3468d7f2e76SPhilippe Mathieu-Daudé !section_covers_addr(section, addr)) {
3478d7f2e76SPhilippe Mathieu-Daudé section = phys_page_find(d, addr);
3488d7f2e76SPhilippe Mathieu-Daudé qatomic_set(&d->mru_section, section);
3498d7f2e76SPhilippe Mathieu-Daudé }
3508d7f2e76SPhilippe Mathieu-Daudé if (resolve_subpage && section->mr->subpage) {
3518d7f2e76SPhilippe Mathieu-Daudé subpage = container_of(section->mr, subpage_t, iomem);
3528d7f2e76SPhilippe Mathieu-Daudé section = &d->map.sections[subpage->sub_section[SUBPAGE_IDX(addr)]];
3538d7f2e76SPhilippe Mathieu-Daudé }
3548d7f2e76SPhilippe Mathieu-Daudé return section;
3558d7f2e76SPhilippe Mathieu-Daudé }
3568d7f2e76SPhilippe Mathieu-Daudé
3578d7f2e76SPhilippe Mathieu-Daudé /* Called from RCU critical section */
3588d7f2e76SPhilippe Mathieu-Daudé static MemoryRegionSection *
address_space_translate_internal(AddressSpaceDispatch * d,hwaddr addr,hwaddr * xlat,hwaddr * plen,bool resolve_subpage)3598d7f2e76SPhilippe Mathieu-Daudé address_space_translate_internal(AddressSpaceDispatch *d, hwaddr addr, hwaddr *xlat,
3608d7f2e76SPhilippe Mathieu-Daudé hwaddr *plen, bool resolve_subpage)
3618d7f2e76SPhilippe Mathieu-Daudé {
3628d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *section;
3638d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr;
3648d7f2e76SPhilippe Mathieu-Daudé Int128 diff;
3658d7f2e76SPhilippe Mathieu-Daudé
3668d7f2e76SPhilippe Mathieu-Daudé section = address_space_lookup_region(d, addr, resolve_subpage);
3678d7f2e76SPhilippe Mathieu-Daudé /* Compute offset within MemoryRegionSection */
3688d7f2e76SPhilippe Mathieu-Daudé addr -= section->offset_within_address_space;
3698d7f2e76SPhilippe Mathieu-Daudé
3708d7f2e76SPhilippe Mathieu-Daudé /* Compute offset within MemoryRegion */
3718d7f2e76SPhilippe Mathieu-Daudé *xlat = addr + section->offset_within_region;
3728d7f2e76SPhilippe Mathieu-Daudé
3738d7f2e76SPhilippe Mathieu-Daudé mr = section->mr;
3748d7f2e76SPhilippe Mathieu-Daudé
3758d7f2e76SPhilippe Mathieu-Daudé /* MMIO registers can be expected to perform full-width accesses based only
3768d7f2e76SPhilippe Mathieu-Daudé * on their address, without considering adjacent registers that could
3778d7f2e76SPhilippe Mathieu-Daudé * decode to completely different MemoryRegions. When such registers
3788d7f2e76SPhilippe Mathieu-Daudé * exist (e.g. I/O ports 0xcf8 and 0xcf9 on most PC chipsets), MMIO
3798d7f2e76SPhilippe Mathieu-Daudé * regions overlap wildly. For this reason we cannot clamp the accesses
3808d7f2e76SPhilippe Mathieu-Daudé * here.
3818d7f2e76SPhilippe Mathieu-Daudé *
3828d7f2e76SPhilippe Mathieu-Daudé * If the length is small (as is the case for address_space_ldl/stl),
3838d7f2e76SPhilippe Mathieu-Daudé * everything works fine. If the incoming length is large, however,
3848d7f2e76SPhilippe Mathieu-Daudé * the caller really has to do the clamping through memory_access_size.
3858d7f2e76SPhilippe Mathieu-Daudé */
3868d7f2e76SPhilippe Mathieu-Daudé if (memory_region_is_ram(mr)) {
3878d7f2e76SPhilippe Mathieu-Daudé diff = int128_sub(section->size, int128_make64(addr));
3888d7f2e76SPhilippe Mathieu-Daudé *plen = int128_get64(int128_min(diff, int128_make64(*plen)));
3898d7f2e76SPhilippe Mathieu-Daudé }
3908d7f2e76SPhilippe Mathieu-Daudé return section;
3918d7f2e76SPhilippe Mathieu-Daudé }
3928d7f2e76SPhilippe Mathieu-Daudé
3938d7f2e76SPhilippe Mathieu-Daudé /**
3948d7f2e76SPhilippe Mathieu-Daudé * address_space_translate_iommu - translate an address through an IOMMU
3958d7f2e76SPhilippe Mathieu-Daudé * memory region and then through the target address space.
3968d7f2e76SPhilippe Mathieu-Daudé *
3978d7f2e76SPhilippe Mathieu-Daudé * @iommu_mr: the IOMMU memory region that we start the translation from
3988d7f2e76SPhilippe Mathieu-Daudé * @addr: the address to be translated through the MMU
3998d7f2e76SPhilippe Mathieu-Daudé * @xlat: the translated address offset within the destination memory region.
4008d7f2e76SPhilippe Mathieu-Daudé * It cannot be %NULL.
4018d7f2e76SPhilippe Mathieu-Daudé * @plen_out: valid read/write length of the translated address. It
4028d7f2e76SPhilippe Mathieu-Daudé * cannot be %NULL.
4038d7f2e76SPhilippe Mathieu-Daudé * @page_mask_out: page mask for the translated address. This
4048d7f2e76SPhilippe Mathieu-Daudé * should only be meaningful for IOMMU translated
4058d7f2e76SPhilippe Mathieu-Daudé * addresses, since there may be huge pages that this bit
4068d7f2e76SPhilippe Mathieu-Daudé * would tell. It can be %NULL if we don't care about it.
4078d7f2e76SPhilippe Mathieu-Daudé * @is_write: whether the translation operation is for write
4088d7f2e76SPhilippe Mathieu-Daudé * @is_mmio: whether this can be MMIO, set true if it can
4098d7f2e76SPhilippe Mathieu-Daudé * @target_as: the address space targeted by the IOMMU
4108d7f2e76SPhilippe Mathieu-Daudé * @attrs: transaction attributes
4118d7f2e76SPhilippe Mathieu-Daudé *
4128d7f2e76SPhilippe Mathieu-Daudé * This function is called from RCU critical section. It is the common
4138d7f2e76SPhilippe Mathieu-Daudé * part of flatview_do_translate and address_space_translate_cached.
4148d7f2e76SPhilippe Mathieu-Daudé */
address_space_translate_iommu(IOMMUMemoryRegion * iommu_mr,hwaddr * xlat,hwaddr * plen_out,hwaddr * page_mask_out,bool is_write,bool is_mmio,AddressSpace ** target_as,MemTxAttrs attrs)4158d7f2e76SPhilippe Mathieu-Daudé static MemoryRegionSection address_space_translate_iommu(IOMMUMemoryRegion *iommu_mr,
4168d7f2e76SPhilippe Mathieu-Daudé hwaddr *xlat,
4178d7f2e76SPhilippe Mathieu-Daudé hwaddr *plen_out,
4188d7f2e76SPhilippe Mathieu-Daudé hwaddr *page_mask_out,
4198d7f2e76SPhilippe Mathieu-Daudé bool is_write,
4208d7f2e76SPhilippe Mathieu-Daudé bool is_mmio,
4218d7f2e76SPhilippe Mathieu-Daudé AddressSpace **target_as,
4228d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs)
4238d7f2e76SPhilippe Mathieu-Daudé {
4248d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *section;
4258d7f2e76SPhilippe Mathieu-Daudé hwaddr page_mask = (hwaddr)-1;
4268d7f2e76SPhilippe Mathieu-Daudé
4278d7f2e76SPhilippe Mathieu-Daudé do {
4288d7f2e76SPhilippe Mathieu-Daudé hwaddr addr = *xlat;
4298d7f2e76SPhilippe Mathieu-Daudé IOMMUMemoryRegionClass *imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
4308d7f2e76SPhilippe Mathieu-Daudé int iommu_idx = 0;
4318d7f2e76SPhilippe Mathieu-Daudé IOMMUTLBEntry iotlb;
4328d7f2e76SPhilippe Mathieu-Daudé
4338d7f2e76SPhilippe Mathieu-Daudé if (imrc->attrs_to_index) {
4348d7f2e76SPhilippe Mathieu-Daudé iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
4358d7f2e76SPhilippe Mathieu-Daudé }
4368d7f2e76SPhilippe Mathieu-Daudé
4378d7f2e76SPhilippe Mathieu-Daudé iotlb = imrc->translate(iommu_mr, addr, is_write ?
4388d7f2e76SPhilippe Mathieu-Daudé IOMMU_WO : IOMMU_RO, iommu_idx);
4398d7f2e76SPhilippe Mathieu-Daudé
4408d7f2e76SPhilippe Mathieu-Daudé if (!(iotlb.perm & (1 << is_write))) {
4418d7f2e76SPhilippe Mathieu-Daudé goto unassigned;
4428d7f2e76SPhilippe Mathieu-Daudé }
4438d7f2e76SPhilippe Mathieu-Daudé
4448d7f2e76SPhilippe Mathieu-Daudé addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
4458d7f2e76SPhilippe Mathieu-Daudé | (addr & iotlb.addr_mask));
4468d7f2e76SPhilippe Mathieu-Daudé page_mask &= iotlb.addr_mask;
4478d7f2e76SPhilippe Mathieu-Daudé *plen_out = MIN(*plen_out, (addr | iotlb.addr_mask) - addr + 1);
4488d7f2e76SPhilippe Mathieu-Daudé *target_as = iotlb.target_as;
4498d7f2e76SPhilippe Mathieu-Daudé
4508d7f2e76SPhilippe Mathieu-Daudé section = address_space_translate_internal(
4518d7f2e76SPhilippe Mathieu-Daudé address_space_to_dispatch(iotlb.target_as), addr, xlat,
4528d7f2e76SPhilippe Mathieu-Daudé plen_out, is_mmio);
4538d7f2e76SPhilippe Mathieu-Daudé
4548d7f2e76SPhilippe Mathieu-Daudé iommu_mr = memory_region_get_iommu(section->mr);
4558d7f2e76SPhilippe Mathieu-Daudé } while (unlikely(iommu_mr));
4568d7f2e76SPhilippe Mathieu-Daudé
4578d7f2e76SPhilippe Mathieu-Daudé if (page_mask_out) {
4588d7f2e76SPhilippe Mathieu-Daudé *page_mask_out = page_mask;
4598d7f2e76SPhilippe Mathieu-Daudé }
4608d7f2e76SPhilippe Mathieu-Daudé return *section;
4618d7f2e76SPhilippe Mathieu-Daudé
4628d7f2e76SPhilippe Mathieu-Daudé unassigned:
4638d7f2e76SPhilippe Mathieu-Daudé return (MemoryRegionSection) { .mr = &io_mem_unassigned };
4648d7f2e76SPhilippe Mathieu-Daudé }
4658d7f2e76SPhilippe Mathieu-Daudé
4668d7f2e76SPhilippe Mathieu-Daudé /**
4678d7f2e76SPhilippe Mathieu-Daudé * flatview_do_translate - translate an address in FlatView
4688d7f2e76SPhilippe Mathieu-Daudé *
4698d7f2e76SPhilippe Mathieu-Daudé * @fv: the flat view that we want to translate on
4708d7f2e76SPhilippe Mathieu-Daudé * @addr: the address to be translated in above address space
4718d7f2e76SPhilippe Mathieu-Daudé * @xlat: the translated address offset within memory region. It
4728d7f2e76SPhilippe Mathieu-Daudé * cannot be @NULL.
4738d7f2e76SPhilippe Mathieu-Daudé * @plen_out: valid read/write length of the translated address. It
4748d7f2e76SPhilippe Mathieu-Daudé * can be @NULL when we don't care about it.
4758d7f2e76SPhilippe Mathieu-Daudé * @page_mask_out: page mask for the translated address. This
4768d7f2e76SPhilippe Mathieu-Daudé * should only be meaningful for IOMMU translated
4778d7f2e76SPhilippe Mathieu-Daudé * addresses, since there may be huge pages that this bit
4788d7f2e76SPhilippe Mathieu-Daudé * would tell. It can be @NULL if we don't care about it.
4798d7f2e76SPhilippe Mathieu-Daudé * @is_write: whether the translation operation is for write
4808d7f2e76SPhilippe Mathieu-Daudé * @is_mmio: whether this can be MMIO, set true if it can
4818d7f2e76SPhilippe Mathieu-Daudé * @target_as: the address space targeted by the IOMMU
4828d7f2e76SPhilippe Mathieu-Daudé * @attrs: memory transaction attributes
4838d7f2e76SPhilippe Mathieu-Daudé *
4848d7f2e76SPhilippe Mathieu-Daudé * This function is called from RCU critical section
4858d7f2e76SPhilippe Mathieu-Daudé */
flatview_do_translate(FlatView * fv,hwaddr addr,hwaddr * xlat,hwaddr * plen_out,hwaddr * page_mask_out,bool is_write,bool is_mmio,AddressSpace ** target_as,MemTxAttrs attrs)4868d7f2e76SPhilippe Mathieu-Daudé static MemoryRegionSection flatview_do_translate(FlatView *fv,
4878d7f2e76SPhilippe Mathieu-Daudé hwaddr addr,
4888d7f2e76SPhilippe Mathieu-Daudé hwaddr *xlat,
4898d7f2e76SPhilippe Mathieu-Daudé hwaddr *plen_out,
4908d7f2e76SPhilippe Mathieu-Daudé hwaddr *page_mask_out,
4918d7f2e76SPhilippe Mathieu-Daudé bool is_write,
4928d7f2e76SPhilippe Mathieu-Daudé bool is_mmio,
4938d7f2e76SPhilippe Mathieu-Daudé AddressSpace **target_as,
4948d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs)
4958d7f2e76SPhilippe Mathieu-Daudé {
4968d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *section;
4978d7f2e76SPhilippe Mathieu-Daudé IOMMUMemoryRegion *iommu_mr;
4988d7f2e76SPhilippe Mathieu-Daudé hwaddr plen = (hwaddr)(-1);
4998d7f2e76SPhilippe Mathieu-Daudé
5008d7f2e76SPhilippe Mathieu-Daudé if (!plen_out) {
5018d7f2e76SPhilippe Mathieu-Daudé plen_out = &plen;
5028d7f2e76SPhilippe Mathieu-Daudé }
5038d7f2e76SPhilippe Mathieu-Daudé
5048d7f2e76SPhilippe Mathieu-Daudé section = address_space_translate_internal(
5058d7f2e76SPhilippe Mathieu-Daudé flatview_to_dispatch(fv), addr, xlat,
5068d7f2e76SPhilippe Mathieu-Daudé plen_out, is_mmio);
5078d7f2e76SPhilippe Mathieu-Daudé
5088d7f2e76SPhilippe Mathieu-Daudé iommu_mr = memory_region_get_iommu(section->mr);
5098d7f2e76SPhilippe Mathieu-Daudé if (unlikely(iommu_mr)) {
5108d7f2e76SPhilippe Mathieu-Daudé return address_space_translate_iommu(iommu_mr, xlat,
5118d7f2e76SPhilippe Mathieu-Daudé plen_out, page_mask_out,
5128d7f2e76SPhilippe Mathieu-Daudé is_write, is_mmio,
5138d7f2e76SPhilippe Mathieu-Daudé target_as, attrs);
5148d7f2e76SPhilippe Mathieu-Daudé }
5158d7f2e76SPhilippe Mathieu-Daudé if (page_mask_out) {
5168d7f2e76SPhilippe Mathieu-Daudé /* Not behind an IOMMU, use default page size. */
5178d7f2e76SPhilippe Mathieu-Daudé *page_mask_out = ~TARGET_PAGE_MASK;
5188d7f2e76SPhilippe Mathieu-Daudé }
5198d7f2e76SPhilippe Mathieu-Daudé
5208d7f2e76SPhilippe Mathieu-Daudé return *section;
5218d7f2e76SPhilippe Mathieu-Daudé }
5228d7f2e76SPhilippe Mathieu-Daudé
5238d7f2e76SPhilippe Mathieu-Daudé /* Called from RCU critical section */
address_space_get_iotlb_entry(AddressSpace * as,hwaddr addr,bool is_write,MemTxAttrs attrs)5248d7f2e76SPhilippe Mathieu-Daudé IOMMUTLBEntry address_space_get_iotlb_entry(AddressSpace *as, hwaddr addr,
5258d7f2e76SPhilippe Mathieu-Daudé bool is_write, MemTxAttrs attrs)
5268d7f2e76SPhilippe Mathieu-Daudé {
5278d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection section;
5288d7f2e76SPhilippe Mathieu-Daudé hwaddr xlat, page_mask;
5298d7f2e76SPhilippe Mathieu-Daudé
5308d7f2e76SPhilippe Mathieu-Daudé /*
5318d7f2e76SPhilippe Mathieu-Daudé * This can never be MMIO, and we don't really care about plen,
5328d7f2e76SPhilippe Mathieu-Daudé * but page mask.
5338d7f2e76SPhilippe Mathieu-Daudé */
5348d7f2e76SPhilippe Mathieu-Daudé section = flatview_do_translate(address_space_to_flatview(as), addr, &xlat,
5358d7f2e76SPhilippe Mathieu-Daudé NULL, &page_mask, is_write, false, &as,
5368d7f2e76SPhilippe Mathieu-Daudé attrs);
5378d7f2e76SPhilippe Mathieu-Daudé
5388d7f2e76SPhilippe Mathieu-Daudé /* Illegal translation */
5398d7f2e76SPhilippe Mathieu-Daudé if (section.mr == &io_mem_unassigned) {
5408d7f2e76SPhilippe Mathieu-Daudé goto iotlb_fail;
5418d7f2e76SPhilippe Mathieu-Daudé }
5428d7f2e76SPhilippe Mathieu-Daudé
5438d7f2e76SPhilippe Mathieu-Daudé /* Convert memory region offset into address space offset */
5448d7f2e76SPhilippe Mathieu-Daudé xlat += section.offset_within_address_space -
5458d7f2e76SPhilippe Mathieu-Daudé section.offset_within_region;
5468d7f2e76SPhilippe Mathieu-Daudé
5478d7f2e76SPhilippe Mathieu-Daudé return (IOMMUTLBEntry) {
5488d7f2e76SPhilippe Mathieu-Daudé .target_as = as,
5498d7f2e76SPhilippe Mathieu-Daudé .iova = addr & ~page_mask,
5508d7f2e76SPhilippe Mathieu-Daudé .translated_addr = xlat & ~page_mask,
5518d7f2e76SPhilippe Mathieu-Daudé .addr_mask = page_mask,
5528d7f2e76SPhilippe Mathieu-Daudé /* IOTLBs are for DMAs, and DMA only allows on RAMs. */
5538d7f2e76SPhilippe Mathieu-Daudé .perm = IOMMU_RW,
5548d7f2e76SPhilippe Mathieu-Daudé };
5558d7f2e76SPhilippe Mathieu-Daudé
5568d7f2e76SPhilippe Mathieu-Daudé iotlb_fail:
5578d7f2e76SPhilippe Mathieu-Daudé return (IOMMUTLBEntry) {0};
5588d7f2e76SPhilippe Mathieu-Daudé }
5598d7f2e76SPhilippe Mathieu-Daudé
5608d7f2e76SPhilippe Mathieu-Daudé /* Called from RCU critical section */
flatview_translate(FlatView * fv,hwaddr addr,hwaddr * xlat,hwaddr * plen,bool is_write,MemTxAttrs attrs)5618d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *flatview_translate(FlatView *fv, hwaddr addr, hwaddr *xlat,
5628d7f2e76SPhilippe Mathieu-Daudé hwaddr *plen, bool is_write,
5638d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs)
5648d7f2e76SPhilippe Mathieu-Daudé {
5658d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr;
5668d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection section;
5678d7f2e76SPhilippe Mathieu-Daudé AddressSpace *as = NULL;
5688d7f2e76SPhilippe Mathieu-Daudé
5698d7f2e76SPhilippe Mathieu-Daudé /* This can be MMIO, so setup MMIO bit. */
5708d7f2e76SPhilippe Mathieu-Daudé section = flatview_do_translate(fv, addr, xlat, plen, NULL,
5718d7f2e76SPhilippe Mathieu-Daudé is_write, true, &as, attrs);
5728d7f2e76SPhilippe Mathieu-Daudé mr = section.mr;
5738d7f2e76SPhilippe Mathieu-Daudé
5748d7f2e76SPhilippe Mathieu-Daudé if (xen_enabled() && memory_access_is_direct(mr, is_write)) {
5758d7f2e76SPhilippe Mathieu-Daudé hwaddr page = ((addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE) - addr;
5768d7f2e76SPhilippe Mathieu-Daudé *plen = MIN(page, *plen);
5778d7f2e76SPhilippe Mathieu-Daudé }
5788d7f2e76SPhilippe Mathieu-Daudé
5798d7f2e76SPhilippe Mathieu-Daudé return mr;
5808d7f2e76SPhilippe Mathieu-Daudé }
5818d7f2e76SPhilippe Mathieu-Daudé
5828d7f2e76SPhilippe Mathieu-Daudé typedef struct TCGIOMMUNotifier {
5838d7f2e76SPhilippe Mathieu-Daudé IOMMUNotifier n;
5848d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr;
5858d7f2e76SPhilippe Mathieu-Daudé CPUState *cpu;
5868d7f2e76SPhilippe Mathieu-Daudé int iommu_idx;
5878d7f2e76SPhilippe Mathieu-Daudé bool active;
5888d7f2e76SPhilippe Mathieu-Daudé } TCGIOMMUNotifier;
5898d7f2e76SPhilippe Mathieu-Daudé
tcg_iommu_unmap_notify(IOMMUNotifier * n,IOMMUTLBEntry * iotlb)5908d7f2e76SPhilippe Mathieu-Daudé static void tcg_iommu_unmap_notify(IOMMUNotifier *n, IOMMUTLBEntry *iotlb)
5918d7f2e76SPhilippe Mathieu-Daudé {
5928d7f2e76SPhilippe Mathieu-Daudé TCGIOMMUNotifier *notifier = container_of(n, TCGIOMMUNotifier, n);
5938d7f2e76SPhilippe Mathieu-Daudé
5948d7f2e76SPhilippe Mathieu-Daudé if (!notifier->active) {
5958d7f2e76SPhilippe Mathieu-Daudé return;
5968d7f2e76SPhilippe Mathieu-Daudé }
5978d7f2e76SPhilippe Mathieu-Daudé tlb_flush(notifier->cpu);
5988d7f2e76SPhilippe Mathieu-Daudé notifier->active = false;
5998d7f2e76SPhilippe Mathieu-Daudé /* We leave the notifier struct on the list to avoid reallocating it later.
6008d7f2e76SPhilippe Mathieu-Daudé * Generally the number of IOMMUs a CPU deals with will be small.
6018d7f2e76SPhilippe Mathieu-Daudé * In any case we can't unregister the iommu notifier from a notify
6028d7f2e76SPhilippe Mathieu-Daudé * callback.
6038d7f2e76SPhilippe Mathieu-Daudé */
6048d7f2e76SPhilippe Mathieu-Daudé }
6058d7f2e76SPhilippe Mathieu-Daudé
tcg_register_iommu_notifier(CPUState * cpu,IOMMUMemoryRegion * iommu_mr,int iommu_idx)6068d7f2e76SPhilippe Mathieu-Daudé static void tcg_register_iommu_notifier(CPUState *cpu,
6078d7f2e76SPhilippe Mathieu-Daudé IOMMUMemoryRegion *iommu_mr,
6088d7f2e76SPhilippe Mathieu-Daudé int iommu_idx)
6098d7f2e76SPhilippe Mathieu-Daudé {
6108d7f2e76SPhilippe Mathieu-Daudé /* Make sure this CPU has an IOMMU notifier registered for this
6118d7f2e76SPhilippe Mathieu-Daudé * IOMMU/IOMMU index combination, so that we can flush its TLB
6128d7f2e76SPhilippe Mathieu-Daudé * when the IOMMU tells us the mappings we've cached have changed.
6138d7f2e76SPhilippe Mathieu-Daudé */
6148d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr = MEMORY_REGION(iommu_mr);
6158d7f2e76SPhilippe Mathieu-Daudé TCGIOMMUNotifier *notifier = NULL;
6168d7f2e76SPhilippe Mathieu-Daudé int i;
6178d7f2e76SPhilippe Mathieu-Daudé
6188d7f2e76SPhilippe Mathieu-Daudé for (i = 0; i < cpu->iommu_notifiers->len; i++) {
6198d7f2e76SPhilippe Mathieu-Daudé notifier = g_array_index(cpu->iommu_notifiers, TCGIOMMUNotifier *, i);
6208d7f2e76SPhilippe Mathieu-Daudé if (notifier->mr == mr && notifier->iommu_idx == iommu_idx) {
6218d7f2e76SPhilippe Mathieu-Daudé break;
6228d7f2e76SPhilippe Mathieu-Daudé }
6238d7f2e76SPhilippe Mathieu-Daudé }
6248d7f2e76SPhilippe Mathieu-Daudé if (i == cpu->iommu_notifiers->len) {
6258d7f2e76SPhilippe Mathieu-Daudé /* Not found, add a new entry at the end of the array */
6268d7f2e76SPhilippe Mathieu-Daudé cpu->iommu_notifiers = g_array_set_size(cpu->iommu_notifiers, i + 1);
6278d7f2e76SPhilippe Mathieu-Daudé notifier = g_new0(TCGIOMMUNotifier, 1);
6288d7f2e76SPhilippe Mathieu-Daudé g_array_index(cpu->iommu_notifiers, TCGIOMMUNotifier *, i) = notifier;
6298d7f2e76SPhilippe Mathieu-Daudé
6308d7f2e76SPhilippe Mathieu-Daudé notifier->mr = mr;
6318d7f2e76SPhilippe Mathieu-Daudé notifier->iommu_idx = iommu_idx;
6328d7f2e76SPhilippe Mathieu-Daudé notifier->cpu = cpu;
6338d7f2e76SPhilippe Mathieu-Daudé /* Rather than trying to register interest in the specific part
6348d7f2e76SPhilippe Mathieu-Daudé * of the iommu's address space that we've accessed and then
6358d7f2e76SPhilippe Mathieu-Daudé * expand it later as subsequent accesses touch more of it, we
6368d7f2e76SPhilippe Mathieu-Daudé * just register interest in the whole thing, on the assumption
6378d7f2e76SPhilippe Mathieu-Daudé * that iommu reconfiguration will be rare.
6388d7f2e76SPhilippe Mathieu-Daudé */
6398d7f2e76SPhilippe Mathieu-Daudé iommu_notifier_init(¬ifier->n,
6408d7f2e76SPhilippe Mathieu-Daudé tcg_iommu_unmap_notify,
6418d7f2e76SPhilippe Mathieu-Daudé IOMMU_NOTIFIER_UNMAP,
6428d7f2e76SPhilippe Mathieu-Daudé 0,
6438d7f2e76SPhilippe Mathieu-Daudé HWADDR_MAX,
6448d7f2e76SPhilippe Mathieu-Daudé iommu_idx);
6458d7f2e76SPhilippe Mathieu-Daudé memory_region_register_iommu_notifier(notifier->mr, ¬ifier->n,
6468d7f2e76SPhilippe Mathieu-Daudé &error_fatal);
6478d7f2e76SPhilippe Mathieu-Daudé }
6488d7f2e76SPhilippe Mathieu-Daudé
6498d7f2e76SPhilippe Mathieu-Daudé if (!notifier->active) {
6508d7f2e76SPhilippe Mathieu-Daudé notifier->active = true;
6518d7f2e76SPhilippe Mathieu-Daudé }
6528d7f2e76SPhilippe Mathieu-Daudé }
6538d7f2e76SPhilippe Mathieu-Daudé
tcg_iommu_free_notifier_list(CPUState * cpu)6548d7f2e76SPhilippe Mathieu-Daudé void tcg_iommu_free_notifier_list(CPUState *cpu)
6558d7f2e76SPhilippe Mathieu-Daudé {
6568d7f2e76SPhilippe Mathieu-Daudé /* Destroy the CPU's notifier list */
6578d7f2e76SPhilippe Mathieu-Daudé int i;
6588d7f2e76SPhilippe Mathieu-Daudé TCGIOMMUNotifier *notifier;
6598d7f2e76SPhilippe Mathieu-Daudé
6608d7f2e76SPhilippe Mathieu-Daudé for (i = 0; i < cpu->iommu_notifiers->len; i++) {
6618d7f2e76SPhilippe Mathieu-Daudé notifier = g_array_index(cpu->iommu_notifiers, TCGIOMMUNotifier *, i);
6628d7f2e76SPhilippe Mathieu-Daudé memory_region_unregister_iommu_notifier(notifier->mr, ¬ifier->n);
6638d7f2e76SPhilippe Mathieu-Daudé g_free(notifier);
6648d7f2e76SPhilippe Mathieu-Daudé }
6658d7f2e76SPhilippe Mathieu-Daudé g_array_free(cpu->iommu_notifiers, true);
6668d7f2e76SPhilippe Mathieu-Daudé }
6678d7f2e76SPhilippe Mathieu-Daudé
tcg_iommu_init_notifier_list(CPUState * cpu)6688d7f2e76SPhilippe Mathieu-Daudé void tcg_iommu_init_notifier_list(CPUState *cpu)
6698d7f2e76SPhilippe Mathieu-Daudé {
6708d7f2e76SPhilippe Mathieu-Daudé cpu->iommu_notifiers = g_array_new(false, true, sizeof(TCGIOMMUNotifier *));
6718d7f2e76SPhilippe Mathieu-Daudé }
6728d7f2e76SPhilippe Mathieu-Daudé
6738d7f2e76SPhilippe Mathieu-Daudé /* Called from RCU critical section */
6748d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *
address_space_translate_for_iotlb(CPUState * cpu,int asidx,hwaddr orig_addr,hwaddr * xlat,hwaddr * plen,MemTxAttrs attrs,int * prot)6758d7f2e76SPhilippe Mathieu-Daudé address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr orig_addr,
6768d7f2e76SPhilippe Mathieu-Daudé hwaddr *xlat, hwaddr *plen,
6778d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs, int *prot)
6788d7f2e76SPhilippe Mathieu-Daudé {
6798d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *section;
6808d7f2e76SPhilippe Mathieu-Daudé IOMMUMemoryRegion *iommu_mr;
6818d7f2e76SPhilippe Mathieu-Daudé IOMMUMemoryRegionClass *imrc;
6828d7f2e76SPhilippe Mathieu-Daudé IOMMUTLBEntry iotlb;
6838d7f2e76SPhilippe Mathieu-Daudé int iommu_idx;
6848d7f2e76SPhilippe Mathieu-Daudé hwaddr addr = orig_addr;
6858d7f2e76SPhilippe Mathieu-Daudé AddressSpaceDispatch *d = cpu->cpu_ases[asidx].memory_dispatch;
6868d7f2e76SPhilippe Mathieu-Daudé
6878d7f2e76SPhilippe Mathieu-Daudé for (;;) {
6888d7f2e76SPhilippe Mathieu-Daudé section = address_space_translate_internal(d, addr, &addr, plen, false);
6898d7f2e76SPhilippe Mathieu-Daudé
6908d7f2e76SPhilippe Mathieu-Daudé iommu_mr = memory_region_get_iommu(section->mr);
6918d7f2e76SPhilippe Mathieu-Daudé if (!iommu_mr) {
6928d7f2e76SPhilippe Mathieu-Daudé break;
6938d7f2e76SPhilippe Mathieu-Daudé }
6948d7f2e76SPhilippe Mathieu-Daudé
6958d7f2e76SPhilippe Mathieu-Daudé imrc = memory_region_get_iommu_class_nocheck(iommu_mr);
6968d7f2e76SPhilippe Mathieu-Daudé
6978d7f2e76SPhilippe Mathieu-Daudé iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
6988d7f2e76SPhilippe Mathieu-Daudé tcg_register_iommu_notifier(cpu, iommu_mr, iommu_idx);
6998d7f2e76SPhilippe Mathieu-Daudé /* We need all the permissions, so pass IOMMU_NONE so the IOMMU
7008d7f2e76SPhilippe Mathieu-Daudé * doesn't short-cut its translation table walk.
7018d7f2e76SPhilippe Mathieu-Daudé */
7028d7f2e76SPhilippe Mathieu-Daudé iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE, iommu_idx);
7038d7f2e76SPhilippe Mathieu-Daudé addr = ((iotlb.translated_addr & ~iotlb.addr_mask)
7048d7f2e76SPhilippe Mathieu-Daudé | (addr & iotlb.addr_mask));
7058d7f2e76SPhilippe Mathieu-Daudé /* Update the caller's prot bits to remove permissions the IOMMU
7068d7f2e76SPhilippe Mathieu-Daudé * is giving us a failure response for. If we get down to no
7078d7f2e76SPhilippe Mathieu-Daudé * permissions left at all we can give up now.
7088d7f2e76SPhilippe Mathieu-Daudé */
7098d7f2e76SPhilippe Mathieu-Daudé if (!(iotlb.perm & IOMMU_RO)) {
7108d7f2e76SPhilippe Mathieu-Daudé *prot &= ~(PAGE_READ | PAGE_EXEC);
7118d7f2e76SPhilippe Mathieu-Daudé }
7128d7f2e76SPhilippe Mathieu-Daudé if (!(iotlb.perm & IOMMU_WO)) {
7138d7f2e76SPhilippe Mathieu-Daudé *prot &= ~PAGE_WRITE;
7148d7f2e76SPhilippe Mathieu-Daudé }
7158d7f2e76SPhilippe Mathieu-Daudé
7168d7f2e76SPhilippe Mathieu-Daudé if (!*prot) {
7178d7f2e76SPhilippe Mathieu-Daudé goto translate_fail;
7188d7f2e76SPhilippe Mathieu-Daudé }
7198d7f2e76SPhilippe Mathieu-Daudé
7208d7f2e76SPhilippe Mathieu-Daudé d = flatview_to_dispatch(address_space_to_flatview(iotlb.target_as));
7218d7f2e76SPhilippe Mathieu-Daudé }
7228d7f2e76SPhilippe Mathieu-Daudé
7238d7f2e76SPhilippe Mathieu-Daudé assert(!memory_region_is_iommu(section->mr));
7248d7f2e76SPhilippe Mathieu-Daudé *xlat = addr;
7258d7f2e76SPhilippe Mathieu-Daudé return section;
7268d7f2e76SPhilippe Mathieu-Daudé
7278d7f2e76SPhilippe Mathieu-Daudé translate_fail:
7288d7f2e76SPhilippe Mathieu-Daudé /*
7298d7f2e76SPhilippe Mathieu-Daudé * We should be given a page-aligned address -- certainly
7308d7f2e76SPhilippe Mathieu-Daudé * tlb_set_page_with_attrs() does so. The page offset of xlat
7318d7f2e76SPhilippe Mathieu-Daudé * is used to index sections[], and PHYS_SECTION_UNASSIGNED = 0.
7328d7f2e76SPhilippe Mathieu-Daudé * The page portion of xlat will be logged by memory_region_access_valid()
7338d7f2e76SPhilippe Mathieu-Daudé * when this memory access is rejected, so use the original untranslated
7348d7f2e76SPhilippe Mathieu-Daudé * physical address.
7358d7f2e76SPhilippe Mathieu-Daudé */
7368d7f2e76SPhilippe Mathieu-Daudé assert((orig_addr & ~TARGET_PAGE_MASK) == 0);
7378d7f2e76SPhilippe Mathieu-Daudé *xlat = orig_addr;
7388d7f2e76SPhilippe Mathieu-Daudé return &d->map.sections[PHYS_SECTION_UNASSIGNED];
7398d7f2e76SPhilippe Mathieu-Daudé }
7408d7f2e76SPhilippe Mathieu-Daudé
cpu_address_space_init(CPUState * cpu,int asidx,const char * prefix,MemoryRegion * mr)7418d7f2e76SPhilippe Mathieu-Daudé void cpu_address_space_init(CPUState *cpu, int asidx,
7428d7f2e76SPhilippe Mathieu-Daudé const char *prefix, MemoryRegion *mr)
7438d7f2e76SPhilippe Mathieu-Daudé {
7448d7f2e76SPhilippe Mathieu-Daudé CPUAddressSpace *newas;
7458d7f2e76SPhilippe Mathieu-Daudé AddressSpace *as = g_new0(AddressSpace, 1);
7468d7f2e76SPhilippe Mathieu-Daudé char *as_name;
7478d7f2e76SPhilippe Mathieu-Daudé
7488d7f2e76SPhilippe Mathieu-Daudé assert(mr);
7498d7f2e76SPhilippe Mathieu-Daudé as_name = g_strdup_printf("%s-%d", prefix, cpu->cpu_index);
7508d7f2e76SPhilippe Mathieu-Daudé address_space_init(as, mr, as_name);
7518d7f2e76SPhilippe Mathieu-Daudé g_free(as_name);
7528d7f2e76SPhilippe Mathieu-Daudé
7538d7f2e76SPhilippe Mathieu-Daudé /* Target code should have set num_ases before calling us */
7548d7f2e76SPhilippe Mathieu-Daudé assert(asidx < cpu->num_ases);
7558d7f2e76SPhilippe Mathieu-Daudé
7568d7f2e76SPhilippe Mathieu-Daudé if (asidx == 0) {
7578d7f2e76SPhilippe Mathieu-Daudé /* address space 0 gets the convenience alias */
7588d7f2e76SPhilippe Mathieu-Daudé cpu->as = as;
7598d7f2e76SPhilippe Mathieu-Daudé }
7608d7f2e76SPhilippe Mathieu-Daudé
7618d7f2e76SPhilippe Mathieu-Daudé /* KVM cannot currently support multiple address spaces. */
7628d7f2e76SPhilippe Mathieu-Daudé assert(asidx == 0 || !kvm_enabled());
7638d7f2e76SPhilippe Mathieu-Daudé
7648d7f2e76SPhilippe Mathieu-Daudé if (!cpu->cpu_ases) {
7658d7f2e76SPhilippe Mathieu-Daudé cpu->cpu_ases = g_new0(CPUAddressSpace, cpu->num_ases);
76624bec42fSSalil Mehta cpu->cpu_ases_count = cpu->num_ases;
7678d7f2e76SPhilippe Mathieu-Daudé }
7688d7f2e76SPhilippe Mathieu-Daudé
7698d7f2e76SPhilippe Mathieu-Daudé newas = &cpu->cpu_ases[asidx];
7708d7f2e76SPhilippe Mathieu-Daudé newas->cpu = cpu;
7718d7f2e76SPhilippe Mathieu-Daudé newas->as = as;
7728d7f2e76SPhilippe Mathieu-Daudé if (tcg_enabled()) {
7738d7f2e76SPhilippe Mathieu-Daudé newas->tcg_as_listener.log_global_after_sync = tcg_log_global_after_sync;
7748d7f2e76SPhilippe Mathieu-Daudé newas->tcg_as_listener.commit = tcg_commit;
7758d7f2e76SPhilippe Mathieu-Daudé newas->tcg_as_listener.name = "tcg";
7768d7f2e76SPhilippe Mathieu-Daudé memory_listener_register(&newas->tcg_as_listener, as);
7778d7f2e76SPhilippe Mathieu-Daudé }
7788d7f2e76SPhilippe Mathieu-Daudé }
7798d7f2e76SPhilippe Mathieu-Daudé
cpu_address_space_destroy(CPUState * cpu,int asidx)78024bec42fSSalil Mehta void cpu_address_space_destroy(CPUState *cpu, int asidx)
78124bec42fSSalil Mehta {
78224bec42fSSalil Mehta CPUAddressSpace *cpuas;
78324bec42fSSalil Mehta
78424bec42fSSalil Mehta assert(cpu->cpu_ases);
78524bec42fSSalil Mehta assert(asidx >= 0 && asidx < cpu->num_ases);
78624bec42fSSalil Mehta /* KVM cannot currently support multiple address spaces. */
78724bec42fSSalil Mehta assert(asidx == 0 || !kvm_enabled());
78824bec42fSSalil Mehta
78924bec42fSSalil Mehta cpuas = &cpu->cpu_ases[asidx];
79024bec42fSSalil Mehta if (tcg_enabled()) {
79124bec42fSSalil Mehta memory_listener_unregister(&cpuas->tcg_as_listener);
79224bec42fSSalil Mehta }
79324bec42fSSalil Mehta
79424bec42fSSalil Mehta address_space_destroy(cpuas->as);
79524bec42fSSalil Mehta g_free_rcu(cpuas->as, rcu);
79624bec42fSSalil Mehta
79724bec42fSSalil Mehta if (asidx == 0) {
79824bec42fSSalil Mehta /* reset the convenience alias for address space 0 */
79924bec42fSSalil Mehta cpu->as = NULL;
80024bec42fSSalil Mehta }
80124bec42fSSalil Mehta
80224bec42fSSalil Mehta if (--cpu->cpu_ases_count == 0) {
80324bec42fSSalil Mehta g_free(cpu->cpu_ases);
80424bec42fSSalil Mehta cpu->cpu_ases = NULL;
80524bec42fSSalil Mehta }
80624bec42fSSalil Mehta }
80724bec42fSSalil Mehta
cpu_get_address_space(CPUState * cpu,int asidx)8088d7f2e76SPhilippe Mathieu-Daudé AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx)
8098d7f2e76SPhilippe Mathieu-Daudé {
8108d7f2e76SPhilippe Mathieu-Daudé /* Return the AddressSpace corresponding to the specified index */
8118d7f2e76SPhilippe Mathieu-Daudé return cpu->cpu_ases[asidx].as;
8128d7f2e76SPhilippe Mathieu-Daudé }
8138d7f2e76SPhilippe Mathieu-Daudé
8148d7f2e76SPhilippe Mathieu-Daudé /* Called from RCU critical section */
qemu_get_ram_block(ram_addr_t addr)8158d7f2e76SPhilippe Mathieu-Daudé static RAMBlock *qemu_get_ram_block(ram_addr_t addr)
8168d7f2e76SPhilippe Mathieu-Daudé {
8178d7f2e76SPhilippe Mathieu-Daudé RAMBlock *block;
8188d7f2e76SPhilippe Mathieu-Daudé
8198d7f2e76SPhilippe Mathieu-Daudé block = qatomic_rcu_read(&ram_list.mru_block);
8208d7f2e76SPhilippe Mathieu-Daudé if (block && addr - block->offset < block->max_length) {
8218d7f2e76SPhilippe Mathieu-Daudé return block;
8228d7f2e76SPhilippe Mathieu-Daudé }
8238d7f2e76SPhilippe Mathieu-Daudé RAMBLOCK_FOREACH(block) {
8248d7f2e76SPhilippe Mathieu-Daudé if (addr - block->offset < block->max_length) {
8258d7f2e76SPhilippe Mathieu-Daudé goto found;
8268d7f2e76SPhilippe Mathieu-Daudé }
8278d7f2e76SPhilippe Mathieu-Daudé }
8288d7f2e76SPhilippe Mathieu-Daudé
8298d7f2e76SPhilippe Mathieu-Daudé fprintf(stderr, "Bad ram offset %" PRIx64 "\n", (uint64_t)addr);
8308d7f2e76SPhilippe Mathieu-Daudé abort();
8318d7f2e76SPhilippe Mathieu-Daudé
8328d7f2e76SPhilippe Mathieu-Daudé found:
833a4a411fbSStefan Hajnoczi /* It is safe to write mru_block outside the BQL. This
8348d7f2e76SPhilippe Mathieu-Daudé * is what happens:
8358d7f2e76SPhilippe Mathieu-Daudé *
8368d7f2e76SPhilippe Mathieu-Daudé * mru_block = xxx
8378d7f2e76SPhilippe Mathieu-Daudé * rcu_read_unlock()
8388d7f2e76SPhilippe Mathieu-Daudé * xxx removed from list
8398d7f2e76SPhilippe Mathieu-Daudé * rcu_read_lock()
8408d7f2e76SPhilippe Mathieu-Daudé * read mru_block
8418d7f2e76SPhilippe Mathieu-Daudé * mru_block = NULL;
8428d7f2e76SPhilippe Mathieu-Daudé * call_rcu(reclaim_ramblock, xxx);
8438d7f2e76SPhilippe Mathieu-Daudé * rcu_read_unlock()
8448d7f2e76SPhilippe Mathieu-Daudé *
8458d7f2e76SPhilippe Mathieu-Daudé * qatomic_rcu_set is not needed here. The block was already published
8468d7f2e76SPhilippe Mathieu-Daudé * when it was placed into the list. Here we're just making an extra
8478d7f2e76SPhilippe Mathieu-Daudé * copy of the pointer.
8488d7f2e76SPhilippe Mathieu-Daudé */
8498d7f2e76SPhilippe Mathieu-Daudé ram_list.mru_block = block;
8508d7f2e76SPhilippe Mathieu-Daudé return block;
8518d7f2e76SPhilippe Mathieu-Daudé }
8528d7f2e76SPhilippe Mathieu-Daudé
tlb_reset_dirty_range_all(ram_addr_t start,ram_addr_t length)8537e8ccf99SPhilippe Mathieu-Daudé void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length)
8548d7f2e76SPhilippe Mathieu-Daudé {
8558d7f2e76SPhilippe Mathieu-Daudé CPUState *cpu;
8568d7f2e76SPhilippe Mathieu-Daudé ram_addr_t start1;
8578d7f2e76SPhilippe Mathieu-Daudé RAMBlock *block;
8588d7f2e76SPhilippe Mathieu-Daudé ram_addr_t end;
8598d7f2e76SPhilippe Mathieu-Daudé
8608d7f2e76SPhilippe Mathieu-Daudé assert(tcg_enabled());
8618d7f2e76SPhilippe Mathieu-Daudé end = TARGET_PAGE_ALIGN(start + length);
8628d7f2e76SPhilippe Mathieu-Daudé start &= TARGET_PAGE_MASK;
8638d7f2e76SPhilippe Mathieu-Daudé
8648d7f2e76SPhilippe Mathieu-Daudé RCU_READ_LOCK_GUARD();
8658d7f2e76SPhilippe Mathieu-Daudé block = qemu_get_ram_block(start);
8668d7f2e76SPhilippe Mathieu-Daudé assert(block == qemu_get_ram_block(end - 1));
8678d7f2e76SPhilippe Mathieu-Daudé start1 = (uintptr_t)ramblock_ptr(block, start - block->offset);
8688d7f2e76SPhilippe Mathieu-Daudé CPU_FOREACH(cpu) {
8698d7f2e76SPhilippe Mathieu-Daudé tlb_reset_dirty(cpu, start1, length);
8708d7f2e76SPhilippe Mathieu-Daudé }
8718d7f2e76SPhilippe Mathieu-Daudé }
8728d7f2e76SPhilippe Mathieu-Daudé
8738d7f2e76SPhilippe Mathieu-Daudé /* Note: start and end must be within the same ram block. */
cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,ram_addr_t length,unsigned client)8748d7f2e76SPhilippe Mathieu-Daudé bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
8758d7f2e76SPhilippe Mathieu-Daudé ram_addr_t length,
8768d7f2e76SPhilippe Mathieu-Daudé unsigned client)
8778d7f2e76SPhilippe Mathieu-Daudé {
8788d7f2e76SPhilippe Mathieu-Daudé DirtyMemoryBlocks *blocks;
8798d7f2e76SPhilippe Mathieu-Daudé unsigned long end, page, start_page;
8808d7f2e76SPhilippe Mathieu-Daudé bool dirty = false;
8818d7f2e76SPhilippe Mathieu-Daudé RAMBlock *ramblock;
8828d7f2e76SPhilippe Mathieu-Daudé uint64_t mr_offset, mr_size;
8838d7f2e76SPhilippe Mathieu-Daudé
8848d7f2e76SPhilippe Mathieu-Daudé if (length == 0) {
8858d7f2e76SPhilippe Mathieu-Daudé return false;
8868d7f2e76SPhilippe Mathieu-Daudé }
8878d7f2e76SPhilippe Mathieu-Daudé
8888d7f2e76SPhilippe Mathieu-Daudé end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
8898d7f2e76SPhilippe Mathieu-Daudé start_page = start >> TARGET_PAGE_BITS;
8908d7f2e76SPhilippe Mathieu-Daudé page = start_page;
8918d7f2e76SPhilippe Mathieu-Daudé
8928d7f2e76SPhilippe Mathieu-Daudé WITH_RCU_READ_LOCK_GUARD() {
8938d7f2e76SPhilippe Mathieu-Daudé blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]);
8948d7f2e76SPhilippe Mathieu-Daudé ramblock = qemu_get_ram_block(start);
8958d7f2e76SPhilippe Mathieu-Daudé /* Range sanity check on the ramblock */
8968d7f2e76SPhilippe Mathieu-Daudé assert(start >= ramblock->offset &&
8978d7f2e76SPhilippe Mathieu-Daudé start + length <= ramblock->offset + ramblock->used_length);
8988d7f2e76SPhilippe Mathieu-Daudé
8998d7f2e76SPhilippe Mathieu-Daudé while (page < end) {
9008d7f2e76SPhilippe Mathieu-Daudé unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE;
9018d7f2e76SPhilippe Mathieu-Daudé unsigned long offset = page % DIRTY_MEMORY_BLOCK_SIZE;
9028d7f2e76SPhilippe Mathieu-Daudé unsigned long num = MIN(end - page,
9038d7f2e76SPhilippe Mathieu-Daudé DIRTY_MEMORY_BLOCK_SIZE - offset);
9048d7f2e76SPhilippe Mathieu-Daudé
9058d7f2e76SPhilippe Mathieu-Daudé dirty |= bitmap_test_and_clear_atomic(blocks->blocks[idx],
9068d7f2e76SPhilippe Mathieu-Daudé offset, num);
9078d7f2e76SPhilippe Mathieu-Daudé page += num;
9088d7f2e76SPhilippe Mathieu-Daudé }
9098d7f2e76SPhilippe Mathieu-Daudé
9108d7f2e76SPhilippe Mathieu-Daudé mr_offset = (ram_addr_t)(start_page << TARGET_PAGE_BITS) - ramblock->offset;
9118d7f2e76SPhilippe Mathieu-Daudé mr_size = (end - start_page) << TARGET_PAGE_BITS;
9128d7f2e76SPhilippe Mathieu-Daudé memory_region_clear_dirty_bitmap(ramblock->mr, mr_offset, mr_size);
9138d7f2e76SPhilippe Mathieu-Daudé }
9148d7f2e76SPhilippe Mathieu-Daudé
91586a9ae80SNicholas Piggin if (dirty) {
91686a9ae80SNicholas Piggin cpu_physical_memory_dirty_bits_cleared(start, length);
9178d7f2e76SPhilippe Mathieu-Daudé }
9188d7f2e76SPhilippe Mathieu-Daudé
9198d7f2e76SPhilippe Mathieu-Daudé return dirty;
9208d7f2e76SPhilippe Mathieu-Daudé }
9218d7f2e76SPhilippe Mathieu-Daudé
cpu_physical_memory_snapshot_and_clear_dirty(MemoryRegion * mr,hwaddr offset,hwaddr length,unsigned client)9228d7f2e76SPhilippe Mathieu-Daudé DirtyBitmapSnapshot *cpu_physical_memory_snapshot_and_clear_dirty
9238d7f2e76SPhilippe Mathieu-Daudé (MemoryRegion *mr, hwaddr offset, hwaddr length, unsigned client)
9248d7f2e76SPhilippe Mathieu-Daudé {
9258d7f2e76SPhilippe Mathieu-Daudé DirtyMemoryBlocks *blocks;
92673188068SPeter Maydell ram_addr_t start, first, last;
9278d7f2e76SPhilippe Mathieu-Daudé unsigned long align = 1UL << (TARGET_PAGE_BITS + BITS_PER_LEVEL);
9288d7f2e76SPhilippe Mathieu-Daudé DirtyBitmapSnapshot *snap;
9298d7f2e76SPhilippe Mathieu-Daudé unsigned long page, end, dest;
9308d7f2e76SPhilippe Mathieu-Daudé
93173188068SPeter Maydell start = memory_region_get_ram_addr(mr);
93273188068SPeter Maydell /* We know we're only called for RAM MemoryRegions */
93373188068SPeter Maydell assert(start != RAM_ADDR_INVALID);
93473188068SPeter Maydell start += offset;
93573188068SPeter Maydell
93673188068SPeter Maydell first = QEMU_ALIGN_DOWN(start, align);
93773188068SPeter Maydell last = QEMU_ALIGN_UP(start + length, align);
93873188068SPeter Maydell
9398d7f2e76SPhilippe Mathieu-Daudé snap = g_malloc0(sizeof(*snap) +
9408d7f2e76SPhilippe Mathieu-Daudé ((last - first) >> (TARGET_PAGE_BITS + 3)));
9418d7f2e76SPhilippe Mathieu-Daudé snap->start = first;
9428d7f2e76SPhilippe Mathieu-Daudé snap->end = last;
9438d7f2e76SPhilippe Mathieu-Daudé
9448d7f2e76SPhilippe Mathieu-Daudé page = first >> TARGET_PAGE_BITS;
9458d7f2e76SPhilippe Mathieu-Daudé end = last >> TARGET_PAGE_BITS;
9468d7f2e76SPhilippe Mathieu-Daudé dest = 0;
9478d7f2e76SPhilippe Mathieu-Daudé
9488d7f2e76SPhilippe Mathieu-Daudé WITH_RCU_READ_LOCK_GUARD() {
9498d7f2e76SPhilippe Mathieu-Daudé blocks = qatomic_rcu_read(&ram_list.dirty_memory[client]);
9508d7f2e76SPhilippe Mathieu-Daudé
9518d7f2e76SPhilippe Mathieu-Daudé while (page < end) {
9528d7f2e76SPhilippe Mathieu-Daudé unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE;
9538d7f2e76SPhilippe Mathieu-Daudé unsigned long ofs = page % DIRTY_MEMORY_BLOCK_SIZE;
9548d7f2e76SPhilippe Mathieu-Daudé unsigned long num = MIN(end - page,
9558d7f2e76SPhilippe Mathieu-Daudé DIRTY_MEMORY_BLOCK_SIZE - ofs);
9568d7f2e76SPhilippe Mathieu-Daudé
9578d7f2e76SPhilippe Mathieu-Daudé assert(QEMU_IS_ALIGNED(ofs, (1 << BITS_PER_LEVEL)));
9588d7f2e76SPhilippe Mathieu-Daudé assert(QEMU_IS_ALIGNED(num, (1 << BITS_PER_LEVEL)));
9598d7f2e76SPhilippe Mathieu-Daudé ofs >>= BITS_PER_LEVEL;
9608d7f2e76SPhilippe Mathieu-Daudé
9618d7f2e76SPhilippe Mathieu-Daudé bitmap_copy_and_clear_atomic(snap->dirty + dest,
9628d7f2e76SPhilippe Mathieu-Daudé blocks->blocks[idx] + ofs,
9638d7f2e76SPhilippe Mathieu-Daudé num);
9648d7f2e76SPhilippe Mathieu-Daudé page += num;
9658d7f2e76SPhilippe Mathieu-Daudé dest += num >> BITS_PER_LEVEL;
9668d7f2e76SPhilippe Mathieu-Daudé }
9678d7f2e76SPhilippe Mathieu-Daudé }
9688d7f2e76SPhilippe Mathieu-Daudé
96986a9ae80SNicholas Piggin cpu_physical_memory_dirty_bits_cleared(start, length);
9708d7f2e76SPhilippe Mathieu-Daudé
9718d7f2e76SPhilippe Mathieu-Daudé memory_region_clear_dirty_bitmap(mr, offset, length);
9728d7f2e76SPhilippe Mathieu-Daudé
9738d7f2e76SPhilippe Mathieu-Daudé return snap;
9748d7f2e76SPhilippe Mathieu-Daudé }
9758d7f2e76SPhilippe Mathieu-Daudé
cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot * snap,ram_addr_t start,ram_addr_t length)9768d7f2e76SPhilippe Mathieu-Daudé bool cpu_physical_memory_snapshot_get_dirty(DirtyBitmapSnapshot *snap,
9778d7f2e76SPhilippe Mathieu-Daudé ram_addr_t start,
9788d7f2e76SPhilippe Mathieu-Daudé ram_addr_t length)
9798d7f2e76SPhilippe Mathieu-Daudé {
9808d7f2e76SPhilippe Mathieu-Daudé unsigned long page, end;
9818d7f2e76SPhilippe Mathieu-Daudé
9828d7f2e76SPhilippe Mathieu-Daudé assert(start >= snap->start);
9838d7f2e76SPhilippe Mathieu-Daudé assert(start + length <= snap->end);
9848d7f2e76SPhilippe Mathieu-Daudé
9858d7f2e76SPhilippe Mathieu-Daudé end = TARGET_PAGE_ALIGN(start + length - snap->start) >> TARGET_PAGE_BITS;
9868d7f2e76SPhilippe Mathieu-Daudé page = (start - snap->start) >> TARGET_PAGE_BITS;
9878d7f2e76SPhilippe Mathieu-Daudé
9888d7f2e76SPhilippe Mathieu-Daudé while (page < end) {
9898d7f2e76SPhilippe Mathieu-Daudé if (test_bit(page, snap->dirty)) {
9908d7f2e76SPhilippe Mathieu-Daudé return true;
9918d7f2e76SPhilippe Mathieu-Daudé }
9928d7f2e76SPhilippe Mathieu-Daudé page++;
9938d7f2e76SPhilippe Mathieu-Daudé }
9948d7f2e76SPhilippe Mathieu-Daudé return false;
9958d7f2e76SPhilippe Mathieu-Daudé }
9968d7f2e76SPhilippe Mathieu-Daudé
9978d7f2e76SPhilippe Mathieu-Daudé /* Called from RCU critical section */
memory_region_section_get_iotlb(CPUState * cpu,MemoryRegionSection * section)9988d7f2e76SPhilippe Mathieu-Daudé hwaddr memory_region_section_get_iotlb(CPUState *cpu,
9998d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *section)
10008d7f2e76SPhilippe Mathieu-Daudé {
10018d7f2e76SPhilippe Mathieu-Daudé AddressSpaceDispatch *d = flatview_to_dispatch(section->fv);
10028d7f2e76SPhilippe Mathieu-Daudé return section - d->map.sections;
10038d7f2e76SPhilippe Mathieu-Daudé }
10048d7f2e76SPhilippe Mathieu-Daudé
10058d7f2e76SPhilippe Mathieu-Daudé static int subpage_register(subpage_t *mmio, uint32_t start, uint32_t end,
10068d7f2e76SPhilippe Mathieu-Daudé uint16_t section);
10078d7f2e76SPhilippe Mathieu-Daudé static subpage_t *subpage_init(FlatView *fv, hwaddr base);
10088d7f2e76SPhilippe Mathieu-Daudé
phys_section_add(PhysPageMap * map,MemoryRegionSection * section)10098d7f2e76SPhilippe Mathieu-Daudé static uint16_t phys_section_add(PhysPageMap *map,
10108d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *section)
10118d7f2e76SPhilippe Mathieu-Daudé {
10128d7f2e76SPhilippe Mathieu-Daudé /* The physical section number is ORed with a page-aligned
10138d7f2e76SPhilippe Mathieu-Daudé * pointer to produce the iotlb entries. Thus it should
10148d7f2e76SPhilippe Mathieu-Daudé * never overflow into the page-aligned value.
10158d7f2e76SPhilippe Mathieu-Daudé */
10168d7f2e76SPhilippe Mathieu-Daudé assert(map->sections_nb < TARGET_PAGE_SIZE);
10178d7f2e76SPhilippe Mathieu-Daudé
10188d7f2e76SPhilippe Mathieu-Daudé if (map->sections_nb == map->sections_nb_alloc) {
10198d7f2e76SPhilippe Mathieu-Daudé map->sections_nb_alloc = MAX(map->sections_nb_alloc * 2, 16);
10208d7f2e76SPhilippe Mathieu-Daudé map->sections = g_renew(MemoryRegionSection, map->sections,
10218d7f2e76SPhilippe Mathieu-Daudé map->sections_nb_alloc);
10228d7f2e76SPhilippe Mathieu-Daudé }
10238d7f2e76SPhilippe Mathieu-Daudé map->sections[map->sections_nb] = *section;
10248d7f2e76SPhilippe Mathieu-Daudé memory_region_ref(section->mr);
10258d7f2e76SPhilippe Mathieu-Daudé return map->sections_nb++;
10268d7f2e76SPhilippe Mathieu-Daudé }
10278d7f2e76SPhilippe Mathieu-Daudé
phys_section_destroy(MemoryRegion * mr)10288d7f2e76SPhilippe Mathieu-Daudé static void phys_section_destroy(MemoryRegion *mr)
10298d7f2e76SPhilippe Mathieu-Daudé {
10308d7f2e76SPhilippe Mathieu-Daudé bool have_sub_page = mr->subpage;
10318d7f2e76SPhilippe Mathieu-Daudé
10328d7f2e76SPhilippe Mathieu-Daudé memory_region_unref(mr);
10338d7f2e76SPhilippe Mathieu-Daudé
10348d7f2e76SPhilippe Mathieu-Daudé if (have_sub_page) {
10358d7f2e76SPhilippe Mathieu-Daudé subpage_t *subpage = container_of(mr, subpage_t, iomem);
10368d7f2e76SPhilippe Mathieu-Daudé object_unref(OBJECT(&subpage->iomem));
10378d7f2e76SPhilippe Mathieu-Daudé g_free(subpage);
10388d7f2e76SPhilippe Mathieu-Daudé }
10398d7f2e76SPhilippe Mathieu-Daudé }
10408d7f2e76SPhilippe Mathieu-Daudé
phys_sections_free(PhysPageMap * map)10418d7f2e76SPhilippe Mathieu-Daudé static void phys_sections_free(PhysPageMap *map)
10428d7f2e76SPhilippe Mathieu-Daudé {
10438d7f2e76SPhilippe Mathieu-Daudé while (map->sections_nb > 0) {
10448d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *section = &map->sections[--map->sections_nb];
10458d7f2e76SPhilippe Mathieu-Daudé phys_section_destroy(section->mr);
10468d7f2e76SPhilippe Mathieu-Daudé }
10478d7f2e76SPhilippe Mathieu-Daudé g_free(map->sections);
10488d7f2e76SPhilippe Mathieu-Daudé g_free(map->nodes);
10498d7f2e76SPhilippe Mathieu-Daudé }
10508d7f2e76SPhilippe Mathieu-Daudé
register_subpage(FlatView * fv,MemoryRegionSection * section)10518d7f2e76SPhilippe Mathieu-Daudé static void register_subpage(FlatView *fv, MemoryRegionSection *section)
10528d7f2e76SPhilippe Mathieu-Daudé {
10538d7f2e76SPhilippe Mathieu-Daudé AddressSpaceDispatch *d = flatview_to_dispatch(fv);
10548d7f2e76SPhilippe Mathieu-Daudé subpage_t *subpage;
10558d7f2e76SPhilippe Mathieu-Daudé hwaddr base = section->offset_within_address_space
10568d7f2e76SPhilippe Mathieu-Daudé & TARGET_PAGE_MASK;
10578d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *existing = phys_page_find(d, base);
10588d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection subsection = {
10598d7f2e76SPhilippe Mathieu-Daudé .offset_within_address_space = base,
10608d7f2e76SPhilippe Mathieu-Daudé .size = int128_make64(TARGET_PAGE_SIZE),
10618d7f2e76SPhilippe Mathieu-Daudé };
10628d7f2e76SPhilippe Mathieu-Daudé hwaddr start, end;
10638d7f2e76SPhilippe Mathieu-Daudé
10648d7f2e76SPhilippe Mathieu-Daudé assert(existing->mr->subpage || existing->mr == &io_mem_unassigned);
10658d7f2e76SPhilippe Mathieu-Daudé
10668d7f2e76SPhilippe Mathieu-Daudé if (!(existing->mr->subpage)) {
10678d7f2e76SPhilippe Mathieu-Daudé subpage = subpage_init(fv, base);
10688d7f2e76SPhilippe Mathieu-Daudé subsection.fv = fv;
10698d7f2e76SPhilippe Mathieu-Daudé subsection.mr = &subpage->iomem;
10708d7f2e76SPhilippe Mathieu-Daudé phys_page_set(d, base >> TARGET_PAGE_BITS, 1,
10718d7f2e76SPhilippe Mathieu-Daudé phys_section_add(&d->map, &subsection));
10728d7f2e76SPhilippe Mathieu-Daudé } else {
10738d7f2e76SPhilippe Mathieu-Daudé subpage = container_of(existing->mr, subpage_t, iomem);
10748d7f2e76SPhilippe Mathieu-Daudé }
10758d7f2e76SPhilippe Mathieu-Daudé start = section->offset_within_address_space & ~TARGET_PAGE_MASK;
10768d7f2e76SPhilippe Mathieu-Daudé end = start + int128_get64(section->size) - 1;
10778d7f2e76SPhilippe Mathieu-Daudé subpage_register(subpage, start, end,
10788d7f2e76SPhilippe Mathieu-Daudé phys_section_add(&d->map, section));
10798d7f2e76SPhilippe Mathieu-Daudé }
10808d7f2e76SPhilippe Mathieu-Daudé
10818d7f2e76SPhilippe Mathieu-Daudé
register_multipage(FlatView * fv,MemoryRegionSection * section)10828d7f2e76SPhilippe Mathieu-Daudé static void register_multipage(FlatView *fv,
10838d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *section)
10848d7f2e76SPhilippe Mathieu-Daudé {
10858d7f2e76SPhilippe Mathieu-Daudé AddressSpaceDispatch *d = flatview_to_dispatch(fv);
10868d7f2e76SPhilippe Mathieu-Daudé hwaddr start_addr = section->offset_within_address_space;
10878d7f2e76SPhilippe Mathieu-Daudé uint16_t section_index = phys_section_add(&d->map, section);
10888d7f2e76SPhilippe Mathieu-Daudé uint64_t num_pages = int128_get64(int128_rshift(section->size,
10898d7f2e76SPhilippe Mathieu-Daudé TARGET_PAGE_BITS));
10908d7f2e76SPhilippe Mathieu-Daudé
10918d7f2e76SPhilippe Mathieu-Daudé assert(num_pages);
10928d7f2e76SPhilippe Mathieu-Daudé phys_page_set(d, start_addr >> TARGET_PAGE_BITS, num_pages, section_index);
10938d7f2e76SPhilippe Mathieu-Daudé }
10948d7f2e76SPhilippe Mathieu-Daudé
10958d7f2e76SPhilippe Mathieu-Daudé /*
10968d7f2e76SPhilippe Mathieu-Daudé * The range in *section* may look like this:
10978d7f2e76SPhilippe Mathieu-Daudé *
10988d7f2e76SPhilippe Mathieu-Daudé * |s|PPPPPPP|s|
10998d7f2e76SPhilippe Mathieu-Daudé *
11008d7f2e76SPhilippe Mathieu-Daudé * where s stands for subpage and P for page.
11018d7f2e76SPhilippe Mathieu-Daudé */
flatview_add_to_dispatch(FlatView * fv,MemoryRegionSection * section)11028d7f2e76SPhilippe Mathieu-Daudé void flatview_add_to_dispatch(FlatView *fv, MemoryRegionSection *section)
11038d7f2e76SPhilippe Mathieu-Daudé {
11048d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection remain = *section;
11058d7f2e76SPhilippe Mathieu-Daudé Int128 page_size = int128_make64(TARGET_PAGE_SIZE);
11068d7f2e76SPhilippe Mathieu-Daudé
11078d7f2e76SPhilippe Mathieu-Daudé /* register first subpage */
11088d7f2e76SPhilippe Mathieu-Daudé if (remain.offset_within_address_space & ~TARGET_PAGE_MASK) {
11098d7f2e76SPhilippe Mathieu-Daudé uint64_t left = TARGET_PAGE_ALIGN(remain.offset_within_address_space)
11108d7f2e76SPhilippe Mathieu-Daudé - remain.offset_within_address_space;
11118d7f2e76SPhilippe Mathieu-Daudé
11128d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection now = remain;
11138d7f2e76SPhilippe Mathieu-Daudé now.size = int128_min(int128_make64(left), now.size);
11148d7f2e76SPhilippe Mathieu-Daudé register_subpage(fv, &now);
11158d7f2e76SPhilippe Mathieu-Daudé if (int128_eq(remain.size, now.size)) {
11168d7f2e76SPhilippe Mathieu-Daudé return;
11178d7f2e76SPhilippe Mathieu-Daudé }
11188d7f2e76SPhilippe Mathieu-Daudé remain.size = int128_sub(remain.size, now.size);
11198d7f2e76SPhilippe Mathieu-Daudé remain.offset_within_address_space += int128_get64(now.size);
11208d7f2e76SPhilippe Mathieu-Daudé remain.offset_within_region += int128_get64(now.size);
11218d7f2e76SPhilippe Mathieu-Daudé }
11228d7f2e76SPhilippe Mathieu-Daudé
11238d7f2e76SPhilippe Mathieu-Daudé /* register whole pages */
11248d7f2e76SPhilippe Mathieu-Daudé if (int128_ge(remain.size, page_size)) {
11258d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection now = remain;
11268d7f2e76SPhilippe Mathieu-Daudé now.size = int128_and(now.size, int128_neg(page_size));
11278d7f2e76SPhilippe Mathieu-Daudé register_multipage(fv, &now);
11288d7f2e76SPhilippe Mathieu-Daudé if (int128_eq(remain.size, now.size)) {
11298d7f2e76SPhilippe Mathieu-Daudé return;
11308d7f2e76SPhilippe Mathieu-Daudé }
11318d7f2e76SPhilippe Mathieu-Daudé remain.size = int128_sub(remain.size, now.size);
11328d7f2e76SPhilippe Mathieu-Daudé remain.offset_within_address_space += int128_get64(now.size);
11338d7f2e76SPhilippe Mathieu-Daudé remain.offset_within_region += int128_get64(now.size);
11348d7f2e76SPhilippe Mathieu-Daudé }
11358d7f2e76SPhilippe Mathieu-Daudé
11368d7f2e76SPhilippe Mathieu-Daudé /* register last subpage */
11378d7f2e76SPhilippe Mathieu-Daudé register_subpage(fv, &remain);
11388d7f2e76SPhilippe Mathieu-Daudé }
11398d7f2e76SPhilippe Mathieu-Daudé
qemu_flush_coalesced_mmio_buffer(void)11408d7f2e76SPhilippe Mathieu-Daudé void qemu_flush_coalesced_mmio_buffer(void)
11418d7f2e76SPhilippe Mathieu-Daudé {
11428d7f2e76SPhilippe Mathieu-Daudé if (kvm_enabled())
11438d7f2e76SPhilippe Mathieu-Daudé kvm_flush_coalesced_mmio_buffer();
11448d7f2e76SPhilippe Mathieu-Daudé }
11458d7f2e76SPhilippe Mathieu-Daudé
qemu_mutex_lock_ramlist(void)11468d7f2e76SPhilippe Mathieu-Daudé void qemu_mutex_lock_ramlist(void)
11478d7f2e76SPhilippe Mathieu-Daudé {
11488d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_lock(&ram_list.mutex);
11498d7f2e76SPhilippe Mathieu-Daudé }
11508d7f2e76SPhilippe Mathieu-Daudé
qemu_mutex_unlock_ramlist(void)11518d7f2e76SPhilippe Mathieu-Daudé void qemu_mutex_unlock_ramlist(void)
11528d7f2e76SPhilippe Mathieu-Daudé {
11538d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_unlock(&ram_list.mutex);
11548d7f2e76SPhilippe Mathieu-Daudé }
11558d7f2e76SPhilippe Mathieu-Daudé
ram_block_format(void)11568d7f2e76SPhilippe Mathieu-Daudé GString *ram_block_format(void)
11578d7f2e76SPhilippe Mathieu-Daudé {
11588d7f2e76SPhilippe Mathieu-Daudé RAMBlock *block;
11598d7f2e76SPhilippe Mathieu-Daudé char *psize;
11608d7f2e76SPhilippe Mathieu-Daudé GString *buf = g_string_new("");
11618d7f2e76SPhilippe Mathieu-Daudé
11628d7f2e76SPhilippe Mathieu-Daudé RCU_READ_LOCK_GUARD();
11638d7f2e76SPhilippe Mathieu-Daudé g_string_append_printf(buf, "%24s %8s %18s %18s %18s %18s %3s\n",
11648d7f2e76SPhilippe Mathieu-Daudé "Block Name", "PSize", "Offset", "Used", "Total",
11658d7f2e76SPhilippe Mathieu-Daudé "HVA", "RO");
11668d7f2e76SPhilippe Mathieu-Daudé
11678d7f2e76SPhilippe Mathieu-Daudé RAMBLOCK_FOREACH(block) {
11688d7f2e76SPhilippe Mathieu-Daudé psize = size_to_str(block->page_size);
11698d7f2e76SPhilippe Mathieu-Daudé g_string_append_printf(buf, "%24s %8s 0x%016" PRIx64 " 0x%016" PRIx64
11708d7f2e76SPhilippe Mathieu-Daudé " 0x%016" PRIx64 " 0x%016" PRIx64 " %3s\n",
11718d7f2e76SPhilippe Mathieu-Daudé block->idstr, psize,
11728d7f2e76SPhilippe Mathieu-Daudé (uint64_t)block->offset,
11738d7f2e76SPhilippe Mathieu-Daudé (uint64_t)block->used_length,
11748d7f2e76SPhilippe Mathieu-Daudé (uint64_t)block->max_length,
11758d7f2e76SPhilippe Mathieu-Daudé (uint64_t)(uintptr_t)block->host,
11768d7f2e76SPhilippe Mathieu-Daudé block->mr->readonly ? "ro" : "rw");
11778d7f2e76SPhilippe Mathieu-Daudé
11788d7f2e76SPhilippe Mathieu-Daudé g_free(psize);
11798d7f2e76SPhilippe Mathieu-Daudé }
11808d7f2e76SPhilippe Mathieu-Daudé
11818d7f2e76SPhilippe Mathieu-Daudé return buf;
11828d7f2e76SPhilippe Mathieu-Daudé }
11838d7f2e76SPhilippe Mathieu-Daudé
find_min_backend_pagesize(Object * obj,void * opaque)11848d7f2e76SPhilippe Mathieu-Daudé static int find_min_backend_pagesize(Object *obj, void *opaque)
11858d7f2e76SPhilippe Mathieu-Daudé {
11868d7f2e76SPhilippe Mathieu-Daudé long *hpsize_min = opaque;
11878d7f2e76SPhilippe Mathieu-Daudé
11888d7f2e76SPhilippe Mathieu-Daudé if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) {
11898d7f2e76SPhilippe Mathieu-Daudé HostMemoryBackend *backend = MEMORY_BACKEND(obj);
11908d7f2e76SPhilippe Mathieu-Daudé long hpsize = host_memory_backend_pagesize(backend);
11918d7f2e76SPhilippe Mathieu-Daudé
11928d7f2e76SPhilippe Mathieu-Daudé if (host_memory_backend_is_mapped(backend) && (hpsize < *hpsize_min)) {
11938d7f2e76SPhilippe Mathieu-Daudé *hpsize_min = hpsize;
11948d7f2e76SPhilippe Mathieu-Daudé }
11958d7f2e76SPhilippe Mathieu-Daudé }
11968d7f2e76SPhilippe Mathieu-Daudé
11978d7f2e76SPhilippe Mathieu-Daudé return 0;
11988d7f2e76SPhilippe Mathieu-Daudé }
11998d7f2e76SPhilippe Mathieu-Daudé
find_max_backend_pagesize(Object * obj,void * opaque)12008d7f2e76SPhilippe Mathieu-Daudé static int find_max_backend_pagesize(Object *obj, void *opaque)
12018d7f2e76SPhilippe Mathieu-Daudé {
12028d7f2e76SPhilippe Mathieu-Daudé long *hpsize_max = opaque;
12038d7f2e76SPhilippe Mathieu-Daudé
12048d7f2e76SPhilippe Mathieu-Daudé if (object_dynamic_cast(obj, TYPE_MEMORY_BACKEND)) {
12058d7f2e76SPhilippe Mathieu-Daudé HostMemoryBackend *backend = MEMORY_BACKEND(obj);
12068d7f2e76SPhilippe Mathieu-Daudé long hpsize = host_memory_backend_pagesize(backend);
12078d7f2e76SPhilippe Mathieu-Daudé
12088d7f2e76SPhilippe Mathieu-Daudé if (host_memory_backend_is_mapped(backend) && (hpsize > *hpsize_max)) {
12098d7f2e76SPhilippe Mathieu-Daudé *hpsize_max = hpsize;
12108d7f2e76SPhilippe Mathieu-Daudé }
12118d7f2e76SPhilippe Mathieu-Daudé }
12128d7f2e76SPhilippe Mathieu-Daudé
12138d7f2e76SPhilippe Mathieu-Daudé return 0;
12148d7f2e76SPhilippe Mathieu-Daudé }
12158d7f2e76SPhilippe Mathieu-Daudé
12168d7f2e76SPhilippe Mathieu-Daudé /*
12178d7f2e76SPhilippe Mathieu-Daudé * TODO: We assume right now that all mapped host memory backends are
12188d7f2e76SPhilippe Mathieu-Daudé * used as RAM, however some might be used for different purposes.
12198d7f2e76SPhilippe Mathieu-Daudé */
qemu_minrampagesize(void)12208d7f2e76SPhilippe Mathieu-Daudé long qemu_minrampagesize(void)
12218d7f2e76SPhilippe Mathieu-Daudé {
12228d7f2e76SPhilippe Mathieu-Daudé long hpsize = LONG_MAX;
12238d7f2e76SPhilippe Mathieu-Daudé Object *memdev_root = object_resolve_path("/objects", NULL);
12248d7f2e76SPhilippe Mathieu-Daudé
12258d7f2e76SPhilippe Mathieu-Daudé object_child_foreach(memdev_root, find_min_backend_pagesize, &hpsize);
12268d7f2e76SPhilippe Mathieu-Daudé return hpsize;
12278d7f2e76SPhilippe Mathieu-Daudé }
12288d7f2e76SPhilippe Mathieu-Daudé
qemu_maxrampagesize(void)12298d7f2e76SPhilippe Mathieu-Daudé long qemu_maxrampagesize(void)
12308d7f2e76SPhilippe Mathieu-Daudé {
12318d7f2e76SPhilippe Mathieu-Daudé long pagesize = 0;
12328d7f2e76SPhilippe Mathieu-Daudé Object *memdev_root = object_resolve_path("/objects", NULL);
12338d7f2e76SPhilippe Mathieu-Daudé
12348d7f2e76SPhilippe Mathieu-Daudé object_child_foreach(memdev_root, find_max_backend_pagesize, &pagesize);
12358d7f2e76SPhilippe Mathieu-Daudé return pagesize;
12368d7f2e76SPhilippe Mathieu-Daudé }
12378d7f2e76SPhilippe Mathieu-Daudé
12388d7f2e76SPhilippe Mathieu-Daudé #ifdef CONFIG_POSIX
get_file_size(int fd)12398d7f2e76SPhilippe Mathieu-Daudé static int64_t get_file_size(int fd)
12408d7f2e76SPhilippe Mathieu-Daudé {
12418d7f2e76SPhilippe Mathieu-Daudé int64_t size;
12428d7f2e76SPhilippe Mathieu-Daudé #if defined(__linux__)
12438d7f2e76SPhilippe Mathieu-Daudé struct stat st;
12448d7f2e76SPhilippe Mathieu-Daudé
12458d7f2e76SPhilippe Mathieu-Daudé if (fstat(fd, &st) < 0) {
12468d7f2e76SPhilippe Mathieu-Daudé return -errno;
12478d7f2e76SPhilippe Mathieu-Daudé }
12488d7f2e76SPhilippe Mathieu-Daudé
12498d7f2e76SPhilippe Mathieu-Daudé /* Special handling for devdax character devices */
12508d7f2e76SPhilippe Mathieu-Daudé if (S_ISCHR(st.st_mode)) {
12518d7f2e76SPhilippe Mathieu-Daudé g_autofree char *subsystem_path = NULL;
12528d7f2e76SPhilippe Mathieu-Daudé g_autofree char *subsystem = NULL;
12538d7f2e76SPhilippe Mathieu-Daudé
12548d7f2e76SPhilippe Mathieu-Daudé subsystem_path = g_strdup_printf("/sys/dev/char/%d:%d/subsystem",
12558d7f2e76SPhilippe Mathieu-Daudé major(st.st_rdev), minor(st.st_rdev));
12568d7f2e76SPhilippe Mathieu-Daudé subsystem = g_file_read_link(subsystem_path, NULL);
12578d7f2e76SPhilippe Mathieu-Daudé
12588d7f2e76SPhilippe Mathieu-Daudé if (subsystem && g_str_has_suffix(subsystem, "/dax")) {
12598d7f2e76SPhilippe Mathieu-Daudé g_autofree char *size_path = NULL;
12608d7f2e76SPhilippe Mathieu-Daudé g_autofree char *size_str = NULL;
12618d7f2e76SPhilippe Mathieu-Daudé
12628d7f2e76SPhilippe Mathieu-Daudé size_path = g_strdup_printf("/sys/dev/char/%d:%d/size",
12638d7f2e76SPhilippe Mathieu-Daudé major(st.st_rdev), minor(st.st_rdev));
12648d7f2e76SPhilippe Mathieu-Daudé
12658d7f2e76SPhilippe Mathieu-Daudé if (g_file_get_contents(size_path, &size_str, NULL, NULL)) {
12668d7f2e76SPhilippe Mathieu-Daudé return g_ascii_strtoll(size_str, NULL, 0);
12678d7f2e76SPhilippe Mathieu-Daudé }
12688d7f2e76SPhilippe Mathieu-Daudé }
12698d7f2e76SPhilippe Mathieu-Daudé }
12708d7f2e76SPhilippe Mathieu-Daudé #endif /* defined(__linux__) */
12718d7f2e76SPhilippe Mathieu-Daudé
12728d7f2e76SPhilippe Mathieu-Daudé /* st.st_size may be zero for special files yet lseek(2) works */
12738d7f2e76SPhilippe Mathieu-Daudé size = lseek(fd, 0, SEEK_END);
12748d7f2e76SPhilippe Mathieu-Daudé if (size < 0) {
12758d7f2e76SPhilippe Mathieu-Daudé return -errno;
12768d7f2e76SPhilippe Mathieu-Daudé }
12778d7f2e76SPhilippe Mathieu-Daudé return size;
12788d7f2e76SPhilippe Mathieu-Daudé }
12798d7f2e76SPhilippe Mathieu-Daudé
get_file_align(int fd)12808d7f2e76SPhilippe Mathieu-Daudé static int64_t get_file_align(int fd)
12818d7f2e76SPhilippe Mathieu-Daudé {
12828d7f2e76SPhilippe Mathieu-Daudé int64_t align = -1;
12838d7f2e76SPhilippe Mathieu-Daudé #if defined(__linux__) && defined(CONFIG_LIBDAXCTL)
12848d7f2e76SPhilippe Mathieu-Daudé struct stat st;
12858d7f2e76SPhilippe Mathieu-Daudé
12868d7f2e76SPhilippe Mathieu-Daudé if (fstat(fd, &st) < 0) {
12878d7f2e76SPhilippe Mathieu-Daudé return -errno;
12888d7f2e76SPhilippe Mathieu-Daudé }
12898d7f2e76SPhilippe Mathieu-Daudé
12908d7f2e76SPhilippe Mathieu-Daudé /* Special handling for devdax character devices */
12918d7f2e76SPhilippe Mathieu-Daudé if (S_ISCHR(st.st_mode)) {
12928d7f2e76SPhilippe Mathieu-Daudé g_autofree char *path = NULL;
12938d7f2e76SPhilippe Mathieu-Daudé g_autofree char *rpath = NULL;
12948d7f2e76SPhilippe Mathieu-Daudé struct daxctl_ctx *ctx;
12958d7f2e76SPhilippe Mathieu-Daudé struct daxctl_region *region;
12968d7f2e76SPhilippe Mathieu-Daudé int rc = 0;
12978d7f2e76SPhilippe Mathieu-Daudé
12988d7f2e76SPhilippe Mathieu-Daudé path = g_strdup_printf("/sys/dev/char/%d:%d",
12998d7f2e76SPhilippe Mathieu-Daudé major(st.st_rdev), minor(st.st_rdev));
13008d7f2e76SPhilippe Mathieu-Daudé rpath = realpath(path, NULL);
13018d7f2e76SPhilippe Mathieu-Daudé if (!rpath) {
13028d7f2e76SPhilippe Mathieu-Daudé return -errno;
13038d7f2e76SPhilippe Mathieu-Daudé }
13048d7f2e76SPhilippe Mathieu-Daudé
13058d7f2e76SPhilippe Mathieu-Daudé rc = daxctl_new(&ctx);
13068d7f2e76SPhilippe Mathieu-Daudé if (rc) {
13078d7f2e76SPhilippe Mathieu-Daudé return -1;
13088d7f2e76SPhilippe Mathieu-Daudé }
13098d7f2e76SPhilippe Mathieu-Daudé
13108d7f2e76SPhilippe Mathieu-Daudé daxctl_region_foreach(ctx, region) {
13118d7f2e76SPhilippe Mathieu-Daudé if (strstr(rpath, daxctl_region_get_path(region))) {
13128d7f2e76SPhilippe Mathieu-Daudé align = daxctl_region_get_align(region);
13138d7f2e76SPhilippe Mathieu-Daudé break;
13148d7f2e76SPhilippe Mathieu-Daudé }
13158d7f2e76SPhilippe Mathieu-Daudé }
13168d7f2e76SPhilippe Mathieu-Daudé daxctl_unref(ctx);
13178d7f2e76SPhilippe Mathieu-Daudé }
13188d7f2e76SPhilippe Mathieu-Daudé #endif /* defined(__linux__) && defined(CONFIG_LIBDAXCTL) */
13198d7f2e76SPhilippe Mathieu-Daudé
13208d7f2e76SPhilippe Mathieu-Daudé return align;
13218d7f2e76SPhilippe Mathieu-Daudé }
13228d7f2e76SPhilippe Mathieu-Daudé
file_ram_open(const char * path,const char * region_name,bool readonly,bool * created)13238d7f2e76SPhilippe Mathieu-Daudé static int file_ram_open(const char *path,
13248d7f2e76SPhilippe Mathieu-Daudé const char *region_name,
13258d7f2e76SPhilippe Mathieu-Daudé bool readonly,
13268d7f2e76SPhilippe Mathieu-Daudé bool *created)
13278d7f2e76SPhilippe Mathieu-Daudé {
13288d7f2e76SPhilippe Mathieu-Daudé char *filename;
13298d7f2e76SPhilippe Mathieu-Daudé char *sanitized_name;
13308d7f2e76SPhilippe Mathieu-Daudé char *c;
13318d7f2e76SPhilippe Mathieu-Daudé int fd = -1;
13328d7f2e76SPhilippe Mathieu-Daudé
13338d7f2e76SPhilippe Mathieu-Daudé *created = false;
13348d7f2e76SPhilippe Mathieu-Daudé for (;;) {
13358d7f2e76SPhilippe Mathieu-Daudé fd = open(path, readonly ? O_RDONLY : O_RDWR);
13368d7f2e76SPhilippe Mathieu-Daudé if (fd >= 0) {
13378d7f2e76SPhilippe Mathieu-Daudé /*
13388d7f2e76SPhilippe Mathieu-Daudé * open(O_RDONLY) won't fail with EISDIR. Check manually if we
13398d7f2e76SPhilippe Mathieu-Daudé * opened a directory and fail similarly to how we fail ENOENT
13408d7f2e76SPhilippe Mathieu-Daudé * in readonly mode. Note that mkstemp() would imply O_RDWR.
13418d7f2e76SPhilippe Mathieu-Daudé */
13428d7f2e76SPhilippe Mathieu-Daudé if (readonly) {
13438d7f2e76SPhilippe Mathieu-Daudé struct stat file_stat;
13448d7f2e76SPhilippe Mathieu-Daudé
13458d7f2e76SPhilippe Mathieu-Daudé if (fstat(fd, &file_stat)) {
13468d7f2e76SPhilippe Mathieu-Daudé close(fd);
13478d7f2e76SPhilippe Mathieu-Daudé if (errno == EINTR) {
13488d7f2e76SPhilippe Mathieu-Daudé continue;
13498d7f2e76SPhilippe Mathieu-Daudé }
13508d7f2e76SPhilippe Mathieu-Daudé return -errno;
13518d7f2e76SPhilippe Mathieu-Daudé } else if (S_ISDIR(file_stat.st_mode)) {
13528d7f2e76SPhilippe Mathieu-Daudé close(fd);
13538d7f2e76SPhilippe Mathieu-Daudé return -EISDIR;
13548d7f2e76SPhilippe Mathieu-Daudé }
13558d7f2e76SPhilippe Mathieu-Daudé }
13568d7f2e76SPhilippe Mathieu-Daudé /* @path names an existing file, use it */
13578d7f2e76SPhilippe Mathieu-Daudé break;
13588d7f2e76SPhilippe Mathieu-Daudé }
13598d7f2e76SPhilippe Mathieu-Daudé if (errno == ENOENT) {
13608d7f2e76SPhilippe Mathieu-Daudé if (readonly) {
13618d7f2e76SPhilippe Mathieu-Daudé /* Refuse to create new, readonly files. */
13628d7f2e76SPhilippe Mathieu-Daudé return -ENOENT;
13638d7f2e76SPhilippe Mathieu-Daudé }
13648d7f2e76SPhilippe Mathieu-Daudé /* @path names a file that doesn't exist, create it */
13658d7f2e76SPhilippe Mathieu-Daudé fd = open(path, O_RDWR | O_CREAT | O_EXCL, 0644);
13668d7f2e76SPhilippe Mathieu-Daudé if (fd >= 0) {
13678d7f2e76SPhilippe Mathieu-Daudé *created = true;
13688d7f2e76SPhilippe Mathieu-Daudé break;
13698d7f2e76SPhilippe Mathieu-Daudé }
13708d7f2e76SPhilippe Mathieu-Daudé } else if (errno == EISDIR) {
13718d7f2e76SPhilippe Mathieu-Daudé /* @path names a directory, create a file there */
13728d7f2e76SPhilippe Mathieu-Daudé /* Make name safe to use with mkstemp by replacing '/' with '_'. */
13738d7f2e76SPhilippe Mathieu-Daudé sanitized_name = g_strdup(region_name);
13748d7f2e76SPhilippe Mathieu-Daudé for (c = sanitized_name; *c != '\0'; c++) {
13758d7f2e76SPhilippe Mathieu-Daudé if (*c == '/') {
13768d7f2e76SPhilippe Mathieu-Daudé *c = '_';
13778d7f2e76SPhilippe Mathieu-Daudé }
13788d7f2e76SPhilippe Mathieu-Daudé }
13798d7f2e76SPhilippe Mathieu-Daudé
13808d7f2e76SPhilippe Mathieu-Daudé filename = g_strdup_printf("%s/qemu_back_mem.%s.XXXXXX", path,
13818d7f2e76SPhilippe Mathieu-Daudé sanitized_name);
13828d7f2e76SPhilippe Mathieu-Daudé g_free(sanitized_name);
13838d7f2e76SPhilippe Mathieu-Daudé
13848d7f2e76SPhilippe Mathieu-Daudé fd = mkstemp(filename);
13858d7f2e76SPhilippe Mathieu-Daudé if (fd >= 0) {
13868d7f2e76SPhilippe Mathieu-Daudé unlink(filename);
13878d7f2e76SPhilippe Mathieu-Daudé g_free(filename);
13888d7f2e76SPhilippe Mathieu-Daudé break;
13898d7f2e76SPhilippe Mathieu-Daudé }
13908d7f2e76SPhilippe Mathieu-Daudé g_free(filename);
13918d7f2e76SPhilippe Mathieu-Daudé }
13928d7f2e76SPhilippe Mathieu-Daudé if (errno != EEXIST && errno != EINTR) {
13938d7f2e76SPhilippe Mathieu-Daudé return -errno;
13948d7f2e76SPhilippe Mathieu-Daudé }
13958d7f2e76SPhilippe Mathieu-Daudé /*
13968d7f2e76SPhilippe Mathieu-Daudé * Try again on EINTR and EEXIST. The latter happens when
13978d7f2e76SPhilippe Mathieu-Daudé * something else creates the file between our two open().
13988d7f2e76SPhilippe Mathieu-Daudé */
13998d7f2e76SPhilippe Mathieu-Daudé }
14008d7f2e76SPhilippe Mathieu-Daudé
14018d7f2e76SPhilippe Mathieu-Daudé return fd;
14028d7f2e76SPhilippe Mathieu-Daudé }
14038d7f2e76SPhilippe Mathieu-Daudé
file_ram_alloc(RAMBlock * block,ram_addr_t memory,int fd,bool truncate,off_t offset,Error ** errp)14048d7f2e76SPhilippe Mathieu-Daudé static void *file_ram_alloc(RAMBlock *block,
14058d7f2e76SPhilippe Mathieu-Daudé ram_addr_t memory,
14068d7f2e76SPhilippe Mathieu-Daudé int fd,
14078d7f2e76SPhilippe Mathieu-Daudé bool truncate,
14088d7f2e76SPhilippe Mathieu-Daudé off_t offset,
14098d7f2e76SPhilippe Mathieu-Daudé Error **errp)
14108d7f2e76SPhilippe Mathieu-Daudé {
14118d7f2e76SPhilippe Mathieu-Daudé uint32_t qemu_map_flags;
14128d7f2e76SPhilippe Mathieu-Daudé void *area;
14138d7f2e76SPhilippe Mathieu-Daudé
14148d7f2e76SPhilippe Mathieu-Daudé block->page_size = qemu_fd_getpagesize(fd);
14158d7f2e76SPhilippe Mathieu-Daudé if (block->mr->align % block->page_size) {
14168d7f2e76SPhilippe Mathieu-Daudé error_setg(errp, "alignment 0x%" PRIx64
14178d7f2e76SPhilippe Mathieu-Daudé " must be multiples of page size 0x%zx",
14188d7f2e76SPhilippe Mathieu-Daudé block->mr->align, block->page_size);
14198d7f2e76SPhilippe Mathieu-Daudé return NULL;
14208d7f2e76SPhilippe Mathieu-Daudé } else if (block->mr->align && !is_power_of_2(block->mr->align)) {
14218d7f2e76SPhilippe Mathieu-Daudé error_setg(errp, "alignment 0x%" PRIx64
14228d7f2e76SPhilippe Mathieu-Daudé " must be a power of two", block->mr->align);
14238d7f2e76SPhilippe Mathieu-Daudé return NULL;
14248d7f2e76SPhilippe Mathieu-Daudé } else if (offset % block->page_size) {
14258d7f2e76SPhilippe Mathieu-Daudé error_setg(errp, "offset 0x%" PRIx64
14268d7f2e76SPhilippe Mathieu-Daudé " must be multiples of page size 0x%zx",
14278d7f2e76SPhilippe Mathieu-Daudé offset, block->page_size);
14288d7f2e76SPhilippe Mathieu-Daudé return NULL;
14298d7f2e76SPhilippe Mathieu-Daudé }
14308d7f2e76SPhilippe Mathieu-Daudé block->mr->align = MAX(block->page_size, block->mr->align);
14318d7f2e76SPhilippe Mathieu-Daudé #if defined(__s390x__)
14328d7f2e76SPhilippe Mathieu-Daudé if (kvm_enabled()) {
14338d7f2e76SPhilippe Mathieu-Daudé block->mr->align = MAX(block->mr->align, QEMU_VMALLOC_ALIGN);
14348d7f2e76SPhilippe Mathieu-Daudé }
14358d7f2e76SPhilippe Mathieu-Daudé #endif
14368d7f2e76SPhilippe Mathieu-Daudé
14378d7f2e76SPhilippe Mathieu-Daudé if (memory < block->page_size) {
14388d7f2e76SPhilippe Mathieu-Daudé error_setg(errp, "memory size 0x" RAM_ADDR_FMT " must be equal to "
14398d7f2e76SPhilippe Mathieu-Daudé "or larger than page size 0x%zx",
14408d7f2e76SPhilippe Mathieu-Daudé memory, block->page_size);
14418d7f2e76SPhilippe Mathieu-Daudé return NULL;
14428d7f2e76SPhilippe Mathieu-Daudé }
14438d7f2e76SPhilippe Mathieu-Daudé
14448d7f2e76SPhilippe Mathieu-Daudé memory = ROUND_UP(memory, block->page_size);
14458d7f2e76SPhilippe Mathieu-Daudé
14468d7f2e76SPhilippe Mathieu-Daudé /*
14478d7f2e76SPhilippe Mathieu-Daudé * ftruncate is not supported by hugetlbfs in older
14488d7f2e76SPhilippe Mathieu-Daudé * hosts, so don't bother bailing out on errors.
14498d7f2e76SPhilippe Mathieu-Daudé * If anything goes wrong with it under other filesystems,
14508d7f2e76SPhilippe Mathieu-Daudé * mmap will fail.
14518d7f2e76SPhilippe Mathieu-Daudé *
14528d7f2e76SPhilippe Mathieu-Daudé * Do not truncate the non-empty backend file to avoid corrupting
14538d7f2e76SPhilippe Mathieu-Daudé * the existing data in the file. Disabling shrinking is not
14548d7f2e76SPhilippe Mathieu-Daudé * enough. For example, the current vNVDIMM implementation stores
14558d7f2e76SPhilippe Mathieu-Daudé * the guest NVDIMM labels at the end of the backend file. If the
14568d7f2e76SPhilippe Mathieu-Daudé * backend file is later extended, QEMU will not be able to find
14578d7f2e76SPhilippe Mathieu-Daudé * those labels. Therefore, extending the non-empty backend file
14588d7f2e76SPhilippe Mathieu-Daudé * is disabled as well.
14598d7f2e76SPhilippe Mathieu-Daudé */
14608d7f2e76SPhilippe Mathieu-Daudé if (truncate && ftruncate(fd, offset + memory)) {
14618d7f2e76SPhilippe Mathieu-Daudé perror("ftruncate");
14628d7f2e76SPhilippe Mathieu-Daudé }
14638d7f2e76SPhilippe Mathieu-Daudé
14648d7f2e76SPhilippe Mathieu-Daudé qemu_map_flags = (block->flags & RAM_READONLY) ? QEMU_MAP_READONLY : 0;
14658d7f2e76SPhilippe Mathieu-Daudé qemu_map_flags |= (block->flags & RAM_SHARED) ? QEMU_MAP_SHARED : 0;
14668d7f2e76SPhilippe Mathieu-Daudé qemu_map_flags |= (block->flags & RAM_PMEM) ? QEMU_MAP_SYNC : 0;
14678d7f2e76SPhilippe Mathieu-Daudé qemu_map_flags |= (block->flags & RAM_NORESERVE) ? QEMU_MAP_NORESERVE : 0;
14688d7f2e76SPhilippe Mathieu-Daudé area = qemu_ram_mmap(fd, memory, block->mr->align, qemu_map_flags, offset);
14698d7f2e76SPhilippe Mathieu-Daudé if (area == MAP_FAILED) {
14708d7f2e76SPhilippe Mathieu-Daudé error_setg_errno(errp, errno,
14718d7f2e76SPhilippe Mathieu-Daudé "unable to map backing store for guest RAM");
14728d7f2e76SPhilippe Mathieu-Daudé return NULL;
14738d7f2e76SPhilippe Mathieu-Daudé }
14748d7f2e76SPhilippe Mathieu-Daudé
14758d7f2e76SPhilippe Mathieu-Daudé block->fd = fd;
14768d7f2e76SPhilippe Mathieu-Daudé block->fd_offset = offset;
14778d7f2e76SPhilippe Mathieu-Daudé return area;
14788d7f2e76SPhilippe Mathieu-Daudé }
14798d7f2e76SPhilippe Mathieu-Daudé #endif
14808d7f2e76SPhilippe Mathieu-Daudé
14818d7f2e76SPhilippe Mathieu-Daudé /* Allocate space within the ram_addr_t space that governs the
14828d7f2e76SPhilippe Mathieu-Daudé * dirty bitmaps.
14838d7f2e76SPhilippe Mathieu-Daudé * Called with the ramlist lock held.
14848d7f2e76SPhilippe Mathieu-Daudé */
find_ram_offset(ram_addr_t size)14858d7f2e76SPhilippe Mathieu-Daudé static ram_addr_t find_ram_offset(ram_addr_t size)
14868d7f2e76SPhilippe Mathieu-Daudé {
14878d7f2e76SPhilippe Mathieu-Daudé RAMBlock *block, *next_block;
14888d7f2e76SPhilippe Mathieu-Daudé ram_addr_t offset = RAM_ADDR_MAX, mingap = RAM_ADDR_MAX;
14898d7f2e76SPhilippe Mathieu-Daudé
14908d7f2e76SPhilippe Mathieu-Daudé assert(size != 0); /* it would hand out same offset multiple times */
14918d7f2e76SPhilippe Mathieu-Daudé
14928d7f2e76SPhilippe Mathieu-Daudé if (QLIST_EMPTY_RCU(&ram_list.blocks)) {
14938d7f2e76SPhilippe Mathieu-Daudé return 0;
14948d7f2e76SPhilippe Mathieu-Daudé }
14958d7f2e76SPhilippe Mathieu-Daudé
14968d7f2e76SPhilippe Mathieu-Daudé RAMBLOCK_FOREACH(block) {
14978d7f2e76SPhilippe Mathieu-Daudé ram_addr_t candidate, next = RAM_ADDR_MAX;
14988d7f2e76SPhilippe Mathieu-Daudé
14998d7f2e76SPhilippe Mathieu-Daudé /* Align blocks to start on a 'long' in the bitmap
15008d7f2e76SPhilippe Mathieu-Daudé * which makes the bitmap sync'ing take the fast path.
15018d7f2e76SPhilippe Mathieu-Daudé */
15028d7f2e76SPhilippe Mathieu-Daudé candidate = block->offset + block->max_length;
15038d7f2e76SPhilippe Mathieu-Daudé candidate = ROUND_UP(candidate, BITS_PER_LONG << TARGET_PAGE_BITS);
15048d7f2e76SPhilippe Mathieu-Daudé
15058d7f2e76SPhilippe Mathieu-Daudé /* Search for the closest following block
15068d7f2e76SPhilippe Mathieu-Daudé * and find the gap.
15078d7f2e76SPhilippe Mathieu-Daudé */
15088d7f2e76SPhilippe Mathieu-Daudé RAMBLOCK_FOREACH(next_block) {
15098d7f2e76SPhilippe Mathieu-Daudé if (next_block->offset >= candidate) {
15108d7f2e76SPhilippe Mathieu-Daudé next = MIN(next, next_block->offset);
15118d7f2e76SPhilippe Mathieu-Daudé }
15128d7f2e76SPhilippe Mathieu-Daudé }
15138d7f2e76SPhilippe Mathieu-Daudé
15148d7f2e76SPhilippe Mathieu-Daudé /* If it fits remember our place and remember the size
15158d7f2e76SPhilippe Mathieu-Daudé * of gap, but keep going so that we might find a smaller
15168d7f2e76SPhilippe Mathieu-Daudé * gap to fill so avoiding fragmentation.
15178d7f2e76SPhilippe Mathieu-Daudé */
15188d7f2e76SPhilippe Mathieu-Daudé if (next - candidate >= size && next - candidate < mingap) {
15198d7f2e76SPhilippe Mathieu-Daudé offset = candidate;
15208d7f2e76SPhilippe Mathieu-Daudé mingap = next - candidate;
15218d7f2e76SPhilippe Mathieu-Daudé }
15228d7f2e76SPhilippe Mathieu-Daudé
15238d7f2e76SPhilippe Mathieu-Daudé trace_find_ram_offset_loop(size, candidate, offset, next, mingap);
15248d7f2e76SPhilippe Mathieu-Daudé }
15258d7f2e76SPhilippe Mathieu-Daudé
15268d7f2e76SPhilippe Mathieu-Daudé if (offset == RAM_ADDR_MAX) {
15278d7f2e76SPhilippe Mathieu-Daudé fprintf(stderr, "Failed to find gap of requested size: %" PRIu64 "\n",
15288d7f2e76SPhilippe Mathieu-Daudé (uint64_t)size);
15298d7f2e76SPhilippe Mathieu-Daudé abort();
15308d7f2e76SPhilippe Mathieu-Daudé }
15318d7f2e76SPhilippe Mathieu-Daudé
15328d7f2e76SPhilippe Mathieu-Daudé trace_find_ram_offset(size, offset);
15338d7f2e76SPhilippe Mathieu-Daudé
15348d7f2e76SPhilippe Mathieu-Daudé return offset;
15358d7f2e76SPhilippe Mathieu-Daudé }
15368d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_setup_dump(void * addr,ram_addr_t size)15378d7f2e76SPhilippe Mathieu-Daudé static void qemu_ram_setup_dump(void *addr, ram_addr_t size)
15388d7f2e76SPhilippe Mathieu-Daudé {
15398d7f2e76SPhilippe Mathieu-Daudé int ret;
15408d7f2e76SPhilippe Mathieu-Daudé
15418d7f2e76SPhilippe Mathieu-Daudé /* Use MADV_DONTDUMP, if user doesn't want the guest memory in the core */
15428d7f2e76SPhilippe Mathieu-Daudé if (!machine_dump_guest_core(current_machine)) {
15438d7f2e76SPhilippe Mathieu-Daudé ret = qemu_madvise(addr, size, QEMU_MADV_DONTDUMP);
15448d7f2e76SPhilippe Mathieu-Daudé if (ret) {
15458d7f2e76SPhilippe Mathieu-Daudé perror("qemu_madvise");
15468d7f2e76SPhilippe Mathieu-Daudé fprintf(stderr, "madvise doesn't support MADV_DONTDUMP, "
15470ff3243aSAkihiko Odaki "but dump-guest-core=off specified\n");
15488d7f2e76SPhilippe Mathieu-Daudé }
15498d7f2e76SPhilippe Mathieu-Daudé }
15508d7f2e76SPhilippe Mathieu-Daudé }
15518d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_get_idstr(RAMBlock * rb)15528d7f2e76SPhilippe Mathieu-Daudé const char *qemu_ram_get_idstr(RAMBlock *rb)
15538d7f2e76SPhilippe Mathieu-Daudé {
15548d7f2e76SPhilippe Mathieu-Daudé return rb->idstr;
15558d7f2e76SPhilippe Mathieu-Daudé }
15568d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_get_host_addr(RAMBlock * rb)15578d7f2e76SPhilippe Mathieu-Daudé void *qemu_ram_get_host_addr(RAMBlock *rb)
15588d7f2e76SPhilippe Mathieu-Daudé {
15598d7f2e76SPhilippe Mathieu-Daudé return rb->host;
15608d7f2e76SPhilippe Mathieu-Daudé }
15618d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_get_offset(RAMBlock * rb)15628d7f2e76SPhilippe Mathieu-Daudé ram_addr_t qemu_ram_get_offset(RAMBlock *rb)
15638d7f2e76SPhilippe Mathieu-Daudé {
15648d7f2e76SPhilippe Mathieu-Daudé return rb->offset;
15658d7f2e76SPhilippe Mathieu-Daudé }
15668d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_get_used_length(RAMBlock * rb)15678d7f2e76SPhilippe Mathieu-Daudé ram_addr_t qemu_ram_get_used_length(RAMBlock *rb)
15688d7f2e76SPhilippe Mathieu-Daudé {
15698d7f2e76SPhilippe Mathieu-Daudé return rb->used_length;
15708d7f2e76SPhilippe Mathieu-Daudé }
15718d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_get_max_length(RAMBlock * rb)15728d7f2e76SPhilippe Mathieu-Daudé ram_addr_t qemu_ram_get_max_length(RAMBlock *rb)
15738d7f2e76SPhilippe Mathieu-Daudé {
15748d7f2e76SPhilippe Mathieu-Daudé return rb->max_length;
15758d7f2e76SPhilippe Mathieu-Daudé }
15768d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_is_shared(RAMBlock * rb)15778d7f2e76SPhilippe Mathieu-Daudé bool qemu_ram_is_shared(RAMBlock *rb)
15788d7f2e76SPhilippe Mathieu-Daudé {
15798d7f2e76SPhilippe Mathieu-Daudé return rb->flags & RAM_SHARED;
15808d7f2e76SPhilippe Mathieu-Daudé }
15818d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_is_noreserve(RAMBlock * rb)15828d7f2e76SPhilippe Mathieu-Daudé bool qemu_ram_is_noreserve(RAMBlock *rb)
15838d7f2e76SPhilippe Mathieu-Daudé {
15848d7f2e76SPhilippe Mathieu-Daudé return rb->flags & RAM_NORESERVE;
15858d7f2e76SPhilippe Mathieu-Daudé }
15868d7f2e76SPhilippe Mathieu-Daudé
15878d7f2e76SPhilippe Mathieu-Daudé /* Note: Only set at the start of postcopy */
qemu_ram_is_uf_zeroable(RAMBlock * rb)15888d7f2e76SPhilippe Mathieu-Daudé bool qemu_ram_is_uf_zeroable(RAMBlock *rb)
15898d7f2e76SPhilippe Mathieu-Daudé {
15908d7f2e76SPhilippe Mathieu-Daudé return rb->flags & RAM_UF_ZEROPAGE;
15918d7f2e76SPhilippe Mathieu-Daudé }
15928d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_set_uf_zeroable(RAMBlock * rb)15938d7f2e76SPhilippe Mathieu-Daudé void qemu_ram_set_uf_zeroable(RAMBlock *rb)
15948d7f2e76SPhilippe Mathieu-Daudé {
15958d7f2e76SPhilippe Mathieu-Daudé rb->flags |= RAM_UF_ZEROPAGE;
15968d7f2e76SPhilippe Mathieu-Daudé }
15978d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_is_migratable(RAMBlock * rb)15988d7f2e76SPhilippe Mathieu-Daudé bool qemu_ram_is_migratable(RAMBlock *rb)
15998d7f2e76SPhilippe Mathieu-Daudé {
16008d7f2e76SPhilippe Mathieu-Daudé return rb->flags & RAM_MIGRATABLE;
16018d7f2e76SPhilippe Mathieu-Daudé }
16028d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_set_migratable(RAMBlock * rb)16038d7f2e76SPhilippe Mathieu-Daudé void qemu_ram_set_migratable(RAMBlock *rb)
16048d7f2e76SPhilippe Mathieu-Daudé {
16058d7f2e76SPhilippe Mathieu-Daudé rb->flags |= RAM_MIGRATABLE;
16068d7f2e76SPhilippe Mathieu-Daudé }
16078d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_unset_migratable(RAMBlock * rb)16088d7f2e76SPhilippe Mathieu-Daudé void qemu_ram_unset_migratable(RAMBlock *rb)
16098d7f2e76SPhilippe Mathieu-Daudé {
16108d7f2e76SPhilippe Mathieu-Daudé rb->flags &= ~RAM_MIGRATABLE;
16118d7f2e76SPhilippe Mathieu-Daudé }
16128d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_is_named_file(RAMBlock * rb)16138d7f2e76SPhilippe Mathieu-Daudé bool qemu_ram_is_named_file(RAMBlock *rb)
16148d7f2e76SPhilippe Mathieu-Daudé {
16158d7f2e76SPhilippe Mathieu-Daudé return rb->flags & RAM_NAMED_FILE;
16168d7f2e76SPhilippe Mathieu-Daudé }
16178d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_get_fd(RAMBlock * rb)16188d7f2e76SPhilippe Mathieu-Daudé int qemu_ram_get_fd(RAMBlock *rb)
16198d7f2e76SPhilippe Mathieu-Daudé {
16208d7f2e76SPhilippe Mathieu-Daudé return rb->fd;
16218d7f2e76SPhilippe Mathieu-Daudé }
16228d7f2e76SPhilippe Mathieu-Daudé
1623a4a411fbSStefan Hajnoczi /* Called with the BQL held. */
qemu_ram_set_idstr(RAMBlock * new_block,const char * name,DeviceState * dev)16248d7f2e76SPhilippe Mathieu-Daudé void qemu_ram_set_idstr(RAMBlock *new_block, const char *name, DeviceState *dev)
16258d7f2e76SPhilippe Mathieu-Daudé {
16268d7f2e76SPhilippe Mathieu-Daudé RAMBlock *block;
16278d7f2e76SPhilippe Mathieu-Daudé
16288d7f2e76SPhilippe Mathieu-Daudé assert(new_block);
16298d7f2e76SPhilippe Mathieu-Daudé assert(!new_block->idstr[0]);
16308d7f2e76SPhilippe Mathieu-Daudé
16318d7f2e76SPhilippe Mathieu-Daudé if (dev) {
16328d7f2e76SPhilippe Mathieu-Daudé char *id = qdev_get_dev_path(dev);
16338d7f2e76SPhilippe Mathieu-Daudé if (id) {
16348d7f2e76SPhilippe Mathieu-Daudé snprintf(new_block->idstr, sizeof(new_block->idstr), "%s/", id);
16358d7f2e76SPhilippe Mathieu-Daudé g_free(id);
16368d7f2e76SPhilippe Mathieu-Daudé }
16378d7f2e76SPhilippe Mathieu-Daudé }
16388d7f2e76SPhilippe Mathieu-Daudé pstrcat(new_block->idstr, sizeof(new_block->idstr), name);
16398d7f2e76SPhilippe Mathieu-Daudé
16408d7f2e76SPhilippe Mathieu-Daudé RCU_READ_LOCK_GUARD();
16418d7f2e76SPhilippe Mathieu-Daudé RAMBLOCK_FOREACH(block) {
16428d7f2e76SPhilippe Mathieu-Daudé if (block != new_block &&
16438d7f2e76SPhilippe Mathieu-Daudé !strcmp(block->idstr, new_block->idstr)) {
16448d7f2e76SPhilippe Mathieu-Daudé fprintf(stderr, "RAMBlock \"%s\" already registered, abort!\n",
16458d7f2e76SPhilippe Mathieu-Daudé new_block->idstr);
16468d7f2e76SPhilippe Mathieu-Daudé abort();
16478d7f2e76SPhilippe Mathieu-Daudé }
16488d7f2e76SPhilippe Mathieu-Daudé }
16498d7f2e76SPhilippe Mathieu-Daudé }
16508d7f2e76SPhilippe Mathieu-Daudé
1651a4a411fbSStefan Hajnoczi /* Called with the BQL held. */
qemu_ram_unset_idstr(RAMBlock * block)16528d7f2e76SPhilippe Mathieu-Daudé void qemu_ram_unset_idstr(RAMBlock *block)
16538d7f2e76SPhilippe Mathieu-Daudé {
16548d7f2e76SPhilippe Mathieu-Daudé /* FIXME: arch_init.c assumes that this is not called throughout
16558d7f2e76SPhilippe Mathieu-Daudé * migration. Ignore the problem since hot-unplug during migration
16568d7f2e76SPhilippe Mathieu-Daudé * does not work anyway.
16578d7f2e76SPhilippe Mathieu-Daudé */
16588d7f2e76SPhilippe Mathieu-Daudé if (block) {
16598d7f2e76SPhilippe Mathieu-Daudé memset(block->idstr, 0, sizeof(block->idstr));
16608d7f2e76SPhilippe Mathieu-Daudé }
16618d7f2e76SPhilippe Mathieu-Daudé }
16628d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_pagesize(RAMBlock * rb)16638d7f2e76SPhilippe Mathieu-Daudé size_t qemu_ram_pagesize(RAMBlock *rb)
16648d7f2e76SPhilippe Mathieu-Daudé {
16658d7f2e76SPhilippe Mathieu-Daudé return rb->page_size;
16668d7f2e76SPhilippe Mathieu-Daudé }
16678d7f2e76SPhilippe Mathieu-Daudé
16688d7f2e76SPhilippe Mathieu-Daudé /* Returns the largest size of page in use */
qemu_ram_pagesize_largest(void)16698d7f2e76SPhilippe Mathieu-Daudé size_t qemu_ram_pagesize_largest(void)
16708d7f2e76SPhilippe Mathieu-Daudé {
16718d7f2e76SPhilippe Mathieu-Daudé RAMBlock *block;
16728d7f2e76SPhilippe Mathieu-Daudé size_t largest = 0;
16738d7f2e76SPhilippe Mathieu-Daudé
16748d7f2e76SPhilippe Mathieu-Daudé RAMBLOCK_FOREACH(block) {
16758d7f2e76SPhilippe Mathieu-Daudé largest = MAX(largest, qemu_ram_pagesize(block));
16768d7f2e76SPhilippe Mathieu-Daudé }
16778d7f2e76SPhilippe Mathieu-Daudé
16788d7f2e76SPhilippe Mathieu-Daudé return largest;
16798d7f2e76SPhilippe Mathieu-Daudé }
16808d7f2e76SPhilippe Mathieu-Daudé
memory_try_enable_merging(void * addr,size_t len)16818d7f2e76SPhilippe Mathieu-Daudé static int memory_try_enable_merging(void *addr, size_t len)
16828d7f2e76SPhilippe Mathieu-Daudé {
16838d7f2e76SPhilippe Mathieu-Daudé if (!machine_mem_merge(current_machine)) {
16848d7f2e76SPhilippe Mathieu-Daudé /* disabled by the user */
16858d7f2e76SPhilippe Mathieu-Daudé return 0;
16868d7f2e76SPhilippe Mathieu-Daudé }
16878d7f2e76SPhilippe Mathieu-Daudé
16888d7f2e76SPhilippe Mathieu-Daudé return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
16898d7f2e76SPhilippe Mathieu-Daudé }
16908d7f2e76SPhilippe Mathieu-Daudé
16918d7f2e76SPhilippe Mathieu-Daudé /*
16928d7f2e76SPhilippe Mathieu-Daudé * Resizing RAM while migrating can result in the migration being canceled.
16938d7f2e76SPhilippe Mathieu-Daudé * Care has to be taken if the guest might have already detected the memory.
16948d7f2e76SPhilippe Mathieu-Daudé *
16958d7f2e76SPhilippe Mathieu-Daudé * As memory core doesn't know how is memory accessed, it is up to
16968d7f2e76SPhilippe Mathieu-Daudé * resize callback to update device state and/or add assertions to detect
16978d7f2e76SPhilippe Mathieu-Daudé * misuse, if necessary.
16988d7f2e76SPhilippe Mathieu-Daudé */
qemu_ram_resize(RAMBlock * block,ram_addr_t newsize,Error ** errp)16998d7f2e76SPhilippe Mathieu-Daudé int qemu_ram_resize(RAMBlock *block, ram_addr_t newsize, Error **errp)
17008d7f2e76SPhilippe Mathieu-Daudé {
17018d7f2e76SPhilippe Mathieu-Daudé const ram_addr_t oldsize = block->used_length;
17028d7f2e76SPhilippe Mathieu-Daudé const ram_addr_t unaligned_size = newsize;
17038d7f2e76SPhilippe Mathieu-Daudé
17048d7f2e76SPhilippe Mathieu-Daudé assert(block);
17058d7f2e76SPhilippe Mathieu-Daudé
17069260bd40SRichard Henderson newsize = TARGET_PAGE_ALIGN(newsize);
17079260bd40SRichard Henderson newsize = REAL_HOST_PAGE_ALIGN(newsize);
17088d7f2e76SPhilippe Mathieu-Daudé
17098d7f2e76SPhilippe Mathieu-Daudé if (block->used_length == newsize) {
17108d7f2e76SPhilippe Mathieu-Daudé /*
17118d7f2e76SPhilippe Mathieu-Daudé * We don't have to resize the ram block (which only knows aligned
17128d7f2e76SPhilippe Mathieu-Daudé * sizes), however, we have to notify if the unaligned size changed.
17138d7f2e76SPhilippe Mathieu-Daudé */
17148d7f2e76SPhilippe Mathieu-Daudé if (unaligned_size != memory_region_size(block->mr)) {
17158d7f2e76SPhilippe Mathieu-Daudé memory_region_set_size(block->mr, unaligned_size);
17168d7f2e76SPhilippe Mathieu-Daudé if (block->resized) {
17178d7f2e76SPhilippe Mathieu-Daudé block->resized(block->idstr, unaligned_size, block->host);
17188d7f2e76SPhilippe Mathieu-Daudé }
17198d7f2e76SPhilippe Mathieu-Daudé }
17208d7f2e76SPhilippe Mathieu-Daudé return 0;
17218d7f2e76SPhilippe Mathieu-Daudé }
17228d7f2e76SPhilippe Mathieu-Daudé
17238d7f2e76SPhilippe Mathieu-Daudé if (!(block->flags & RAM_RESIZEABLE)) {
17248d7f2e76SPhilippe Mathieu-Daudé error_setg_errno(errp, EINVAL,
17258d7f2e76SPhilippe Mathieu-Daudé "Size mismatch: %s: 0x" RAM_ADDR_FMT
17268d7f2e76SPhilippe Mathieu-Daudé " != 0x" RAM_ADDR_FMT, block->idstr,
17278d7f2e76SPhilippe Mathieu-Daudé newsize, block->used_length);
17288d7f2e76SPhilippe Mathieu-Daudé return -EINVAL;
17298d7f2e76SPhilippe Mathieu-Daudé }
17308d7f2e76SPhilippe Mathieu-Daudé
17318d7f2e76SPhilippe Mathieu-Daudé if (block->max_length < newsize) {
17328d7f2e76SPhilippe Mathieu-Daudé error_setg_errno(errp, EINVAL,
17338d7f2e76SPhilippe Mathieu-Daudé "Size too large: %s: 0x" RAM_ADDR_FMT
17348d7f2e76SPhilippe Mathieu-Daudé " > 0x" RAM_ADDR_FMT, block->idstr,
17358d7f2e76SPhilippe Mathieu-Daudé newsize, block->max_length);
17368d7f2e76SPhilippe Mathieu-Daudé return -EINVAL;
17378d7f2e76SPhilippe Mathieu-Daudé }
17388d7f2e76SPhilippe Mathieu-Daudé
17398d7f2e76SPhilippe Mathieu-Daudé /* Notify before modifying the ram block and touching the bitmaps. */
17408d7f2e76SPhilippe Mathieu-Daudé if (block->host) {
17418d7f2e76SPhilippe Mathieu-Daudé ram_block_notify_resize(block->host, oldsize, newsize);
17428d7f2e76SPhilippe Mathieu-Daudé }
17438d7f2e76SPhilippe Mathieu-Daudé
17448d7f2e76SPhilippe Mathieu-Daudé cpu_physical_memory_clear_dirty_range(block->offset, block->used_length);
17458d7f2e76SPhilippe Mathieu-Daudé block->used_length = newsize;
17468d7f2e76SPhilippe Mathieu-Daudé cpu_physical_memory_set_dirty_range(block->offset, block->used_length,
17478d7f2e76SPhilippe Mathieu-Daudé DIRTY_CLIENTS_ALL);
17488d7f2e76SPhilippe Mathieu-Daudé memory_region_set_size(block->mr, unaligned_size);
17498d7f2e76SPhilippe Mathieu-Daudé if (block->resized) {
17508d7f2e76SPhilippe Mathieu-Daudé block->resized(block->idstr, unaligned_size, block->host);
17518d7f2e76SPhilippe Mathieu-Daudé }
17528d7f2e76SPhilippe Mathieu-Daudé return 0;
17538d7f2e76SPhilippe Mathieu-Daudé }
17548d7f2e76SPhilippe Mathieu-Daudé
17558d7f2e76SPhilippe Mathieu-Daudé /*
17568d7f2e76SPhilippe Mathieu-Daudé * Trigger sync on the given ram block for range [start, start + length]
17578d7f2e76SPhilippe Mathieu-Daudé * with the backing store if one is available.
17588d7f2e76SPhilippe Mathieu-Daudé * Otherwise no-op.
17598d7f2e76SPhilippe Mathieu-Daudé * @Note: this is supposed to be a synchronous op.
17608d7f2e76SPhilippe Mathieu-Daudé */
qemu_ram_msync(RAMBlock * block,ram_addr_t start,ram_addr_t length)17618d7f2e76SPhilippe Mathieu-Daudé void qemu_ram_msync(RAMBlock *block, ram_addr_t start, ram_addr_t length)
17628d7f2e76SPhilippe Mathieu-Daudé {
17638d7f2e76SPhilippe Mathieu-Daudé /* The requested range should fit in within the block range */
17648d7f2e76SPhilippe Mathieu-Daudé g_assert((start + length) <= block->used_length);
17658d7f2e76SPhilippe Mathieu-Daudé
17668d7f2e76SPhilippe Mathieu-Daudé #ifdef CONFIG_LIBPMEM
17678d7f2e76SPhilippe Mathieu-Daudé /* The lack of support for pmem should not block the sync */
17688d7f2e76SPhilippe Mathieu-Daudé if (ramblock_is_pmem(block)) {
17698d7f2e76SPhilippe Mathieu-Daudé void *addr = ramblock_ptr(block, start);
17708d7f2e76SPhilippe Mathieu-Daudé pmem_persist(addr, length);
17718d7f2e76SPhilippe Mathieu-Daudé return;
17728d7f2e76SPhilippe Mathieu-Daudé }
17738d7f2e76SPhilippe Mathieu-Daudé #endif
17748d7f2e76SPhilippe Mathieu-Daudé if (block->fd >= 0) {
17758d7f2e76SPhilippe Mathieu-Daudé /**
17768d7f2e76SPhilippe Mathieu-Daudé * Case there is no support for PMEM or the memory has not been
17778d7f2e76SPhilippe Mathieu-Daudé * specified as persistent (or is not one) - use the msync.
17788d7f2e76SPhilippe Mathieu-Daudé * Less optimal but still achieves the same goal
17798d7f2e76SPhilippe Mathieu-Daudé */
17808d7f2e76SPhilippe Mathieu-Daudé void *addr = ramblock_ptr(block, start);
17818d7f2e76SPhilippe Mathieu-Daudé if (qemu_msync(addr, length, block->fd)) {
17828d7f2e76SPhilippe Mathieu-Daudé warn_report("%s: failed to sync memory range: start: "
17838d7f2e76SPhilippe Mathieu-Daudé RAM_ADDR_FMT " length: " RAM_ADDR_FMT,
17848d7f2e76SPhilippe Mathieu-Daudé __func__, start, length);
17858d7f2e76SPhilippe Mathieu-Daudé }
17868d7f2e76SPhilippe Mathieu-Daudé }
17878d7f2e76SPhilippe Mathieu-Daudé }
17888d7f2e76SPhilippe Mathieu-Daudé
17898d7f2e76SPhilippe Mathieu-Daudé /* Called with ram_list.mutex held */
dirty_memory_extend(ram_addr_t new_ram_size)1790b84f06c2SDavid Hildenbrand static void dirty_memory_extend(ram_addr_t new_ram_size)
17918d7f2e76SPhilippe Mathieu-Daudé {
1792b84f06c2SDavid Hildenbrand unsigned int old_num_blocks = ram_list.num_dirty_blocks;
1793b84f06c2SDavid Hildenbrand unsigned int new_num_blocks = DIV_ROUND_UP(new_ram_size,
17948d7f2e76SPhilippe Mathieu-Daudé DIRTY_MEMORY_BLOCK_SIZE);
17958d7f2e76SPhilippe Mathieu-Daudé int i;
17968d7f2e76SPhilippe Mathieu-Daudé
17978d7f2e76SPhilippe Mathieu-Daudé /* Only need to extend if block count increased */
17988d7f2e76SPhilippe Mathieu-Daudé if (new_num_blocks <= old_num_blocks) {
17998d7f2e76SPhilippe Mathieu-Daudé return;
18008d7f2e76SPhilippe Mathieu-Daudé }
18018d7f2e76SPhilippe Mathieu-Daudé
18028d7f2e76SPhilippe Mathieu-Daudé for (i = 0; i < DIRTY_MEMORY_NUM; i++) {
18038d7f2e76SPhilippe Mathieu-Daudé DirtyMemoryBlocks *old_blocks;
18048d7f2e76SPhilippe Mathieu-Daudé DirtyMemoryBlocks *new_blocks;
18058d7f2e76SPhilippe Mathieu-Daudé int j;
18068d7f2e76SPhilippe Mathieu-Daudé
18078d7f2e76SPhilippe Mathieu-Daudé old_blocks = qatomic_rcu_read(&ram_list.dirty_memory[i]);
18088d7f2e76SPhilippe Mathieu-Daudé new_blocks = g_malloc(sizeof(*new_blocks) +
18098d7f2e76SPhilippe Mathieu-Daudé sizeof(new_blocks->blocks[0]) * new_num_blocks);
18108d7f2e76SPhilippe Mathieu-Daudé
18118d7f2e76SPhilippe Mathieu-Daudé if (old_num_blocks) {
18128d7f2e76SPhilippe Mathieu-Daudé memcpy(new_blocks->blocks, old_blocks->blocks,
18138d7f2e76SPhilippe Mathieu-Daudé old_num_blocks * sizeof(old_blocks->blocks[0]));
18148d7f2e76SPhilippe Mathieu-Daudé }
18158d7f2e76SPhilippe Mathieu-Daudé
18168d7f2e76SPhilippe Mathieu-Daudé for (j = old_num_blocks; j < new_num_blocks; j++) {
18178d7f2e76SPhilippe Mathieu-Daudé new_blocks->blocks[j] = bitmap_new(DIRTY_MEMORY_BLOCK_SIZE);
18188d7f2e76SPhilippe Mathieu-Daudé }
18198d7f2e76SPhilippe Mathieu-Daudé
18208d7f2e76SPhilippe Mathieu-Daudé qatomic_rcu_set(&ram_list.dirty_memory[i], new_blocks);
18218d7f2e76SPhilippe Mathieu-Daudé
18228d7f2e76SPhilippe Mathieu-Daudé if (old_blocks) {
18238d7f2e76SPhilippe Mathieu-Daudé g_free_rcu(old_blocks, rcu);
18248d7f2e76SPhilippe Mathieu-Daudé }
18258d7f2e76SPhilippe Mathieu-Daudé }
1826b84f06c2SDavid Hildenbrand
1827b84f06c2SDavid Hildenbrand ram_list.num_dirty_blocks = new_num_blocks;
18288d7f2e76SPhilippe Mathieu-Daudé }
18298d7f2e76SPhilippe Mathieu-Daudé
ram_block_add(RAMBlock * new_block,Error ** errp)18308d7f2e76SPhilippe Mathieu-Daudé static void ram_block_add(RAMBlock *new_block, Error **errp)
18318d7f2e76SPhilippe Mathieu-Daudé {
18328d7f2e76SPhilippe Mathieu-Daudé const bool noreserve = qemu_ram_is_noreserve(new_block);
18338d7f2e76SPhilippe Mathieu-Daudé const bool shared = qemu_ram_is_shared(new_block);
18348d7f2e76SPhilippe Mathieu-Daudé RAMBlock *block;
18358d7f2e76SPhilippe Mathieu-Daudé RAMBlock *last_block = NULL;
183615f7a80cSXiaoyao Li bool free_on_error = false;
1837b84f06c2SDavid Hildenbrand ram_addr_t ram_size;
18388d7f2e76SPhilippe Mathieu-Daudé Error *err = NULL;
18398d7f2e76SPhilippe Mathieu-Daudé
18408d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_lock_ramlist();
18418d7f2e76SPhilippe Mathieu-Daudé new_block->offset = find_ram_offset(new_block->max_length);
18428d7f2e76SPhilippe Mathieu-Daudé
18438d7f2e76SPhilippe Mathieu-Daudé if (!new_block->host) {
18448d7f2e76SPhilippe Mathieu-Daudé if (xen_enabled()) {
18458d7f2e76SPhilippe Mathieu-Daudé xen_ram_alloc(new_block->offset, new_block->max_length,
18468d7f2e76SPhilippe Mathieu-Daudé new_block->mr, &err);
18478d7f2e76SPhilippe Mathieu-Daudé if (err) {
18488d7f2e76SPhilippe Mathieu-Daudé error_propagate(errp, err);
18498d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_unlock_ramlist();
18508d7f2e76SPhilippe Mathieu-Daudé return;
18518d7f2e76SPhilippe Mathieu-Daudé }
18528d7f2e76SPhilippe Mathieu-Daudé } else {
18538d7f2e76SPhilippe Mathieu-Daudé new_block->host = qemu_anon_ram_alloc(new_block->max_length,
18548d7f2e76SPhilippe Mathieu-Daudé &new_block->mr->align,
18558d7f2e76SPhilippe Mathieu-Daudé shared, noreserve);
18568d7f2e76SPhilippe Mathieu-Daudé if (!new_block->host) {
18578d7f2e76SPhilippe Mathieu-Daudé error_setg_errno(errp, errno,
18588d7f2e76SPhilippe Mathieu-Daudé "cannot set up guest memory '%s'",
18598d7f2e76SPhilippe Mathieu-Daudé memory_region_name(new_block->mr));
18608d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_unlock_ramlist();
18618d7f2e76SPhilippe Mathieu-Daudé return;
18628d7f2e76SPhilippe Mathieu-Daudé }
18638d7f2e76SPhilippe Mathieu-Daudé memory_try_enable_merging(new_block->host, new_block->max_length);
186415f7a80cSXiaoyao Li free_on_error = true;
186515f7a80cSXiaoyao Li }
186615f7a80cSXiaoyao Li }
186715f7a80cSXiaoyao Li
186815f7a80cSXiaoyao Li if (new_block->flags & RAM_GUEST_MEMFD) {
1869644a5277SZhenzhong Duan int ret;
1870644a5277SZhenzhong Duan
187115f7a80cSXiaoyao Li assert(kvm_enabled());
187215f7a80cSXiaoyao Li assert(new_block->guest_memfd < 0);
187315f7a80cSXiaoyao Li
1874644a5277SZhenzhong Duan ret = ram_block_discard_require(true);
1875644a5277SZhenzhong Duan if (ret < 0) {
1876644a5277SZhenzhong Duan error_setg_errno(errp, -ret,
1877852f0048SPaolo Bonzini "cannot set up private guest memory: discard currently blocked");
1878852f0048SPaolo Bonzini error_append_hint(errp, "Are you using assigned devices?\n");
1879852f0048SPaolo Bonzini goto out_free;
1880852f0048SPaolo Bonzini }
1881852f0048SPaolo Bonzini
188215f7a80cSXiaoyao Li new_block->guest_memfd = kvm_create_guest_memfd(new_block->max_length,
188315f7a80cSXiaoyao Li 0, errp);
188415f7a80cSXiaoyao Li if (new_block->guest_memfd < 0) {
188515f7a80cSXiaoyao Li qemu_mutex_unlock_ramlist();
188615f7a80cSXiaoyao Li goto out_free;
18878d7f2e76SPhilippe Mathieu-Daudé }
18888d7f2e76SPhilippe Mathieu-Daudé }
18898d7f2e76SPhilippe Mathieu-Daudé
1890b84f06c2SDavid Hildenbrand ram_size = (new_block->offset + new_block->max_length) >> TARGET_PAGE_BITS;
1891b84f06c2SDavid Hildenbrand dirty_memory_extend(ram_size);
18928d7f2e76SPhilippe Mathieu-Daudé /* Keep the list sorted from biggest to smallest block. Unlike QTAILQ,
18938d7f2e76SPhilippe Mathieu-Daudé * QLIST (which has an RCU-friendly variant) does not have insertion at
18948d7f2e76SPhilippe Mathieu-Daudé * tail, so save the last element in last_block.
18958d7f2e76SPhilippe Mathieu-Daudé */
18968d7f2e76SPhilippe Mathieu-Daudé RAMBLOCK_FOREACH(block) {
18978d7f2e76SPhilippe Mathieu-Daudé last_block = block;
18988d7f2e76SPhilippe Mathieu-Daudé if (block->max_length < new_block->max_length) {
18998d7f2e76SPhilippe Mathieu-Daudé break;
19008d7f2e76SPhilippe Mathieu-Daudé }
19018d7f2e76SPhilippe Mathieu-Daudé }
19028d7f2e76SPhilippe Mathieu-Daudé if (block) {
19038d7f2e76SPhilippe Mathieu-Daudé QLIST_INSERT_BEFORE_RCU(block, new_block, next);
19048d7f2e76SPhilippe Mathieu-Daudé } else if (last_block) {
19058d7f2e76SPhilippe Mathieu-Daudé QLIST_INSERT_AFTER_RCU(last_block, new_block, next);
19068d7f2e76SPhilippe Mathieu-Daudé } else { /* list is empty */
19078d7f2e76SPhilippe Mathieu-Daudé QLIST_INSERT_HEAD_RCU(&ram_list.blocks, new_block, next);
19088d7f2e76SPhilippe Mathieu-Daudé }
19098d7f2e76SPhilippe Mathieu-Daudé ram_list.mru_block = NULL;
19108d7f2e76SPhilippe Mathieu-Daudé
19118d7f2e76SPhilippe Mathieu-Daudé /* Write list before version */
19128d7f2e76SPhilippe Mathieu-Daudé smp_wmb();
19138d7f2e76SPhilippe Mathieu-Daudé ram_list.version++;
19148d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_unlock_ramlist();
19158d7f2e76SPhilippe Mathieu-Daudé
19168d7f2e76SPhilippe Mathieu-Daudé cpu_physical_memory_set_dirty_range(new_block->offset,
19178d7f2e76SPhilippe Mathieu-Daudé new_block->used_length,
19188d7f2e76SPhilippe Mathieu-Daudé DIRTY_CLIENTS_ALL);
19198d7f2e76SPhilippe Mathieu-Daudé
19208d7f2e76SPhilippe Mathieu-Daudé if (new_block->host) {
19218d7f2e76SPhilippe Mathieu-Daudé qemu_ram_setup_dump(new_block->host, new_block->max_length);
19228d7f2e76SPhilippe Mathieu-Daudé qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_HUGEPAGE);
19238d7f2e76SPhilippe Mathieu-Daudé /*
19248d7f2e76SPhilippe Mathieu-Daudé * MADV_DONTFORK is also needed by KVM in absence of synchronous MMU
19258d7f2e76SPhilippe Mathieu-Daudé * Configure it unless the machine is a qtest server, in which case
19268d7f2e76SPhilippe Mathieu-Daudé * KVM is not used and it may be forked (eg for fuzzing purposes).
19278d7f2e76SPhilippe Mathieu-Daudé */
19288d7f2e76SPhilippe Mathieu-Daudé if (!qtest_enabled()) {
19298d7f2e76SPhilippe Mathieu-Daudé qemu_madvise(new_block->host, new_block->max_length,
19308d7f2e76SPhilippe Mathieu-Daudé QEMU_MADV_DONTFORK);
19318d7f2e76SPhilippe Mathieu-Daudé }
19328d7f2e76SPhilippe Mathieu-Daudé ram_block_notify_add(new_block->host, new_block->used_length,
19338d7f2e76SPhilippe Mathieu-Daudé new_block->max_length);
19348d7f2e76SPhilippe Mathieu-Daudé }
193515f7a80cSXiaoyao Li return;
193615f7a80cSXiaoyao Li
193715f7a80cSXiaoyao Li out_free:
193815f7a80cSXiaoyao Li if (free_on_error) {
193915f7a80cSXiaoyao Li qemu_anon_ram_free(new_block->host, new_block->max_length);
194015f7a80cSXiaoyao Li new_block->host = NULL;
194115f7a80cSXiaoyao Li }
19428d7f2e76SPhilippe Mathieu-Daudé }
19438d7f2e76SPhilippe Mathieu-Daudé
19448d7f2e76SPhilippe Mathieu-Daudé #ifdef CONFIG_POSIX
qemu_ram_alloc_from_fd(ram_addr_t size,MemoryRegion * mr,uint32_t ram_flags,int fd,off_t offset,Error ** errp)19458d7f2e76SPhilippe Mathieu-Daudé RAMBlock *qemu_ram_alloc_from_fd(ram_addr_t size, MemoryRegion *mr,
19468d7f2e76SPhilippe Mathieu-Daudé uint32_t ram_flags, int fd, off_t offset,
19478d7f2e76SPhilippe Mathieu-Daudé Error **errp)
19488d7f2e76SPhilippe Mathieu-Daudé {
19498d7f2e76SPhilippe Mathieu-Daudé RAMBlock *new_block;
19508d7f2e76SPhilippe Mathieu-Daudé Error *local_err = NULL;
19518d7f2e76SPhilippe Mathieu-Daudé int64_t file_size, file_align;
19528d7f2e76SPhilippe Mathieu-Daudé
19538d7f2e76SPhilippe Mathieu-Daudé /* Just support these ram flags by now. */
19548d7f2e76SPhilippe Mathieu-Daudé assert((ram_flags & ~(RAM_SHARED | RAM_PMEM | RAM_NORESERVE |
19558d7f2e76SPhilippe Mathieu-Daudé RAM_PROTECTED | RAM_NAMED_FILE | RAM_READONLY |
195615f7a80cSXiaoyao Li RAM_READONLY_FD | RAM_GUEST_MEMFD)) == 0);
19578d7f2e76SPhilippe Mathieu-Daudé
19588d7f2e76SPhilippe Mathieu-Daudé if (xen_enabled()) {
19598d7f2e76SPhilippe Mathieu-Daudé error_setg(errp, "-mem-path not supported with Xen");
19608d7f2e76SPhilippe Mathieu-Daudé return NULL;
19618d7f2e76SPhilippe Mathieu-Daudé }
19628d7f2e76SPhilippe Mathieu-Daudé
19638d7f2e76SPhilippe Mathieu-Daudé if (kvm_enabled() && !kvm_has_sync_mmu()) {
19648d7f2e76SPhilippe Mathieu-Daudé error_setg(errp,
19658d7f2e76SPhilippe Mathieu-Daudé "host lacks kvm mmu notifiers, -mem-path unsupported");
19668d7f2e76SPhilippe Mathieu-Daudé return NULL;
19678d7f2e76SPhilippe Mathieu-Daudé }
19688d7f2e76SPhilippe Mathieu-Daudé
19699260bd40SRichard Henderson size = TARGET_PAGE_ALIGN(size);
19709260bd40SRichard Henderson size = REAL_HOST_PAGE_ALIGN(size);
19719260bd40SRichard Henderson
19728d7f2e76SPhilippe Mathieu-Daudé file_size = get_file_size(fd);
1973*7fd02244SSteve Sistare if (file_size && file_size < offset + size) {
1974*7fd02244SSteve Sistare error_setg(errp, "%s backing store size 0x%" PRIx64
1975*7fd02244SSteve Sistare " is too small for 'size' option 0x" RAM_ADDR_FMT
1976*7fd02244SSteve Sistare " plus 'offset' option 0x%" PRIx64,
1977*7fd02244SSteve Sistare memory_region_name(mr), file_size, size,
1978*7fd02244SSteve Sistare (uint64_t)offset);
19798d7f2e76SPhilippe Mathieu-Daudé return NULL;
19808d7f2e76SPhilippe Mathieu-Daudé }
19818d7f2e76SPhilippe Mathieu-Daudé
19828d7f2e76SPhilippe Mathieu-Daudé file_align = get_file_align(fd);
19838d7f2e76SPhilippe Mathieu-Daudé if (file_align > 0 && file_align > mr->align) {
19848d7f2e76SPhilippe Mathieu-Daudé error_setg(errp, "backing store align 0x%" PRIx64
19858d7f2e76SPhilippe Mathieu-Daudé " is larger than 'align' option 0x%" PRIx64,
19868d7f2e76SPhilippe Mathieu-Daudé file_align, mr->align);
19878d7f2e76SPhilippe Mathieu-Daudé return NULL;
19888d7f2e76SPhilippe Mathieu-Daudé }
19898d7f2e76SPhilippe Mathieu-Daudé
19908d7f2e76SPhilippe Mathieu-Daudé new_block = g_malloc0(sizeof(*new_block));
19918d7f2e76SPhilippe Mathieu-Daudé new_block->mr = mr;
19928d7f2e76SPhilippe Mathieu-Daudé new_block->used_length = size;
19938d7f2e76SPhilippe Mathieu-Daudé new_block->max_length = size;
19948d7f2e76SPhilippe Mathieu-Daudé new_block->flags = ram_flags;
199515f7a80cSXiaoyao Li new_block->guest_memfd = -1;
19968d7f2e76SPhilippe Mathieu-Daudé new_block->host = file_ram_alloc(new_block, size, fd, !file_size, offset,
19978d7f2e76SPhilippe Mathieu-Daudé errp);
19988d7f2e76SPhilippe Mathieu-Daudé if (!new_block->host) {
19998d7f2e76SPhilippe Mathieu-Daudé g_free(new_block);
20008d7f2e76SPhilippe Mathieu-Daudé return NULL;
20018d7f2e76SPhilippe Mathieu-Daudé }
20028d7f2e76SPhilippe Mathieu-Daudé
20038d7f2e76SPhilippe Mathieu-Daudé ram_block_add(new_block, &local_err);
20048d7f2e76SPhilippe Mathieu-Daudé if (local_err) {
20058d7f2e76SPhilippe Mathieu-Daudé g_free(new_block);
20068d7f2e76SPhilippe Mathieu-Daudé error_propagate(errp, local_err);
20078d7f2e76SPhilippe Mathieu-Daudé return NULL;
20088d7f2e76SPhilippe Mathieu-Daudé }
20098d7f2e76SPhilippe Mathieu-Daudé return new_block;
20108d7f2e76SPhilippe Mathieu-Daudé
20118d7f2e76SPhilippe Mathieu-Daudé }
20128d7f2e76SPhilippe Mathieu-Daudé
20138d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_alloc_from_file(ram_addr_t size,MemoryRegion * mr,uint32_t ram_flags,const char * mem_path,off_t offset,Error ** errp)20148d7f2e76SPhilippe Mathieu-Daudé RAMBlock *qemu_ram_alloc_from_file(ram_addr_t size, MemoryRegion *mr,
20158d7f2e76SPhilippe Mathieu-Daudé uint32_t ram_flags, const char *mem_path,
20168d7f2e76SPhilippe Mathieu-Daudé off_t offset, Error **errp)
20178d7f2e76SPhilippe Mathieu-Daudé {
20188d7f2e76SPhilippe Mathieu-Daudé int fd;
20198d7f2e76SPhilippe Mathieu-Daudé bool created;
20208d7f2e76SPhilippe Mathieu-Daudé RAMBlock *block;
20218d7f2e76SPhilippe Mathieu-Daudé
20228d7f2e76SPhilippe Mathieu-Daudé fd = file_ram_open(mem_path, memory_region_name(mr),
20238d7f2e76SPhilippe Mathieu-Daudé !!(ram_flags & RAM_READONLY_FD), &created);
20248d7f2e76SPhilippe Mathieu-Daudé if (fd < 0) {
20258d7f2e76SPhilippe Mathieu-Daudé error_setg_errno(errp, -fd, "can't open backing store %s for guest RAM",
20268d7f2e76SPhilippe Mathieu-Daudé mem_path);
20278d7f2e76SPhilippe Mathieu-Daudé if (!(ram_flags & RAM_READONLY_FD) && !(ram_flags & RAM_SHARED) &&
20288d7f2e76SPhilippe Mathieu-Daudé fd == -EACCES) {
20298d7f2e76SPhilippe Mathieu-Daudé /*
20308d7f2e76SPhilippe Mathieu-Daudé * If we can open the file R/O (note: will never create a new file)
20318d7f2e76SPhilippe Mathieu-Daudé * and we are dealing with a private mapping, there are still ways
20328d7f2e76SPhilippe Mathieu-Daudé * to consume such files and get RAM instead of ROM.
20338d7f2e76SPhilippe Mathieu-Daudé */
20348d7f2e76SPhilippe Mathieu-Daudé fd = file_ram_open(mem_path, memory_region_name(mr), true,
20358d7f2e76SPhilippe Mathieu-Daudé &created);
20368d7f2e76SPhilippe Mathieu-Daudé if (fd < 0) {
20378d7f2e76SPhilippe Mathieu-Daudé return NULL;
20388d7f2e76SPhilippe Mathieu-Daudé }
20398d7f2e76SPhilippe Mathieu-Daudé assert(!created);
20408d7f2e76SPhilippe Mathieu-Daudé close(fd);
20418d7f2e76SPhilippe Mathieu-Daudé error_append_hint(errp, "Consider opening the backing store"
20428d7f2e76SPhilippe Mathieu-Daudé " read-only but still creating writable RAM using"
20438d7f2e76SPhilippe Mathieu-Daudé " '-object memory-backend-file,readonly=on,rom=off...'"
20448d7f2e76SPhilippe Mathieu-Daudé " (see \"VM templating\" documentation)\n");
20458d7f2e76SPhilippe Mathieu-Daudé }
20468d7f2e76SPhilippe Mathieu-Daudé return NULL;
20478d7f2e76SPhilippe Mathieu-Daudé }
20488d7f2e76SPhilippe Mathieu-Daudé
20498d7f2e76SPhilippe Mathieu-Daudé block = qemu_ram_alloc_from_fd(size, mr, ram_flags, fd, offset, errp);
20508d7f2e76SPhilippe Mathieu-Daudé if (!block) {
20518d7f2e76SPhilippe Mathieu-Daudé if (created) {
20528d7f2e76SPhilippe Mathieu-Daudé unlink(mem_path);
20538d7f2e76SPhilippe Mathieu-Daudé }
20548d7f2e76SPhilippe Mathieu-Daudé close(fd);
20558d7f2e76SPhilippe Mathieu-Daudé return NULL;
20568d7f2e76SPhilippe Mathieu-Daudé }
20578d7f2e76SPhilippe Mathieu-Daudé
20588d7f2e76SPhilippe Mathieu-Daudé return block;
20598d7f2e76SPhilippe Mathieu-Daudé }
20608d7f2e76SPhilippe Mathieu-Daudé #endif
20618d7f2e76SPhilippe Mathieu-Daudé
20628d7f2e76SPhilippe Mathieu-Daudé static
qemu_ram_alloc_internal(ram_addr_t size,ram_addr_t max_size,void (* resized)(const char *,uint64_t length,void * host),void * host,uint32_t ram_flags,MemoryRegion * mr,Error ** errp)20638d7f2e76SPhilippe Mathieu-Daudé RAMBlock *qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
20648d7f2e76SPhilippe Mathieu-Daudé void (*resized)(const char*,
20658d7f2e76SPhilippe Mathieu-Daudé uint64_t length,
20668d7f2e76SPhilippe Mathieu-Daudé void *host),
20678d7f2e76SPhilippe Mathieu-Daudé void *host, uint32_t ram_flags,
20688d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr, Error **errp)
20698d7f2e76SPhilippe Mathieu-Daudé {
20708d7f2e76SPhilippe Mathieu-Daudé RAMBlock *new_block;
20718d7f2e76SPhilippe Mathieu-Daudé Error *local_err = NULL;
20729260bd40SRichard Henderson int align;
20738d7f2e76SPhilippe Mathieu-Daudé
20748d7f2e76SPhilippe Mathieu-Daudé assert((ram_flags & ~(RAM_SHARED | RAM_RESIZEABLE | RAM_PREALLOC |
207515f7a80cSXiaoyao Li RAM_NORESERVE | RAM_GUEST_MEMFD)) == 0);
20768d7f2e76SPhilippe Mathieu-Daudé assert(!host ^ (ram_flags & RAM_PREALLOC));
20778d7f2e76SPhilippe Mathieu-Daudé
20789260bd40SRichard Henderson align = qemu_real_host_page_size();
20799260bd40SRichard Henderson align = MAX(align, TARGET_PAGE_SIZE);
20809260bd40SRichard Henderson size = ROUND_UP(size, align);
20819260bd40SRichard Henderson max_size = ROUND_UP(max_size, align);
20829260bd40SRichard Henderson
20838d7f2e76SPhilippe Mathieu-Daudé new_block = g_malloc0(sizeof(*new_block));
20848d7f2e76SPhilippe Mathieu-Daudé new_block->mr = mr;
20858d7f2e76SPhilippe Mathieu-Daudé new_block->resized = resized;
20868d7f2e76SPhilippe Mathieu-Daudé new_block->used_length = size;
20878d7f2e76SPhilippe Mathieu-Daudé new_block->max_length = max_size;
20888d7f2e76SPhilippe Mathieu-Daudé assert(max_size >= size);
20898d7f2e76SPhilippe Mathieu-Daudé new_block->fd = -1;
209015f7a80cSXiaoyao Li new_block->guest_memfd = -1;
20918d7f2e76SPhilippe Mathieu-Daudé new_block->page_size = qemu_real_host_page_size();
20928d7f2e76SPhilippe Mathieu-Daudé new_block->host = host;
20938d7f2e76SPhilippe Mathieu-Daudé new_block->flags = ram_flags;
20948d7f2e76SPhilippe Mathieu-Daudé ram_block_add(new_block, &local_err);
20958d7f2e76SPhilippe Mathieu-Daudé if (local_err) {
20968d7f2e76SPhilippe Mathieu-Daudé g_free(new_block);
20978d7f2e76SPhilippe Mathieu-Daudé error_propagate(errp, local_err);
20988d7f2e76SPhilippe Mathieu-Daudé return NULL;
20998d7f2e76SPhilippe Mathieu-Daudé }
21008d7f2e76SPhilippe Mathieu-Daudé return new_block;
21018d7f2e76SPhilippe Mathieu-Daudé }
21028d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_alloc_from_ptr(ram_addr_t size,void * host,MemoryRegion * mr,Error ** errp)21038d7f2e76SPhilippe Mathieu-Daudé RAMBlock *qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
21048d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr, Error **errp)
21058d7f2e76SPhilippe Mathieu-Daudé {
21068d7f2e76SPhilippe Mathieu-Daudé return qemu_ram_alloc_internal(size, size, NULL, host, RAM_PREALLOC, mr,
21078d7f2e76SPhilippe Mathieu-Daudé errp);
21088d7f2e76SPhilippe Mathieu-Daudé }
21098d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_alloc(ram_addr_t size,uint32_t ram_flags,MemoryRegion * mr,Error ** errp)21108d7f2e76SPhilippe Mathieu-Daudé RAMBlock *qemu_ram_alloc(ram_addr_t size, uint32_t ram_flags,
21118d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr, Error **errp)
21128d7f2e76SPhilippe Mathieu-Daudé {
211315f7a80cSXiaoyao Li assert((ram_flags & ~(RAM_SHARED | RAM_NORESERVE | RAM_GUEST_MEMFD)) == 0);
21148d7f2e76SPhilippe Mathieu-Daudé return qemu_ram_alloc_internal(size, size, NULL, NULL, ram_flags, mr, errp);
21158d7f2e76SPhilippe Mathieu-Daudé }
21168d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_alloc_resizeable(ram_addr_t size,ram_addr_t maxsz,void (* resized)(const char *,uint64_t length,void * host),MemoryRegion * mr,Error ** errp)21178d7f2e76SPhilippe Mathieu-Daudé RAMBlock *qemu_ram_alloc_resizeable(ram_addr_t size, ram_addr_t maxsz,
21188d7f2e76SPhilippe Mathieu-Daudé void (*resized)(const char*,
21198d7f2e76SPhilippe Mathieu-Daudé uint64_t length,
21208d7f2e76SPhilippe Mathieu-Daudé void *host),
21218d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr, Error **errp)
21228d7f2e76SPhilippe Mathieu-Daudé {
21238d7f2e76SPhilippe Mathieu-Daudé return qemu_ram_alloc_internal(size, maxsz, resized, NULL,
21248d7f2e76SPhilippe Mathieu-Daudé RAM_RESIZEABLE, mr, errp);
21258d7f2e76SPhilippe Mathieu-Daudé }
21268d7f2e76SPhilippe Mathieu-Daudé
reclaim_ramblock(RAMBlock * block)21278d7f2e76SPhilippe Mathieu-Daudé static void reclaim_ramblock(RAMBlock *block)
21288d7f2e76SPhilippe Mathieu-Daudé {
21298d7f2e76SPhilippe Mathieu-Daudé if (block->flags & RAM_PREALLOC) {
21308d7f2e76SPhilippe Mathieu-Daudé ;
21318d7f2e76SPhilippe Mathieu-Daudé } else if (xen_enabled()) {
21328d7f2e76SPhilippe Mathieu-Daudé xen_invalidate_map_cache_entry(block->host);
21338d7f2e76SPhilippe Mathieu-Daudé #ifndef _WIN32
21348d7f2e76SPhilippe Mathieu-Daudé } else if (block->fd >= 0) {
21358d7f2e76SPhilippe Mathieu-Daudé qemu_ram_munmap(block->fd, block->host, block->max_length);
21368d7f2e76SPhilippe Mathieu-Daudé close(block->fd);
21378d7f2e76SPhilippe Mathieu-Daudé #endif
21388d7f2e76SPhilippe Mathieu-Daudé } else {
21398d7f2e76SPhilippe Mathieu-Daudé qemu_anon_ram_free(block->host, block->max_length);
21408d7f2e76SPhilippe Mathieu-Daudé }
214115f7a80cSXiaoyao Li
214215f7a80cSXiaoyao Li if (block->guest_memfd >= 0) {
214315f7a80cSXiaoyao Li close(block->guest_memfd);
2144852f0048SPaolo Bonzini ram_block_discard_require(false);
214515f7a80cSXiaoyao Li }
214615f7a80cSXiaoyao Li
21478d7f2e76SPhilippe Mathieu-Daudé g_free(block);
21488d7f2e76SPhilippe Mathieu-Daudé }
21498d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_free(RAMBlock * block)21508d7f2e76SPhilippe Mathieu-Daudé void qemu_ram_free(RAMBlock *block)
21518d7f2e76SPhilippe Mathieu-Daudé {
21528d7f2e76SPhilippe Mathieu-Daudé if (!block) {
21538d7f2e76SPhilippe Mathieu-Daudé return;
21548d7f2e76SPhilippe Mathieu-Daudé }
21558d7f2e76SPhilippe Mathieu-Daudé
21568d7f2e76SPhilippe Mathieu-Daudé if (block->host) {
21578d7f2e76SPhilippe Mathieu-Daudé ram_block_notify_remove(block->host, block->used_length,
21588d7f2e76SPhilippe Mathieu-Daudé block->max_length);
21598d7f2e76SPhilippe Mathieu-Daudé }
21608d7f2e76SPhilippe Mathieu-Daudé
21618d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_lock_ramlist();
21628d7f2e76SPhilippe Mathieu-Daudé QLIST_REMOVE_RCU(block, next);
21638d7f2e76SPhilippe Mathieu-Daudé ram_list.mru_block = NULL;
21648d7f2e76SPhilippe Mathieu-Daudé /* Write list before version */
21658d7f2e76SPhilippe Mathieu-Daudé smp_wmb();
21668d7f2e76SPhilippe Mathieu-Daudé ram_list.version++;
21678d7f2e76SPhilippe Mathieu-Daudé call_rcu(block, reclaim_ramblock, rcu);
21688d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_unlock_ramlist();
21698d7f2e76SPhilippe Mathieu-Daudé }
21708d7f2e76SPhilippe Mathieu-Daudé
21718d7f2e76SPhilippe Mathieu-Daudé #ifndef _WIN32
qemu_ram_remap(ram_addr_t addr,ram_addr_t length)21728d7f2e76SPhilippe Mathieu-Daudé void qemu_ram_remap(ram_addr_t addr, ram_addr_t length)
21738d7f2e76SPhilippe Mathieu-Daudé {
21748d7f2e76SPhilippe Mathieu-Daudé RAMBlock *block;
21758d7f2e76SPhilippe Mathieu-Daudé ram_addr_t offset;
21768d7f2e76SPhilippe Mathieu-Daudé int flags;
21778d7f2e76SPhilippe Mathieu-Daudé void *area, *vaddr;
21788d7f2e76SPhilippe Mathieu-Daudé int prot;
21798d7f2e76SPhilippe Mathieu-Daudé
21808d7f2e76SPhilippe Mathieu-Daudé RAMBLOCK_FOREACH(block) {
21818d7f2e76SPhilippe Mathieu-Daudé offset = addr - block->offset;
21828d7f2e76SPhilippe Mathieu-Daudé if (offset < block->max_length) {
21838d7f2e76SPhilippe Mathieu-Daudé vaddr = ramblock_ptr(block, offset);
21848d7f2e76SPhilippe Mathieu-Daudé if (block->flags & RAM_PREALLOC) {
21858d7f2e76SPhilippe Mathieu-Daudé ;
21868d7f2e76SPhilippe Mathieu-Daudé } else if (xen_enabled()) {
21878d7f2e76SPhilippe Mathieu-Daudé abort();
21888d7f2e76SPhilippe Mathieu-Daudé } else {
21898d7f2e76SPhilippe Mathieu-Daudé flags = MAP_FIXED;
21908d7f2e76SPhilippe Mathieu-Daudé flags |= block->flags & RAM_SHARED ?
21918d7f2e76SPhilippe Mathieu-Daudé MAP_SHARED : MAP_PRIVATE;
21928d7f2e76SPhilippe Mathieu-Daudé flags |= block->flags & RAM_NORESERVE ? MAP_NORESERVE : 0;
21938d7f2e76SPhilippe Mathieu-Daudé prot = PROT_READ;
21948d7f2e76SPhilippe Mathieu-Daudé prot |= block->flags & RAM_READONLY ? 0 : PROT_WRITE;
21958d7f2e76SPhilippe Mathieu-Daudé if (block->fd >= 0) {
21968d7f2e76SPhilippe Mathieu-Daudé area = mmap(vaddr, length, prot, flags, block->fd,
21978d7f2e76SPhilippe Mathieu-Daudé offset + block->fd_offset);
21988d7f2e76SPhilippe Mathieu-Daudé } else {
21998d7f2e76SPhilippe Mathieu-Daudé flags |= MAP_ANONYMOUS;
22008d7f2e76SPhilippe Mathieu-Daudé area = mmap(vaddr, length, prot, flags, -1, 0);
22018d7f2e76SPhilippe Mathieu-Daudé }
22028d7f2e76SPhilippe Mathieu-Daudé if (area != vaddr) {
22038d7f2e76SPhilippe Mathieu-Daudé error_report("Could not remap addr: "
22048d7f2e76SPhilippe Mathieu-Daudé RAM_ADDR_FMT "@" RAM_ADDR_FMT "",
22058d7f2e76SPhilippe Mathieu-Daudé length, addr);
22068d7f2e76SPhilippe Mathieu-Daudé exit(1);
22078d7f2e76SPhilippe Mathieu-Daudé }
22088d7f2e76SPhilippe Mathieu-Daudé memory_try_enable_merging(vaddr, length);
22098d7f2e76SPhilippe Mathieu-Daudé qemu_ram_setup_dump(vaddr, length);
22108d7f2e76SPhilippe Mathieu-Daudé }
22118d7f2e76SPhilippe Mathieu-Daudé }
22128d7f2e76SPhilippe Mathieu-Daudé }
22138d7f2e76SPhilippe Mathieu-Daudé }
22148d7f2e76SPhilippe Mathieu-Daudé #endif /* !_WIN32 */
22158d7f2e76SPhilippe Mathieu-Daudé
2216a99dd337SJuergen Gross /*
2217a99dd337SJuergen Gross * Return a host pointer to guest's ram.
22185a5585f4SEdgar E. Iglesias * For Xen, foreign mappings get created if they don't already exist.
22198d7f2e76SPhilippe Mathieu-Daudé *
22205a5585f4SEdgar E. Iglesias * @block: block for the RAM to lookup (optional and may be NULL).
22215a5585f4SEdgar E. Iglesias * @addr: address within the memory region.
22225a5585f4SEdgar E. Iglesias * @size: pointer to requested size (optional and may be NULL).
22235a5585f4SEdgar E. Iglesias * size may get modified and return a value smaller than
22245a5585f4SEdgar E. Iglesias * what was requested.
22255a5585f4SEdgar E. Iglesias * @lock: wether to lock the mapping in xen-mapcache until invalidated.
22265a5585f4SEdgar E. Iglesias * @is_write: hint wether to map RW or RO in the xen-mapcache.
22275a5585f4SEdgar E. Iglesias * (optional and may always be set to true).
22288d7f2e76SPhilippe Mathieu-Daudé *
22298d7f2e76SPhilippe Mathieu-Daudé * Called within RCU critical section.
22308d7f2e76SPhilippe Mathieu-Daudé */
qemu_ram_ptr_length(RAMBlock * block,ram_addr_t addr,hwaddr * size,bool lock,bool is_write)2231aab4631aSManos Pitsidianakis static void *qemu_ram_ptr_length(RAMBlock *block, ram_addr_t addr,
22325a5585f4SEdgar E. Iglesias hwaddr *size, bool lock,
22335a5585f4SEdgar E. Iglesias bool is_write)
22348d7f2e76SPhilippe Mathieu-Daudé {
2235a99dd337SJuergen Gross hwaddr len = 0;
2236a99dd337SJuergen Gross
2237a99dd337SJuergen Gross if (size && *size == 0) {
22388d7f2e76SPhilippe Mathieu-Daudé return NULL;
22398d7f2e76SPhilippe Mathieu-Daudé }
22408d7f2e76SPhilippe Mathieu-Daudé
22418d7f2e76SPhilippe Mathieu-Daudé if (block == NULL) {
22428d7f2e76SPhilippe Mathieu-Daudé block = qemu_get_ram_block(addr);
22438d7f2e76SPhilippe Mathieu-Daudé addr -= block->offset;
22448d7f2e76SPhilippe Mathieu-Daudé }
2245a99dd337SJuergen Gross if (size) {
22468d7f2e76SPhilippe Mathieu-Daudé *size = MIN(*size, block->max_length - addr);
2247a99dd337SJuergen Gross len = *size;
2248a99dd337SJuergen Gross }
22498d7f2e76SPhilippe Mathieu-Daudé
22508d7f2e76SPhilippe Mathieu-Daudé if (xen_enabled() && block->host == NULL) {
22518d7f2e76SPhilippe Mathieu-Daudé /* We need to check if the requested address is in the RAM
22528d7f2e76SPhilippe Mathieu-Daudé * because we don't want to map the entire memory in QEMU.
22538d7f2e76SPhilippe Mathieu-Daudé * In that case just map the requested area.
22548d7f2e76SPhilippe Mathieu-Daudé */
2255a5bdc451SEdgar E. Iglesias if (xen_mr_is_memory(block->mr)) {
22565d1c2602SEdgar E. Iglesias return xen_map_cache(block->mr, block->offset + addr,
225749a72029SEdgar E. Iglesias len, block->offset,
225849a72029SEdgar E. Iglesias lock, lock, is_write);
22598d7f2e76SPhilippe Mathieu-Daudé }
22608d7f2e76SPhilippe Mathieu-Daudé
22615a5585f4SEdgar E. Iglesias block->host = xen_map_cache(block->mr, block->offset,
226249a72029SEdgar E. Iglesias block->max_length,
226349a72029SEdgar E. Iglesias block->offset,
226449a72029SEdgar E. Iglesias 1, lock, is_write);
22658d7f2e76SPhilippe Mathieu-Daudé }
22668d7f2e76SPhilippe Mathieu-Daudé
22678d7f2e76SPhilippe Mathieu-Daudé return ramblock_ptr(block, addr);
22688d7f2e76SPhilippe Mathieu-Daudé }
22698d7f2e76SPhilippe Mathieu-Daudé
2270a99dd337SJuergen Gross /*
2271a99dd337SJuergen Gross * Return a host pointer to ram allocated with qemu_ram_alloc.
2272a99dd337SJuergen Gross * This should not be used for general purpose DMA. Use address_space_map
2273a99dd337SJuergen Gross * or address_space_rw instead. For local memory (e.g. video ram) that the
2274a99dd337SJuergen Gross * device owns, use memory_region_get_ram_ptr.
2275a99dd337SJuergen Gross *
2276a99dd337SJuergen Gross * Called within RCU critical section.
2277a99dd337SJuergen Gross */
qemu_map_ram_ptr(RAMBlock * ram_block,ram_addr_t addr)2278a99dd337SJuergen Gross void *qemu_map_ram_ptr(RAMBlock *ram_block, ram_addr_t addr)
2279a99dd337SJuergen Gross {
22805a5585f4SEdgar E. Iglesias return qemu_ram_ptr_length(ram_block, addr, NULL, false, true);
2281a99dd337SJuergen Gross }
2282a99dd337SJuergen Gross
22838d7f2e76SPhilippe Mathieu-Daudé /* Return the offset of a hostpointer within a ramblock */
qemu_ram_block_host_offset(RAMBlock * rb,void * host)22848d7f2e76SPhilippe Mathieu-Daudé ram_addr_t qemu_ram_block_host_offset(RAMBlock *rb, void *host)
22858d7f2e76SPhilippe Mathieu-Daudé {
22868d7f2e76SPhilippe Mathieu-Daudé ram_addr_t res = (uint8_t *)host - (uint8_t *)rb->host;
22878d7f2e76SPhilippe Mathieu-Daudé assert((uintptr_t)host >= (uintptr_t)rb->host);
22888d7f2e76SPhilippe Mathieu-Daudé assert(res < rb->max_length);
22898d7f2e76SPhilippe Mathieu-Daudé
22908d7f2e76SPhilippe Mathieu-Daudé return res;
22918d7f2e76SPhilippe Mathieu-Daudé }
22928d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_block_from_host(void * ptr,bool round_offset,ram_addr_t * offset)22938d7f2e76SPhilippe Mathieu-Daudé RAMBlock *qemu_ram_block_from_host(void *ptr, bool round_offset,
22948d7f2e76SPhilippe Mathieu-Daudé ram_addr_t *offset)
22958d7f2e76SPhilippe Mathieu-Daudé {
22968d7f2e76SPhilippe Mathieu-Daudé RAMBlock *block;
22978d7f2e76SPhilippe Mathieu-Daudé uint8_t *host = ptr;
22988d7f2e76SPhilippe Mathieu-Daudé
22998d7f2e76SPhilippe Mathieu-Daudé if (xen_enabled()) {
23008d7f2e76SPhilippe Mathieu-Daudé ram_addr_t ram_addr;
23018d7f2e76SPhilippe Mathieu-Daudé RCU_READ_LOCK_GUARD();
23028d7f2e76SPhilippe Mathieu-Daudé ram_addr = xen_ram_addr_from_mapcache(ptr);
2303596ccccdSEdgar E. Iglesias if (ram_addr == RAM_ADDR_INVALID) {
2304596ccccdSEdgar E. Iglesias return NULL;
2305596ccccdSEdgar E. Iglesias }
2306596ccccdSEdgar E. Iglesias
23078d7f2e76SPhilippe Mathieu-Daudé block = qemu_get_ram_block(ram_addr);
23088d7f2e76SPhilippe Mathieu-Daudé if (block) {
23098d7f2e76SPhilippe Mathieu-Daudé *offset = ram_addr - block->offset;
23108d7f2e76SPhilippe Mathieu-Daudé }
23118d7f2e76SPhilippe Mathieu-Daudé return block;
23128d7f2e76SPhilippe Mathieu-Daudé }
23138d7f2e76SPhilippe Mathieu-Daudé
23148d7f2e76SPhilippe Mathieu-Daudé RCU_READ_LOCK_GUARD();
23158d7f2e76SPhilippe Mathieu-Daudé block = qatomic_rcu_read(&ram_list.mru_block);
23168d7f2e76SPhilippe Mathieu-Daudé if (block && block->host && host - block->host < block->max_length) {
23178d7f2e76SPhilippe Mathieu-Daudé goto found;
23188d7f2e76SPhilippe Mathieu-Daudé }
23198d7f2e76SPhilippe Mathieu-Daudé
23208d7f2e76SPhilippe Mathieu-Daudé RAMBLOCK_FOREACH(block) {
23218d7f2e76SPhilippe Mathieu-Daudé /* This case append when the block is not mapped. */
23228d7f2e76SPhilippe Mathieu-Daudé if (block->host == NULL) {
23238d7f2e76SPhilippe Mathieu-Daudé continue;
23248d7f2e76SPhilippe Mathieu-Daudé }
23258d7f2e76SPhilippe Mathieu-Daudé if (host - block->host < block->max_length) {
23268d7f2e76SPhilippe Mathieu-Daudé goto found;
23278d7f2e76SPhilippe Mathieu-Daudé }
23288d7f2e76SPhilippe Mathieu-Daudé }
23298d7f2e76SPhilippe Mathieu-Daudé
23308d7f2e76SPhilippe Mathieu-Daudé return NULL;
23318d7f2e76SPhilippe Mathieu-Daudé
23328d7f2e76SPhilippe Mathieu-Daudé found:
23338d7f2e76SPhilippe Mathieu-Daudé *offset = (host - block->host);
23348d7f2e76SPhilippe Mathieu-Daudé if (round_offset) {
23358d7f2e76SPhilippe Mathieu-Daudé *offset &= TARGET_PAGE_MASK;
23368d7f2e76SPhilippe Mathieu-Daudé }
23378d7f2e76SPhilippe Mathieu-Daudé return block;
23388d7f2e76SPhilippe Mathieu-Daudé }
23398d7f2e76SPhilippe Mathieu-Daudé
23408d7f2e76SPhilippe Mathieu-Daudé /*
23418d7f2e76SPhilippe Mathieu-Daudé * Finds the named RAMBlock
23428d7f2e76SPhilippe Mathieu-Daudé *
23438d7f2e76SPhilippe Mathieu-Daudé * name: The name of RAMBlock to find
23448d7f2e76SPhilippe Mathieu-Daudé *
23458d7f2e76SPhilippe Mathieu-Daudé * Returns: RAMBlock (or NULL if not found)
23468d7f2e76SPhilippe Mathieu-Daudé */
qemu_ram_block_by_name(const char * name)23478d7f2e76SPhilippe Mathieu-Daudé RAMBlock *qemu_ram_block_by_name(const char *name)
23488d7f2e76SPhilippe Mathieu-Daudé {
23498d7f2e76SPhilippe Mathieu-Daudé RAMBlock *block;
23508d7f2e76SPhilippe Mathieu-Daudé
23518d7f2e76SPhilippe Mathieu-Daudé RAMBLOCK_FOREACH(block) {
23528d7f2e76SPhilippe Mathieu-Daudé if (!strcmp(name, block->idstr)) {
23538d7f2e76SPhilippe Mathieu-Daudé return block;
23548d7f2e76SPhilippe Mathieu-Daudé }
23558d7f2e76SPhilippe Mathieu-Daudé }
23568d7f2e76SPhilippe Mathieu-Daudé
23578d7f2e76SPhilippe Mathieu-Daudé return NULL;
23588d7f2e76SPhilippe Mathieu-Daudé }
23598d7f2e76SPhilippe Mathieu-Daudé
23608d7f2e76SPhilippe Mathieu-Daudé /*
23618d7f2e76SPhilippe Mathieu-Daudé * Some of the system routines need to translate from a host pointer
23628d7f2e76SPhilippe Mathieu-Daudé * (typically a TLB entry) back to a ram offset.
23638d7f2e76SPhilippe Mathieu-Daudé */
qemu_ram_addr_from_host(void * ptr)23648d7f2e76SPhilippe Mathieu-Daudé ram_addr_t qemu_ram_addr_from_host(void *ptr)
23658d7f2e76SPhilippe Mathieu-Daudé {
23668d7f2e76SPhilippe Mathieu-Daudé RAMBlock *block;
23678d7f2e76SPhilippe Mathieu-Daudé ram_addr_t offset;
23688d7f2e76SPhilippe Mathieu-Daudé
23698d7f2e76SPhilippe Mathieu-Daudé block = qemu_ram_block_from_host(ptr, false, &offset);
23708d7f2e76SPhilippe Mathieu-Daudé if (!block) {
23718d7f2e76SPhilippe Mathieu-Daudé return RAM_ADDR_INVALID;
23728d7f2e76SPhilippe Mathieu-Daudé }
23738d7f2e76SPhilippe Mathieu-Daudé
23748d7f2e76SPhilippe Mathieu-Daudé return block->offset + offset;
23758d7f2e76SPhilippe Mathieu-Daudé }
23768d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_addr_from_host_nofail(void * ptr)23778d7f2e76SPhilippe Mathieu-Daudé ram_addr_t qemu_ram_addr_from_host_nofail(void *ptr)
23788d7f2e76SPhilippe Mathieu-Daudé {
23798d7f2e76SPhilippe Mathieu-Daudé ram_addr_t ram_addr;
23808d7f2e76SPhilippe Mathieu-Daudé
23818d7f2e76SPhilippe Mathieu-Daudé ram_addr = qemu_ram_addr_from_host(ptr);
23828d7f2e76SPhilippe Mathieu-Daudé if (ram_addr == RAM_ADDR_INVALID) {
23838d7f2e76SPhilippe Mathieu-Daudé error_report("Bad ram pointer %p", ptr);
23848d7f2e76SPhilippe Mathieu-Daudé abort();
23858d7f2e76SPhilippe Mathieu-Daudé }
23868d7f2e76SPhilippe Mathieu-Daudé return ram_addr;
23878d7f2e76SPhilippe Mathieu-Daudé }
23888d7f2e76SPhilippe Mathieu-Daudé
23898d7f2e76SPhilippe Mathieu-Daudé static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
23908d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs, void *buf, hwaddr len);
23918d7f2e76SPhilippe Mathieu-Daudé static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
23928d7f2e76SPhilippe Mathieu-Daudé const void *buf, hwaddr len);
23938d7f2e76SPhilippe Mathieu-Daudé static bool flatview_access_valid(FlatView *fv, hwaddr addr, hwaddr len,
23948d7f2e76SPhilippe Mathieu-Daudé bool is_write, MemTxAttrs attrs);
23958d7f2e76SPhilippe Mathieu-Daudé
subpage_read(void * opaque,hwaddr addr,uint64_t * data,unsigned len,MemTxAttrs attrs)23968d7f2e76SPhilippe Mathieu-Daudé static MemTxResult subpage_read(void *opaque, hwaddr addr, uint64_t *data,
23978d7f2e76SPhilippe Mathieu-Daudé unsigned len, MemTxAttrs attrs)
23988d7f2e76SPhilippe Mathieu-Daudé {
23998d7f2e76SPhilippe Mathieu-Daudé subpage_t *subpage = opaque;
24008d7f2e76SPhilippe Mathieu-Daudé uint8_t buf[8];
24018d7f2e76SPhilippe Mathieu-Daudé MemTxResult res;
24028d7f2e76SPhilippe Mathieu-Daudé
24038d7f2e76SPhilippe Mathieu-Daudé #if defined(DEBUG_SUBPAGE)
24048d7f2e76SPhilippe Mathieu-Daudé printf("%s: subpage %p len %u addr " HWADDR_FMT_plx "\n", __func__,
24058d7f2e76SPhilippe Mathieu-Daudé subpage, len, addr);
24068d7f2e76SPhilippe Mathieu-Daudé #endif
24078d7f2e76SPhilippe Mathieu-Daudé res = flatview_read(subpage->fv, addr + subpage->base, attrs, buf, len);
24088d7f2e76SPhilippe Mathieu-Daudé if (res) {
24098d7f2e76SPhilippe Mathieu-Daudé return res;
24108d7f2e76SPhilippe Mathieu-Daudé }
24118d7f2e76SPhilippe Mathieu-Daudé *data = ldn_p(buf, len);
24128d7f2e76SPhilippe Mathieu-Daudé return MEMTX_OK;
24138d7f2e76SPhilippe Mathieu-Daudé }
24148d7f2e76SPhilippe Mathieu-Daudé
subpage_write(void * opaque,hwaddr addr,uint64_t value,unsigned len,MemTxAttrs attrs)24158d7f2e76SPhilippe Mathieu-Daudé static MemTxResult subpage_write(void *opaque, hwaddr addr,
24168d7f2e76SPhilippe Mathieu-Daudé uint64_t value, unsigned len, MemTxAttrs attrs)
24178d7f2e76SPhilippe Mathieu-Daudé {
24188d7f2e76SPhilippe Mathieu-Daudé subpage_t *subpage = opaque;
24198d7f2e76SPhilippe Mathieu-Daudé uint8_t buf[8];
24208d7f2e76SPhilippe Mathieu-Daudé
24218d7f2e76SPhilippe Mathieu-Daudé #if defined(DEBUG_SUBPAGE)
24228d7f2e76SPhilippe Mathieu-Daudé printf("%s: subpage %p len %u addr " HWADDR_FMT_plx
24238d7f2e76SPhilippe Mathieu-Daudé " value %"PRIx64"\n",
24248d7f2e76SPhilippe Mathieu-Daudé __func__, subpage, len, addr, value);
24258d7f2e76SPhilippe Mathieu-Daudé #endif
24268d7f2e76SPhilippe Mathieu-Daudé stn_p(buf, len, value);
24278d7f2e76SPhilippe Mathieu-Daudé return flatview_write(subpage->fv, addr + subpage->base, attrs, buf, len);
24288d7f2e76SPhilippe Mathieu-Daudé }
24298d7f2e76SPhilippe Mathieu-Daudé
subpage_accepts(void * opaque,hwaddr addr,unsigned len,bool is_write,MemTxAttrs attrs)24308d7f2e76SPhilippe Mathieu-Daudé static bool subpage_accepts(void *opaque, hwaddr addr,
24318d7f2e76SPhilippe Mathieu-Daudé unsigned len, bool is_write,
24328d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs)
24338d7f2e76SPhilippe Mathieu-Daudé {
24348d7f2e76SPhilippe Mathieu-Daudé subpage_t *subpage = opaque;
24358d7f2e76SPhilippe Mathieu-Daudé #if defined(DEBUG_SUBPAGE)
24368d7f2e76SPhilippe Mathieu-Daudé printf("%s: subpage %p %c len %u addr " HWADDR_FMT_plx "\n",
24378d7f2e76SPhilippe Mathieu-Daudé __func__, subpage, is_write ? 'w' : 'r', len, addr);
24388d7f2e76SPhilippe Mathieu-Daudé #endif
24398d7f2e76SPhilippe Mathieu-Daudé
24408d7f2e76SPhilippe Mathieu-Daudé return flatview_access_valid(subpage->fv, addr + subpage->base,
24418d7f2e76SPhilippe Mathieu-Daudé len, is_write, attrs);
24428d7f2e76SPhilippe Mathieu-Daudé }
24438d7f2e76SPhilippe Mathieu-Daudé
24448d7f2e76SPhilippe Mathieu-Daudé static const MemoryRegionOps subpage_ops = {
24458d7f2e76SPhilippe Mathieu-Daudé .read_with_attrs = subpage_read,
24468d7f2e76SPhilippe Mathieu-Daudé .write_with_attrs = subpage_write,
24478d7f2e76SPhilippe Mathieu-Daudé .impl.min_access_size = 1,
24488d7f2e76SPhilippe Mathieu-Daudé .impl.max_access_size = 8,
24498d7f2e76SPhilippe Mathieu-Daudé .valid.min_access_size = 1,
24508d7f2e76SPhilippe Mathieu-Daudé .valid.max_access_size = 8,
24518d7f2e76SPhilippe Mathieu-Daudé .valid.accepts = subpage_accepts,
24528d7f2e76SPhilippe Mathieu-Daudé .endianness = DEVICE_NATIVE_ENDIAN,
24538d7f2e76SPhilippe Mathieu-Daudé };
24548d7f2e76SPhilippe Mathieu-Daudé
subpage_register(subpage_t * mmio,uint32_t start,uint32_t end,uint16_t section)24558d7f2e76SPhilippe Mathieu-Daudé static int subpage_register(subpage_t *mmio, uint32_t start, uint32_t end,
24568d7f2e76SPhilippe Mathieu-Daudé uint16_t section)
24578d7f2e76SPhilippe Mathieu-Daudé {
24588d7f2e76SPhilippe Mathieu-Daudé int idx, eidx;
24598d7f2e76SPhilippe Mathieu-Daudé
24608d7f2e76SPhilippe Mathieu-Daudé if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
24618d7f2e76SPhilippe Mathieu-Daudé return -1;
24628d7f2e76SPhilippe Mathieu-Daudé idx = SUBPAGE_IDX(start);
24638d7f2e76SPhilippe Mathieu-Daudé eidx = SUBPAGE_IDX(end);
24648d7f2e76SPhilippe Mathieu-Daudé #if defined(DEBUG_SUBPAGE)
24658d7f2e76SPhilippe Mathieu-Daudé printf("%s: %p start %08x end %08x idx %08x eidx %08x section %d\n",
24668d7f2e76SPhilippe Mathieu-Daudé __func__, mmio, start, end, idx, eidx, section);
24678d7f2e76SPhilippe Mathieu-Daudé #endif
24688d7f2e76SPhilippe Mathieu-Daudé for (; idx <= eidx; idx++) {
24698d7f2e76SPhilippe Mathieu-Daudé mmio->sub_section[idx] = section;
24708d7f2e76SPhilippe Mathieu-Daudé }
24718d7f2e76SPhilippe Mathieu-Daudé
24728d7f2e76SPhilippe Mathieu-Daudé return 0;
24738d7f2e76SPhilippe Mathieu-Daudé }
24748d7f2e76SPhilippe Mathieu-Daudé
subpage_init(FlatView * fv,hwaddr base)24758d7f2e76SPhilippe Mathieu-Daudé static subpage_t *subpage_init(FlatView *fv, hwaddr base)
24768d7f2e76SPhilippe Mathieu-Daudé {
24778d7f2e76SPhilippe Mathieu-Daudé subpage_t *mmio;
24788d7f2e76SPhilippe Mathieu-Daudé
24798d7f2e76SPhilippe Mathieu-Daudé /* mmio->sub_section is set to PHYS_SECTION_UNASSIGNED with g_malloc0 */
24808d7f2e76SPhilippe Mathieu-Daudé mmio = g_malloc0(sizeof(subpage_t) + TARGET_PAGE_SIZE * sizeof(uint16_t));
24818d7f2e76SPhilippe Mathieu-Daudé mmio->fv = fv;
24828d7f2e76SPhilippe Mathieu-Daudé mmio->base = base;
24838d7f2e76SPhilippe Mathieu-Daudé memory_region_init_io(&mmio->iomem, NULL, &subpage_ops, mmio,
24848d7f2e76SPhilippe Mathieu-Daudé NULL, TARGET_PAGE_SIZE);
24858d7f2e76SPhilippe Mathieu-Daudé mmio->iomem.subpage = true;
24868d7f2e76SPhilippe Mathieu-Daudé #if defined(DEBUG_SUBPAGE)
24878d7f2e76SPhilippe Mathieu-Daudé printf("%s: %p base " HWADDR_FMT_plx " len %08x\n", __func__,
24888d7f2e76SPhilippe Mathieu-Daudé mmio, base, TARGET_PAGE_SIZE);
24898d7f2e76SPhilippe Mathieu-Daudé #endif
24908d7f2e76SPhilippe Mathieu-Daudé
24918d7f2e76SPhilippe Mathieu-Daudé return mmio;
24928d7f2e76SPhilippe Mathieu-Daudé }
24938d7f2e76SPhilippe Mathieu-Daudé
dummy_section(PhysPageMap * map,FlatView * fv,MemoryRegion * mr)24948d7f2e76SPhilippe Mathieu-Daudé static uint16_t dummy_section(PhysPageMap *map, FlatView *fv, MemoryRegion *mr)
24958d7f2e76SPhilippe Mathieu-Daudé {
24968d7f2e76SPhilippe Mathieu-Daudé assert(fv);
24978d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection section = {
24988d7f2e76SPhilippe Mathieu-Daudé .fv = fv,
24998d7f2e76SPhilippe Mathieu-Daudé .mr = mr,
25008d7f2e76SPhilippe Mathieu-Daudé .offset_within_address_space = 0,
25018d7f2e76SPhilippe Mathieu-Daudé .offset_within_region = 0,
25028d7f2e76SPhilippe Mathieu-Daudé .size = int128_2_64(),
25038d7f2e76SPhilippe Mathieu-Daudé };
25048d7f2e76SPhilippe Mathieu-Daudé
25058d7f2e76SPhilippe Mathieu-Daudé return phys_section_add(map, §ion);
25068d7f2e76SPhilippe Mathieu-Daudé }
25078d7f2e76SPhilippe Mathieu-Daudé
iotlb_to_section(CPUState * cpu,hwaddr index,MemTxAttrs attrs)25088d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *iotlb_to_section(CPUState *cpu,
25098d7f2e76SPhilippe Mathieu-Daudé hwaddr index, MemTxAttrs attrs)
25108d7f2e76SPhilippe Mathieu-Daudé {
25118d7f2e76SPhilippe Mathieu-Daudé int asidx = cpu_asidx_from_attrs(cpu, attrs);
25128d7f2e76SPhilippe Mathieu-Daudé CPUAddressSpace *cpuas = &cpu->cpu_ases[asidx];
25138d7f2e76SPhilippe Mathieu-Daudé AddressSpaceDispatch *d = cpuas->memory_dispatch;
25148d7f2e76SPhilippe Mathieu-Daudé int section_index = index & ~TARGET_PAGE_MASK;
25158d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *ret;
25168d7f2e76SPhilippe Mathieu-Daudé
25178d7f2e76SPhilippe Mathieu-Daudé assert(section_index < d->map.sections_nb);
25188d7f2e76SPhilippe Mathieu-Daudé ret = d->map.sections + section_index;
25198d7f2e76SPhilippe Mathieu-Daudé assert(ret->mr);
25208d7f2e76SPhilippe Mathieu-Daudé assert(ret->mr->ops);
25218d7f2e76SPhilippe Mathieu-Daudé
25228d7f2e76SPhilippe Mathieu-Daudé return ret;
25238d7f2e76SPhilippe Mathieu-Daudé }
25248d7f2e76SPhilippe Mathieu-Daudé
io_mem_init(void)25258d7f2e76SPhilippe Mathieu-Daudé static void io_mem_init(void)
25268d7f2e76SPhilippe Mathieu-Daudé {
25278d7f2e76SPhilippe Mathieu-Daudé memory_region_init_io(&io_mem_unassigned, NULL, &unassigned_mem_ops, NULL,
25288d7f2e76SPhilippe Mathieu-Daudé NULL, UINT64_MAX);
25298d7f2e76SPhilippe Mathieu-Daudé }
25308d7f2e76SPhilippe Mathieu-Daudé
address_space_dispatch_new(FlatView * fv)25318d7f2e76SPhilippe Mathieu-Daudé AddressSpaceDispatch *address_space_dispatch_new(FlatView *fv)
25328d7f2e76SPhilippe Mathieu-Daudé {
25338d7f2e76SPhilippe Mathieu-Daudé AddressSpaceDispatch *d = g_new0(AddressSpaceDispatch, 1);
25348d7f2e76SPhilippe Mathieu-Daudé uint16_t n;
25358d7f2e76SPhilippe Mathieu-Daudé
25368d7f2e76SPhilippe Mathieu-Daudé n = dummy_section(&d->map, fv, &io_mem_unassigned);
25378d7f2e76SPhilippe Mathieu-Daudé assert(n == PHYS_SECTION_UNASSIGNED);
25388d7f2e76SPhilippe Mathieu-Daudé
25398d7f2e76SPhilippe Mathieu-Daudé d->phys_map = (PhysPageEntry) { .ptr = PHYS_MAP_NODE_NIL, .skip = 1 };
25408d7f2e76SPhilippe Mathieu-Daudé
25418d7f2e76SPhilippe Mathieu-Daudé return d;
25428d7f2e76SPhilippe Mathieu-Daudé }
25438d7f2e76SPhilippe Mathieu-Daudé
address_space_dispatch_free(AddressSpaceDispatch * d)25448d7f2e76SPhilippe Mathieu-Daudé void address_space_dispatch_free(AddressSpaceDispatch *d)
25458d7f2e76SPhilippe Mathieu-Daudé {
25468d7f2e76SPhilippe Mathieu-Daudé phys_sections_free(&d->map);
25478d7f2e76SPhilippe Mathieu-Daudé g_free(d);
25488d7f2e76SPhilippe Mathieu-Daudé }
25498d7f2e76SPhilippe Mathieu-Daudé
do_nothing(CPUState * cpu,run_on_cpu_data d)25508d7f2e76SPhilippe Mathieu-Daudé static void do_nothing(CPUState *cpu, run_on_cpu_data d)
25518d7f2e76SPhilippe Mathieu-Daudé {
25528d7f2e76SPhilippe Mathieu-Daudé }
25538d7f2e76SPhilippe Mathieu-Daudé
tcg_log_global_after_sync(MemoryListener * listener)25548d7f2e76SPhilippe Mathieu-Daudé static void tcg_log_global_after_sync(MemoryListener *listener)
25558d7f2e76SPhilippe Mathieu-Daudé {
25568d7f2e76SPhilippe Mathieu-Daudé CPUAddressSpace *cpuas;
25578d7f2e76SPhilippe Mathieu-Daudé
25588d7f2e76SPhilippe Mathieu-Daudé /* Wait for the CPU to end the current TB. This avoids the following
25598d7f2e76SPhilippe Mathieu-Daudé * incorrect race:
25608d7f2e76SPhilippe Mathieu-Daudé *
25618d7f2e76SPhilippe Mathieu-Daudé * vCPU migration
25628d7f2e76SPhilippe Mathieu-Daudé * ---------------------- -------------------------
25638d7f2e76SPhilippe Mathieu-Daudé * TLB check -> slow path
25648d7f2e76SPhilippe Mathieu-Daudé * notdirty_mem_write
25658d7f2e76SPhilippe Mathieu-Daudé * write to RAM
25668d7f2e76SPhilippe Mathieu-Daudé * mark dirty
25678d7f2e76SPhilippe Mathieu-Daudé * clear dirty flag
25688d7f2e76SPhilippe Mathieu-Daudé * TLB check -> fast path
25698d7f2e76SPhilippe Mathieu-Daudé * read memory
25708d7f2e76SPhilippe Mathieu-Daudé * write to RAM
25718d7f2e76SPhilippe Mathieu-Daudé *
25728d7f2e76SPhilippe Mathieu-Daudé * by pushing the migration thread's memory read after the vCPU thread has
25738d7f2e76SPhilippe Mathieu-Daudé * written the memory.
25748d7f2e76SPhilippe Mathieu-Daudé */
25758d7f2e76SPhilippe Mathieu-Daudé if (replay_mode == REPLAY_MODE_NONE) {
25768d7f2e76SPhilippe Mathieu-Daudé /*
25778d7f2e76SPhilippe Mathieu-Daudé * VGA can make calls to this function while updating the screen.
25788d7f2e76SPhilippe Mathieu-Daudé * In record/replay mode this causes a deadlock, because
25798d7f2e76SPhilippe Mathieu-Daudé * run_on_cpu waits for rr mutex. Therefore no races are possible
25808d7f2e76SPhilippe Mathieu-Daudé * in this case and no need for making run_on_cpu when
25818d7f2e76SPhilippe Mathieu-Daudé * record/replay is enabled.
25828d7f2e76SPhilippe Mathieu-Daudé */
25838d7f2e76SPhilippe Mathieu-Daudé cpuas = container_of(listener, CPUAddressSpace, tcg_as_listener);
25848d7f2e76SPhilippe Mathieu-Daudé run_on_cpu(cpuas->cpu, do_nothing, RUN_ON_CPU_NULL);
25858d7f2e76SPhilippe Mathieu-Daudé }
25868d7f2e76SPhilippe Mathieu-Daudé }
25878d7f2e76SPhilippe Mathieu-Daudé
tcg_commit_cpu(CPUState * cpu,run_on_cpu_data data)25888d7f2e76SPhilippe Mathieu-Daudé static void tcg_commit_cpu(CPUState *cpu, run_on_cpu_data data)
25898d7f2e76SPhilippe Mathieu-Daudé {
25908d7f2e76SPhilippe Mathieu-Daudé CPUAddressSpace *cpuas = data.host_ptr;
25918d7f2e76SPhilippe Mathieu-Daudé
25928d7f2e76SPhilippe Mathieu-Daudé cpuas->memory_dispatch = address_space_to_dispatch(cpuas->as);
25938d7f2e76SPhilippe Mathieu-Daudé tlb_flush(cpu);
25948d7f2e76SPhilippe Mathieu-Daudé }
25958d7f2e76SPhilippe Mathieu-Daudé
tcg_commit(MemoryListener * listener)25968d7f2e76SPhilippe Mathieu-Daudé static void tcg_commit(MemoryListener *listener)
25978d7f2e76SPhilippe Mathieu-Daudé {
25988d7f2e76SPhilippe Mathieu-Daudé CPUAddressSpace *cpuas;
25998d7f2e76SPhilippe Mathieu-Daudé CPUState *cpu;
26008d7f2e76SPhilippe Mathieu-Daudé
26018d7f2e76SPhilippe Mathieu-Daudé assert(tcg_enabled());
26028d7f2e76SPhilippe Mathieu-Daudé /* since each CPU stores ram addresses in its TLB cache, we must
26038d7f2e76SPhilippe Mathieu-Daudé reset the modified entries */
26048d7f2e76SPhilippe Mathieu-Daudé cpuas = container_of(listener, CPUAddressSpace, tcg_as_listener);
26058d7f2e76SPhilippe Mathieu-Daudé cpu = cpuas->cpu;
26068d7f2e76SPhilippe Mathieu-Daudé
26078d7f2e76SPhilippe Mathieu-Daudé /*
26088d7f2e76SPhilippe Mathieu-Daudé * Defer changes to as->memory_dispatch until the cpu is quiescent.
26098d7f2e76SPhilippe Mathieu-Daudé * Otherwise we race between (1) other cpu threads and (2) ongoing
26108d7f2e76SPhilippe Mathieu-Daudé * i/o for the current cpu thread, with data cached by mmu_lookup().
26118d7f2e76SPhilippe Mathieu-Daudé *
26128d7f2e76SPhilippe Mathieu-Daudé * In addition, queueing the work function will kick the cpu back to
26138d7f2e76SPhilippe Mathieu-Daudé * the main loop, which will end the RCU critical section and reclaim
26148d7f2e76SPhilippe Mathieu-Daudé * the memory data structures.
26158d7f2e76SPhilippe Mathieu-Daudé *
26168d7f2e76SPhilippe Mathieu-Daudé * That said, the listener is also called during realize, before
26178d7f2e76SPhilippe Mathieu-Daudé * all of the tcg machinery for run-on is initialized: thus halt_cond.
26188d7f2e76SPhilippe Mathieu-Daudé */
26198d7f2e76SPhilippe Mathieu-Daudé if (cpu->halt_cond) {
26208d7f2e76SPhilippe Mathieu-Daudé async_run_on_cpu(cpu, tcg_commit_cpu, RUN_ON_CPU_HOST_PTR(cpuas));
26218d7f2e76SPhilippe Mathieu-Daudé } else {
26228d7f2e76SPhilippe Mathieu-Daudé tcg_commit_cpu(cpu, RUN_ON_CPU_HOST_PTR(cpuas));
26238d7f2e76SPhilippe Mathieu-Daudé }
26248d7f2e76SPhilippe Mathieu-Daudé }
26258d7f2e76SPhilippe Mathieu-Daudé
memory_map_init(void)26268d7f2e76SPhilippe Mathieu-Daudé static void memory_map_init(void)
26278d7f2e76SPhilippe Mathieu-Daudé {
26288d7f2e76SPhilippe Mathieu-Daudé system_memory = g_malloc(sizeof(*system_memory));
26298d7f2e76SPhilippe Mathieu-Daudé
26308d7f2e76SPhilippe Mathieu-Daudé memory_region_init(system_memory, NULL, "system", UINT64_MAX);
26318d7f2e76SPhilippe Mathieu-Daudé address_space_init(&address_space_memory, system_memory, "memory");
26328d7f2e76SPhilippe Mathieu-Daudé
26338d7f2e76SPhilippe Mathieu-Daudé system_io = g_malloc(sizeof(*system_io));
26348d7f2e76SPhilippe Mathieu-Daudé memory_region_init_io(system_io, NULL, &unassigned_io_ops, NULL, "io",
26358d7f2e76SPhilippe Mathieu-Daudé 65536);
26368d7f2e76SPhilippe Mathieu-Daudé address_space_init(&address_space_io, system_io, "I/O");
26378d7f2e76SPhilippe Mathieu-Daudé }
26388d7f2e76SPhilippe Mathieu-Daudé
get_system_memory(void)26398d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *get_system_memory(void)
26408d7f2e76SPhilippe Mathieu-Daudé {
26418d7f2e76SPhilippe Mathieu-Daudé return system_memory;
26428d7f2e76SPhilippe Mathieu-Daudé }
26438d7f2e76SPhilippe Mathieu-Daudé
get_system_io(void)26448d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *get_system_io(void)
26458d7f2e76SPhilippe Mathieu-Daudé {
26468d7f2e76SPhilippe Mathieu-Daudé return system_io;
26478d7f2e76SPhilippe Mathieu-Daudé }
26488d7f2e76SPhilippe Mathieu-Daudé
invalidate_and_set_dirty(MemoryRegion * mr,hwaddr addr,hwaddr length)26498d7f2e76SPhilippe Mathieu-Daudé static void invalidate_and_set_dirty(MemoryRegion *mr, hwaddr addr,
26508d7f2e76SPhilippe Mathieu-Daudé hwaddr length)
26518d7f2e76SPhilippe Mathieu-Daudé {
26528d7f2e76SPhilippe Mathieu-Daudé uint8_t dirty_log_mask = memory_region_get_dirty_log_mask(mr);
265373188068SPeter Maydell ram_addr_t ramaddr = memory_region_get_ram_addr(mr);
265473188068SPeter Maydell
265573188068SPeter Maydell /* We know we're only called for RAM MemoryRegions */
265673188068SPeter Maydell assert(ramaddr != RAM_ADDR_INVALID);
265773188068SPeter Maydell addr += ramaddr;
26588d7f2e76SPhilippe Mathieu-Daudé
26598d7f2e76SPhilippe Mathieu-Daudé /* No early return if dirty_log_mask is or becomes 0, because
26608d7f2e76SPhilippe Mathieu-Daudé * cpu_physical_memory_set_dirty_range will still call
26618d7f2e76SPhilippe Mathieu-Daudé * xen_modified_memory.
26628d7f2e76SPhilippe Mathieu-Daudé */
26638d7f2e76SPhilippe Mathieu-Daudé if (dirty_log_mask) {
26648d7f2e76SPhilippe Mathieu-Daudé dirty_log_mask =
26658d7f2e76SPhilippe Mathieu-Daudé cpu_physical_memory_range_includes_clean(addr, length, dirty_log_mask);
26668d7f2e76SPhilippe Mathieu-Daudé }
26678d7f2e76SPhilippe Mathieu-Daudé if (dirty_log_mask & (1 << DIRTY_MEMORY_CODE)) {
26688d7f2e76SPhilippe Mathieu-Daudé assert(tcg_enabled());
26698d7f2e76SPhilippe Mathieu-Daudé tb_invalidate_phys_range(addr, addr + length - 1);
26708d7f2e76SPhilippe Mathieu-Daudé dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
26718d7f2e76SPhilippe Mathieu-Daudé }
26728d7f2e76SPhilippe Mathieu-Daudé cpu_physical_memory_set_dirty_range(addr, length, dirty_log_mask);
26738d7f2e76SPhilippe Mathieu-Daudé }
26748d7f2e76SPhilippe Mathieu-Daudé
memory_region_flush_rom_device(MemoryRegion * mr,hwaddr addr,hwaddr size)26758d7f2e76SPhilippe Mathieu-Daudé void memory_region_flush_rom_device(MemoryRegion *mr, hwaddr addr, hwaddr size)
26768d7f2e76SPhilippe Mathieu-Daudé {
26778d7f2e76SPhilippe Mathieu-Daudé /*
26788d7f2e76SPhilippe Mathieu-Daudé * In principle this function would work on other memory region types too,
26798d7f2e76SPhilippe Mathieu-Daudé * but the ROM device use case is the only one where this operation is
26808d7f2e76SPhilippe Mathieu-Daudé * necessary. Other memory regions should use the
26818d7f2e76SPhilippe Mathieu-Daudé * address_space_read/write() APIs.
26828d7f2e76SPhilippe Mathieu-Daudé */
26838d7f2e76SPhilippe Mathieu-Daudé assert(memory_region_is_romd(mr));
26848d7f2e76SPhilippe Mathieu-Daudé
26858d7f2e76SPhilippe Mathieu-Daudé invalidate_and_set_dirty(mr, addr, size);
26868d7f2e76SPhilippe Mathieu-Daudé }
26878d7f2e76SPhilippe Mathieu-Daudé
memory_access_size(MemoryRegion * mr,unsigned l,hwaddr addr)26888d7f2e76SPhilippe Mathieu-Daudé int memory_access_size(MemoryRegion *mr, unsigned l, hwaddr addr)
26898d7f2e76SPhilippe Mathieu-Daudé {
26908d7f2e76SPhilippe Mathieu-Daudé unsigned access_size_max = mr->ops->valid.max_access_size;
26918d7f2e76SPhilippe Mathieu-Daudé
26928d7f2e76SPhilippe Mathieu-Daudé /* Regions are assumed to support 1-4 byte accesses unless
26938d7f2e76SPhilippe Mathieu-Daudé otherwise specified. */
26948d7f2e76SPhilippe Mathieu-Daudé if (access_size_max == 0) {
26958d7f2e76SPhilippe Mathieu-Daudé access_size_max = 4;
26968d7f2e76SPhilippe Mathieu-Daudé }
26978d7f2e76SPhilippe Mathieu-Daudé
26988d7f2e76SPhilippe Mathieu-Daudé /* Bound the maximum access by the alignment of the address. */
26998d7f2e76SPhilippe Mathieu-Daudé if (!mr->ops->impl.unaligned) {
27008d7f2e76SPhilippe Mathieu-Daudé unsigned align_size_max = addr & -addr;
27018d7f2e76SPhilippe Mathieu-Daudé if (align_size_max != 0 && align_size_max < access_size_max) {
27028d7f2e76SPhilippe Mathieu-Daudé access_size_max = align_size_max;
27038d7f2e76SPhilippe Mathieu-Daudé }
27048d7f2e76SPhilippe Mathieu-Daudé }
27058d7f2e76SPhilippe Mathieu-Daudé
27068d7f2e76SPhilippe Mathieu-Daudé /* Don't attempt accesses larger than the maximum. */
27078d7f2e76SPhilippe Mathieu-Daudé if (l > access_size_max) {
27088d7f2e76SPhilippe Mathieu-Daudé l = access_size_max;
27098d7f2e76SPhilippe Mathieu-Daudé }
27108d7f2e76SPhilippe Mathieu-Daudé l = pow2floor(l);
27118d7f2e76SPhilippe Mathieu-Daudé
27128d7f2e76SPhilippe Mathieu-Daudé return l;
27138d7f2e76SPhilippe Mathieu-Daudé }
27148d7f2e76SPhilippe Mathieu-Daudé
prepare_mmio_access(MemoryRegion * mr)27158d7f2e76SPhilippe Mathieu-Daudé bool prepare_mmio_access(MemoryRegion *mr)
27168d7f2e76SPhilippe Mathieu-Daudé {
27178d7f2e76SPhilippe Mathieu-Daudé bool release_lock = false;
27188d7f2e76SPhilippe Mathieu-Daudé
2719195801d7SStefan Hajnoczi if (!bql_locked()) {
2720195801d7SStefan Hajnoczi bql_lock();
27218d7f2e76SPhilippe Mathieu-Daudé release_lock = true;
27228d7f2e76SPhilippe Mathieu-Daudé }
27238d7f2e76SPhilippe Mathieu-Daudé if (mr->flush_coalesced_mmio) {
27248d7f2e76SPhilippe Mathieu-Daudé qemu_flush_coalesced_mmio_buffer();
27258d7f2e76SPhilippe Mathieu-Daudé }
27268d7f2e76SPhilippe Mathieu-Daudé
27278d7f2e76SPhilippe Mathieu-Daudé return release_lock;
27288d7f2e76SPhilippe Mathieu-Daudé }
27298d7f2e76SPhilippe Mathieu-Daudé
27308d7f2e76SPhilippe Mathieu-Daudé /**
27318d7f2e76SPhilippe Mathieu-Daudé * flatview_access_allowed
27328d7f2e76SPhilippe Mathieu-Daudé * @mr: #MemoryRegion to be accessed
27338d7f2e76SPhilippe Mathieu-Daudé * @attrs: memory transaction attributes
27348d7f2e76SPhilippe Mathieu-Daudé * @addr: address within that memory region
27358d7f2e76SPhilippe Mathieu-Daudé * @len: the number of bytes to access
27368d7f2e76SPhilippe Mathieu-Daudé *
27378d7f2e76SPhilippe Mathieu-Daudé * Check if a memory transaction is allowed.
27388d7f2e76SPhilippe Mathieu-Daudé *
27398d7f2e76SPhilippe Mathieu-Daudé * Returns: true if transaction is allowed, false if denied.
27408d7f2e76SPhilippe Mathieu-Daudé */
flatview_access_allowed(MemoryRegion * mr,MemTxAttrs attrs,hwaddr addr,hwaddr len)27418d7f2e76SPhilippe Mathieu-Daudé static bool flatview_access_allowed(MemoryRegion *mr, MemTxAttrs attrs,
27428d7f2e76SPhilippe Mathieu-Daudé hwaddr addr, hwaddr len)
27438d7f2e76SPhilippe Mathieu-Daudé {
27448d7f2e76SPhilippe Mathieu-Daudé if (likely(!attrs.memory)) {
27458d7f2e76SPhilippe Mathieu-Daudé return true;
27468d7f2e76SPhilippe Mathieu-Daudé }
27478d7f2e76SPhilippe Mathieu-Daudé if (memory_region_is_ram(mr)) {
27488d7f2e76SPhilippe Mathieu-Daudé return true;
27498d7f2e76SPhilippe Mathieu-Daudé }
27508d7f2e76SPhilippe Mathieu-Daudé qemu_log_mask(LOG_GUEST_ERROR,
27518d7f2e76SPhilippe Mathieu-Daudé "Invalid access to non-RAM device at "
27528d7f2e76SPhilippe Mathieu-Daudé "addr 0x%" HWADDR_PRIX ", size %" HWADDR_PRIu ", "
27538d7f2e76SPhilippe Mathieu-Daudé "region '%s'\n", addr, len, memory_region_name(mr));
27548d7f2e76SPhilippe Mathieu-Daudé return false;
27558d7f2e76SPhilippe Mathieu-Daudé }
27568d7f2e76SPhilippe Mathieu-Daudé
flatview_write_continue_step(MemTxAttrs attrs,const uint8_t * buf,hwaddr len,hwaddr mr_addr,hwaddr * l,MemoryRegion * mr)2757e7927d33SJonathan Cameron static MemTxResult flatview_write_continue_step(MemTxAttrs attrs,
2758e7927d33SJonathan Cameron const uint8_t *buf,
2759e7927d33SJonathan Cameron hwaddr len, hwaddr mr_addr,
2760e7927d33SJonathan Cameron hwaddr *l, MemoryRegion *mr)
2761e7927d33SJonathan Cameron {
2762e7927d33SJonathan Cameron if (!flatview_access_allowed(mr, attrs, mr_addr, *l)) {
2763e7927d33SJonathan Cameron return MEMTX_ACCESS_ERROR;
2764e7927d33SJonathan Cameron }
2765e7927d33SJonathan Cameron
2766e7927d33SJonathan Cameron if (!memory_access_is_direct(mr, true)) {
2767e7927d33SJonathan Cameron uint64_t val;
2768e7927d33SJonathan Cameron MemTxResult result;
2769e7927d33SJonathan Cameron bool release_lock = prepare_mmio_access(mr);
2770e7927d33SJonathan Cameron
2771e7927d33SJonathan Cameron *l = memory_access_size(mr, *l, mr_addr);
2772e7927d33SJonathan Cameron /*
2773e7927d33SJonathan Cameron * XXX: could force current_cpu to NULL to avoid
2774e7927d33SJonathan Cameron * potential bugs
2775e7927d33SJonathan Cameron */
2776e7927d33SJonathan Cameron
2777e7927d33SJonathan Cameron /*
2778e7927d33SJonathan Cameron * Assure Coverity (and ourselves) that we are not going to OVERRUN
2779e7927d33SJonathan Cameron * the buffer by following ldn_he_p().
2780e7927d33SJonathan Cameron */
2781e7927d33SJonathan Cameron #ifdef QEMU_STATIC_ANALYSIS
2782e7927d33SJonathan Cameron assert((*l == 1 && len >= 1) ||
2783e7927d33SJonathan Cameron (*l == 2 && len >= 2) ||
2784e7927d33SJonathan Cameron (*l == 4 && len >= 4) ||
2785e7927d33SJonathan Cameron (*l == 8 && len >= 8));
2786e7927d33SJonathan Cameron #endif
2787e7927d33SJonathan Cameron val = ldn_he_p(buf, *l);
2788e7927d33SJonathan Cameron result = memory_region_dispatch_write(mr, mr_addr, val,
2789e7927d33SJonathan Cameron size_memop(*l), attrs);
2790e7927d33SJonathan Cameron if (release_lock) {
2791e7927d33SJonathan Cameron bql_unlock();
2792e7927d33SJonathan Cameron }
2793e7927d33SJonathan Cameron
2794e7927d33SJonathan Cameron return result;
2795e7927d33SJonathan Cameron } else {
2796e7927d33SJonathan Cameron /* RAM case */
2797e7927d33SJonathan Cameron uint8_t *ram_ptr = qemu_ram_ptr_length(mr->ram_block, mr_addr, l,
27985a5585f4SEdgar E. Iglesias false, true);
2799e7927d33SJonathan Cameron
2800e7927d33SJonathan Cameron memmove(ram_ptr, buf, *l);
2801e7927d33SJonathan Cameron invalidate_and_set_dirty(mr, mr_addr, *l);
2802e7927d33SJonathan Cameron
2803e7927d33SJonathan Cameron return MEMTX_OK;
2804e7927d33SJonathan Cameron }
2805e7927d33SJonathan Cameron }
2806e7927d33SJonathan Cameron
28078d7f2e76SPhilippe Mathieu-Daudé /* Called within RCU critical section. */
flatview_write_continue(FlatView * fv,hwaddr addr,MemTxAttrs attrs,const void * ptr,hwaddr len,hwaddr mr_addr,hwaddr l,MemoryRegion * mr)28088d7f2e76SPhilippe Mathieu-Daudé static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
28098d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs,
28108d7f2e76SPhilippe Mathieu-Daudé const void *ptr,
28114c7c8563SJonathan Cameron hwaddr len, hwaddr mr_addr,
28128d7f2e76SPhilippe Mathieu-Daudé hwaddr l, MemoryRegion *mr)
28138d7f2e76SPhilippe Mathieu-Daudé {
28148d7f2e76SPhilippe Mathieu-Daudé MemTxResult result = MEMTX_OK;
28158d7f2e76SPhilippe Mathieu-Daudé const uint8_t *buf = ptr;
28168d7f2e76SPhilippe Mathieu-Daudé
28178d7f2e76SPhilippe Mathieu-Daudé for (;;) {
2818e7927d33SJonathan Cameron result |= flatview_write_continue_step(attrs, buf, len, mr_addr, &l,
2819e7927d33SJonathan Cameron mr);
28208d7f2e76SPhilippe Mathieu-Daudé
28218d7f2e76SPhilippe Mathieu-Daudé len -= l;
28228d7f2e76SPhilippe Mathieu-Daudé buf += l;
28238d7f2e76SPhilippe Mathieu-Daudé addr += l;
28248d7f2e76SPhilippe Mathieu-Daudé
28258d7f2e76SPhilippe Mathieu-Daudé if (!len) {
28268d7f2e76SPhilippe Mathieu-Daudé break;
28278d7f2e76SPhilippe Mathieu-Daudé }
28288d7f2e76SPhilippe Mathieu-Daudé
28298d7f2e76SPhilippe Mathieu-Daudé l = len;
28304c7c8563SJonathan Cameron mr = flatview_translate(fv, addr, &mr_addr, &l, true, attrs);
28318d7f2e76SPhilippe Mathieu-Daudé }
28328d7f2e76SPhilippe Mathieu-Daudé
28338d7f2e76SPhilippe Mathieu-Daudé return result;
28348d7f2e76SPhilippe Mathieu-Daudé }
28358d7f2e76SPhilippe Mathieu-Daudé
28368d7f2e76SPhilippe Mathieu-Daudé /* Called from RCU critical section. */
flatview_write(FlatView * fv,hwaddr addr,MemTxAttrs attrs,const void * buf,hwaddr len)28378d7f2e76SPhilippe Mathieu-Daudé static MemTxResult flatview_write(FlatView *fv, hwaddr addr, MemTxAttrs attrs,
28388d7f2e76SPhilippe Mathieu-Daudé const void *buf, hwaddr len)
28398d7f2e76SPhilippe Mathieu-Daudé {
28408d7f2e76SPhilippe Mathieu-Daudé hwaddr l;
28414c7c8563SJonathan Cameron hwaddr mr_addr;
28428d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr;
28438d7f2e76SPhilippe Mathieu-Daudé
28448d7f2e76SPhilippe Mathieu-Daudé l = len;
28454c7c8563SJonathan Cameron mr = flatview_translate(fv, addr, &mr_addr, &l, true, attrs);
28468d7f2e76SPhilippe Mathieu-Daudé if (!flatview_access_allowed(mr, attrs, addr, len)) {
28478d7f2e76SPhilippe Mathieu-Daudé return MEMTX_ACCESS_ERROR;
28488d7f2e76SPhilippe Mathieu-Daudé }
28498d7f2e76SPhilippe Mathieu-Daudé return flatview_write_continue(fv, addr, attrs, buf, len,
28504c7c8563SJonathan Cameron mr_addr, l, mr);
28518d7f2e76SPhilippe Mathieu-Daudé }
28528d7f2e76SPhilippe Mathieu-Daudé
flatview_read_continue_step(MemTxAttrs attrs,uint8_t * buf,hwaddr len,hwaddr mr_addr,hwaddr * l,MemoryRegion * mr)2853e7927d33SJonathan Cameron static MemTxResult flatview_read_continue_step(MemTxAttrs attrs, uint8_t *buf,
2854e7927d33SJonathan Cameron hwaddr len, hwaddr mr_addr,
2855e7927d33SJonathan Cameron hwaddr *l,
2856e7927d33SJonathan Cameron MemoryRegion *mr)
2857e7927d33SJonathan Cameron {
2858e7927d33SJonathan Cameron if (!flatview_access_allowed(mr, attrs, mr_addr, *l)) {
2859e7927d33SJonathan Cameron return MEMTX_ACCESS_ERROR;
2860e7927d33SJonathan Cameron }
2861e7927d33SJonathan Cameron
2862e7927d33SJonathan Cameron if (!memory_access_is_direct(mr, false)) {
2863e7927d33SJonathan Cameron /* I/O case */
2864e7927d33SJonathan Cameron uint64_t val;
2865e7927d33SJonathan Cameron MemTxResult result;
2866e7927d33SJonathan Cameron bool release_lock = prepare_mmio_access(mr);
2867e7927d33SJonathan Cameron
2868e7927d33SJonathan Cameron *l = memory_access_size(mr, *l, mr_addr);
2869e7927d33SJonathan Cameron result = memory_region_dispatch_read(mr, mr_addr, &val, size_memop(*l),
2870e7927d33SJonathan Cameron attrs);
2871e7927d33SJonathan Cameron
2872e7927d33SJonathan Cameron /*
2873e7927d33SJonathan Cameron * Assure Coverity (and ourselves) that we are not going to OVERRUN
2874e7927d33SJonathan Cameron * the buffer by following stn_he_p().
2875e7927d33SJonathan Cameron */
2876e7927d33SJonathan Cameron #ifdef QEMU_STATIC_ANALYSIS
2877e7927d33SJonathan Cameron assert((*l == 1 && len >= 1) ||
2878e7927d33SJonathan Cameron (*l == 2 && len >= 2) ||
2879e7927d33SJonathan Cameron (*l == 4 && len >= 4) ||
2880e7927d33SJonathan Cameron (*l == 8 && len >= 8));
2881e7927d33SJonathan Cameron #endif
2882e7927d33SJonathan Cameron stn_he_p(buf, *l, val);
2883e7927d33SJonathan Cameron
2884e7927d33SJonathan Cameron if (release_lock) {
2885e7927d33SJonathan Cameron bql_unlock();
2886e7927d33SJonathan Cameron }
2887e7927d33SJonathan Cameron return result;
2888e7927d33SJonathan Cameron } else {
2889e7927d33SJonathan Cameron /* RAM case */
2890e7927d33SJonathan Cameron uint8_t *ram_ptr = qemu_ram_ptr_length(mr->ram_block, mr_addr, l,
28915a5585f4SEdgar E. Iglesias false, false);
2892e7927d33SJonathan Cameron
2893e7927d33SJonathan Cameron memcpy(buf, ram_ptr, *l);
2894e7927d33SJonathan Cameron
2895e7927d33SJonathan Cameron return MEMTX_OK;
2896e7927d33SJonathan Cameron }
2897e7927d33SJonathan Cameron }
2898e7927d33SJonathan Cameron
28998d7f2e76SPhilippe Mathieu-Daudé /* Called within RCU critical section. */
flatview_read_continue(FlatView * fv,hwaddr addr,MemTxAttrs attrs,void * ptr,hwaddr len,hwaddr mr_addr,hwaddr l,MemoryRegion * mr)29008d7f2e76SPhilippe Mathieu-Daudé MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
29018d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs, void *ptr,
29024c7c8563SJonathan Cameron hwaddr len, hwaddr mr_addr, hwaddr l,
29038d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr)
29048d7f2e76SPhilippe Mathieu-Daudé {
29058d7f2e76SPhilippe Mathieu-Daudé MemTxResult result = MEMTX_OK;
29068d7f2e76SPhilippe Mathieu-Daudé uint8_t *buf = ptr;
29078d7f2e76SPhilippe Mathieu-Daudé
29088d7f2e76SPhilippe Mathieu-Daudé fuzz_dma_read_cb(addr, len, mr);
29098d7f2e76SPhilippe Mathieu-Daudé for (;;) {
2910e7927d33SJonathan Cameron result |= flatview_read_continue_step(attrs, buf, len, mr_addr, &l, mr);
29118d7f2e76SPhilippe Mathieu-Daudé
29128d7f2e76SPhilippe Mathieu-Daudé len -= l;
29138d7f2e76SPhilippe Mathieu-Daudé buf += l;
29148d7f2e76SPhilippe Mathieu-Daudé addr += l;
29158d7f2e76SPhilippe Mathieu-Daudé
29168d7f2e76SPhilippe Mathieu-Daudé if (!len) {
29178d7f2e76SPhilippe Mathieu-Daudé break;
29188d7f2e76SPhilippe Mathieu-Daudé }
29198d7f2e76SPhilippe Mathieu-Daudé
29208d7f2e76SPhilippe Mathieu-Daudé l = len;
29214c7c8563SJonathan Cameron mr = flatview_translate(fv, addr, &mr_addr, &l, false, attrs);
29228d7f2e76SPhilippe Mathieu-Daudé }
29238d7f2e76SPhilippe Mathieu-Daudé
29248d7f2e76SPhilippe Mathieu-Daudé return result;
29258d7f2e76SPhilippe Mathieu-Daudé }
29268d7f2e76SPhilippe Mathieu-Daudé
29278d7f2e76SPhilippe Mathieu-Daudé /* Called from RCU critical section. */
flatview_read(FlatView * fv,hwaddr addr,MemTxAttrs attrs,void * buf,hwaddr len)29288d7f2e76SPhilippe Mathieu-Daudé static MemTxResult flatview_read(FlatView *fv, hwaddr addr,
29298d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs, void *buf, hwaddr len)
29308d7f2e76SPhilippe Mathieu-Daudé {
29318d7f2e76SPhilippe Mathieu-Daudé hwaddr l;
29324c7c8563SJonathan Cameron hwaddr mr_addr;
29338d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr;
29348d7f2e76SPhilippe Mathieu-Daudé
29358d7f2e76SPhilippe Mathieu-Daudé l = len;
29364c7c8563SJonathan Cameron mr = flatview_translate(fv, addr, &mr_addr, &l, false, attrs);
29378d7f2e76SPhilippe Mathieu-Daudé if (!flatview_access_allowed(mr, attrs, addr, len)) {
29388d7f2e76SPhilippe Mathieu-Daudé return MEMTX_ACCESS_ERROR;
29398d7f2e76SPhilippe Mathieu-Daudé }
29408d7f2e76SPhilippe Mathieu-Daudé return flatview_read_continue(fv, addr, attrs, buf, len,
29414c7c8563SJonathan Cameron mr_addr, l, mr);
29428d7f2e76SPhilippe Mathieu-Daudé }
29438d7f2e76SPhilippe Mathieu-Daudé
address_space_read_full(AddressSpace * as,hwaddr addr,MemTxAttrs attrs,void * buf,hwaddr len)29448d7f2e76SPhilippe Mathieu-Daudé MemTxResult address_space_read_full(AddressSpace *as, hwaddr addr,
29458d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs, void *buf, hwaddr len)
29468d7f2e76SPhilippe Mathieu-Daudé {
29478d7f2e76SPhilippe Mathieu-Daudé MemTxResult result = MEMTX_OK;
29488d7f2e76SPhilippe Mathieu-Daudé FlatView *fv;
29498d7f2e76SPhilippe Mathieu-Daudé
29508d7f2e76SPhilippe Mathieu-Daudé if (len > 0) {
29518d7f2e76SPhilippe Mathieu-Daudé RCU_READ_LOCK_GUARD();
29528d7f2e76SPhilippe Mathieu-Daudé fv = address_space_to_flatview(as);
29538d7f2e76SPhilippe Mathieu-Daudé result = flatview_read(fv, addr, attrs, buf, len);
29548d7f2e76SPhilippe Mathieu-Daudé }
29558d7f2e76SPhilippe Mathieu-Daudé
29568d7f2e76SPhilippe Mathieu-Daudé return result;
29578d7f2e76SPhilippe Mathieu-Daudé }
29588d7f2e76SPhilippe Mathieu-Daudé
address_space_write(AddressSpace * as,hwaddr addr,MemTxAttrs attrs,const void * buf,hwaddr len)29598d7f2e76SPhilippe Mathieu-Daudé MemTxResult address_space_write(AddressSpace *as, hwaddr addr,
29608d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs,
29618d7f2e76SPhilippe Mathieu-Daudé const void *buf, hwaddr len)
29628d7f2e76SPhilippe Mathieu-Daudé {
29638d7f2e76SPhilippe Mathieu-Daudé MemTxResult result = MEMTX_OK;
29648d7f2e76SPhilippe Mathieu-Daudé FlatView *fv;
29658d7f2e76SPhilippe Mathieu-Daudé
29668d7f2e76SPhilippe Mathieu-Daudé if (len > 0) {
29678d7f2e76SPhilippe Mathieu-Daudé RCU_READ_LOCK_GUARD();
29688d7f2e76SPhilippe Mathieu-Daudé fv = address_space_to_flatview(as);
29698d7f2e76SPhilippe Mathieu-Daudé result = flatview_write(fv, addr, attrs, buf, len);
29708d7f2e76SPhilippe Mathieu-Daudé }
29718d7f2e76SPhilippe Mathieu-Daudé
29728d7f2e76SPhilippe Mathieu-Daudé return result;
29738d7f2e76SPhilippe Mathieu-Daudé }
29748d7f2e76SPhilippe Mathieu-Daudé
address_space_rw(AddressSpace * as,hwaddr addr,MemTxAttrs attrs,void * buf,hwaddr len,bool is_write)29758d7f2e76SPhilippe Mathieu-Daudé MemTxResult address_space_rw(AddressSpace *as, hwaddr addr, MemTxAttrs attrs,
29768d7f2e76SPhilippe Mathieu-Daudé void *buf, hwaddr len, bool is_write)
29778d7f2e76SPhilippe Mathieu-Daudé {
29788d7f2e76SPhilippe Mathieu-Daudé if (is_write) {
29798d7f2e76SPhilippe Mathieu-Daudé return address_space_write(as, addr, attrs, buf, len);
29808d7f2e76SPhilippe Mathieu-Daudé } else {
29818d7f2e76SPhilippe Mathieu-Daudé return address_space_read_full(as, addr, attrs, buf, len);
29828d7f2e76SPhilippe Mathieu-Daudé }
29838d7f2e76SPhilippe Mathieu-Daudé }
29848d7f2e76SPhilippe Mathieu-Daudé
address_space_set(AddressSpace * as,hwaddr addr,uint8_t c,hwaddr len,MemTxAttrs attrs)29858d7f2e76SPhilippe Mathieu-Daudé MemTxResult address_space_set(AddressSpace *as, hwaddr addr,
29868d7f2e76SPhilippe Mathieu-Daudé uint8_t c, hwaddr len, MemTxAttrs attrs)
29878d7f2e76SPhilippe Mathieu-Daudé {
29888d7f2e76SPhilippe Mathieu-Daudé #define FILLBUF_SIZE 512
29898d7f2e76SPhilippe Mathieu-Daudé uint8_t fillbuf[FILLBUF_SIZE];
29908d7f2e76SPhilippe Mathieu-Daudé int l;
29918d7f2e76SPhilippe Mathieu-Daudé MemTxResult error = MEMTX_OK;
29928d7f2e76SPhilippe Mathieu-Daudé
29938d7f2e76SPhilippe Mathieu-Daudé memset(fillbuf, c, FILLBUF_SIZE);
29948d7f2e76SPhilippe Mathieu-Daudé while (len > 0) {
29958d7f2e76SPhilippe Mathieu-Daudé l = len < FILLBUF_SIZE ? len : FILLBUF_SIZE;
29968d7f2e76SPhilippe Mathieu-Daudé error |= address_space_write(as, addr, attrs, fillbuf, l);
29978d7f2e76SPhilippe Mathieu-Daudé len -= l;
29988d7f2e76SPhilippe Mathieu-Daudé addr += l;
29998d7f2e76SPhilippe Mathieu-Daudé }
30008d7f2e76SPhilippe Mathieu-Daudé
30018d7f2e76SPhilippe Mathieu-Daudé return error;
30028d7f2e76SPhilippe Mathieu-Daudé }
30038d7f2e76SPhilippe Mathieu-Daudé
cpu_physical_memory_rw(hwaddr addr,void * buf,hwaddr len,bool is_write)30048d7f2e76SPhilippe Mathieu-Daudé void cpu_physical_memory_rw(hwaddr addr, void *buf,
30058d7f2e76SPhilippe Mathieu-Daudé hwaddr len, bool is_write)
30068d7f2e76SPhilippe Mathieu-Daudé {
30078d7f2e76SPhilippe Mathieu-Daudé address_space_rw(&address_space_memory, addr, MEMTXATTRS_UNSPECIFIED,
30088d7f2e76SPhilippe Mathieu-Daudé buf, len, is_write);
30098d7f2e76SPhilippe Mathieu-Daudé }
30108d7f2e76SPhilippe Mathieu-Daudé
30118d7f2e76SPhilippe Mathieu-Daudé enum write_rom_type {
30128d7f2e76SPhilippe Mathieu-Daudé WRITE_DATA,
30138d7f2e76SPhilippe Mathieu-Daudé FLUSH_CACHE,
30148d7f2e76SPhilippe Mathieu-Daudé };
30158d7f2e76SPhilippe Mathieu-Daudé
address_space_write_rom_internal(AddressSpace * as,hwaddr addr,MemTxAttrs attrs,const void * ptr,hwaddr len,enum write_rom_type type)30168d7f2e76SPhilippe Mathieu-Daudé static inline MemTxResult address_space_write_rom_internal(AddressSpace *as,
30178d7f2e76SPhilippe Mathieu-Daudé hwaddr addr,
30188d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs,
30198d7f2e76SPhilippe Mathieu-Daudé const void *ptr,
30208d7f2e76SPhilippe Mathieu-Daudé hwaddr len,
30218d7f2e76SPhilippe Mathieu-Daudé enum write_rom_type type)
30228d7f2e76SPhilippe Mathieu-Daudé {
30238d7f2e76SPhilippe Mathieu-Daudé hwaddr l;
30248d7f2e76SPhilippe Mathieu-Daudé uint8_t *ram_ptr;
30258d7f2e76SPhilippe Mathieu-Daudé hwaddr addr1;
30268d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr;
30278d7f2e76SPhilippe Mathieu-Daudé const uint8_t *buf = ptr;
30288d7f2e76SPhilippe Mathieu-Daudé
30298d7f2e76SPhilippe Mathieu-Daudé RCU_READ_LOCK_GUARD();
30308d7f2e76SPhilippe Mathieu-Daudé while (len > 0) {
30318d7f2e76SPhilippe Mathieu-Daudé l = len;
30328d7f2e76SPhilippe Mathieu-Daudé mr = address_space_translate(as, addr, &addr1, &l, true, attrs);
30338d7f2e76SPhilippe Mathieu-Daudé
30348d7f2e76SPhilippe Mathieu-Daudé if (!(memory_region_is_ram(mr) ||
30358d7f2e76SPhilippe Mathieu-Daudé memory_region_is_romd(mr))) {
30368d7f2e76SPhilippe Mathieu-Daudé l = memory_access_size(mr, l, addr1);
30378d7f2e76SPhilippe Mathieu-Daudé } else {
30388d7f2e76SPhilippe Mathieu-Daudé /* ROM/RAM case */
30398d7f2e76SPhilippe Mathieu-Daudé ram_ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
30408d7f2e76SPhilippe Mathieu-Daudé switch (type) {
30418d7f2e76SPhilippe Mathieu-Daudé case WRITE_DATA:
30428d7f2e76SPhilippe Mathieu-Daudé memcpy(ram_ptr, buf, l);
30438d7f2e76SPhilippe Mathieu-Daudé invalidate_and_set_dirty(mr, addr1, l);
30448d7f2e76SPhilippe Mathieu-Daudé break;
30458d7f2e76SPhilippe Mathieu-Daudé case FLUSH_CACHE:
30468d7f2e76SPhilippe Mathieu-Daudé flush_idcache_range((uintptr_t)ram_ptr, (uintptr_t)ram_ptr, l);
30478d7f2e76SPhilippe Mathieu-Daudé break;
30488d7f2e76SPhilippe Mathieu-Daudé }
30498d7f2e76SPhilippe Mathieu-Daudé }
30508d7f2e76SPhilippe Mathieu-Daudé len -= l;
30518d7f2e76SPhilippe Mathieu-Daudé buf += l;
30528d7f2e76SPhilippe Mathieu-Daudé addr += l;
30538d7f2e76SPhilippe Mathieu-Daudé }
30548d7f2e76SPhilippe Mathieu-Daudé return MEMTX_OK;
30558d7f2e76SPhilippe Mathieu-Daudé }
30568d7f2e76SPhilippe Mathieu-Daudé
30578d7f2e76SPhilippe Mathieu-Daudé /* used for ROM loading : can write in RAM and ROM */
address_space_write_rom(AddressSpace * as,hwaddr addr,MemTxAttrs attrs,const void * buf,hwaddr len)30588d7f2e76SPhilippe Mathieu-Daudé MemTxResult address_space_write_rom(AddressSpace *as, hwaddr addr,
30598d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs,
30608d7f2e76SPhilippe Mathieu-Daudé const void *buf, hwaddr len)
30618d7f2e76SPhilippe Mathieu-Daudé {
30628d7f2e76SPhilippe Mathieu-Daudé return address_space_write_rom_internal(as, addr, attrs,
30638d7f2e76SPhilippe Mathieu-Daudé buf, len, WRITE_DATA);
30648d7f2e76SPhilippe Mathieu-Daudé }
30658d7f2e76SPhilippe Mathieu-Daudé
cpu_flush_icache_range(hwaddr start,hwaddr len)30668d7f2e76SPhilippe Mathieu-Daudé void cpu_flush_icache_range(hwaddr start, hwaddr len)
30678d7f2e76SPhilippe Mathieu-Daudé {
30688d7f2e76SPhilippe Mathieu-Daudé /*
30698d7f2e76SPhilippe Mathieu-Daudé * This function should do the same thing as an icache flush that was
30708d7f2e76SPhilippe Mathieu-Daudé * triggered from within the guest. For TCG we are always cache coherent,
30718d7f2e76SPhilippe Mathieu-Daudé * so there is no need to flush anything. For KVM / Xen we need to flush
30728d7f2e76SPhilippe Mathieu-Daudé * the host's instruction cache at least.
30738d7f2e76SPhilippe Mathieu-Daudé */
30748d7f2e76SPhilippe Mathieu-Daudé if (tcg_enabled()) {
30758d7f2e76SPhilippe Mathieu-Daudé return;
30768d7f2e76SPhilippe Mathieu-Daudé }
30778d7f2e76SPhilippe Mathieu-Daudé
30788d7f2e76SPhilippe Mathieu-Daudé address_space_write_rom_internal(&address_space_memory,
30798d7f2e76SPhilippe Mathieu-Daudé start, MEMTXATTRS_UNSPECIFIED,
30808d7f2e76SPhilippe Mathieu-Daudé NULL, len, FLUSH_CACHE);
30818d7f2e76SPhilippe Mathieu-Daudé }
30828d7f2e76SPhilippe Mathieu-Daudé
3083637b0aa1SMattias Nissler /*
3084637b0aa1SMattias Nissler * A magic value stored in the first 8 bytes of the bounce buffer struct. Used
3085637b0aa1SMattias Nissler * to detect illegal pointers passed to address_space_unmap.
3086637b0aa1SMattias Nissler */
3087637b0aa1SMattias Nissler #define BOUNCE_BUFFER_MAGIC 0xb4017ceb4ffe12ed
3088637b0aa1SMattias Nissler
3089637b0aa1SMattias Nissler typedef struct {
3090637b0aa1SMattias Nissler uint64_t magic;
3091637b0aa1SMattias Nissler MemoryRegion *mr;
3092637b0aa1SMattias Nissler hwaddr addr;
3093637b0aa1SMattias Nissler size_t len;
3094637b0aa1SMattias Nissler uint8_t buffer[];
3095637b0aa1SMattias Nissler } BounceBuffer;
3096637b0aa1SMattias Nissler
309769e78f1bSMattias Nissler static void
address_space_unregister_map_client_do(AddressSpaceMapClient * client)309869e78f1bSMattias Nissler address_space_unregister_map_client_do(AddressSpaceMapClient *client)
30998d7f2e76SPhilippe Mathieu-Daudé {
31008d7f2e76SPhilippe Mathieu-Daudé QLIST_REMOVE(client, link);
31018d7f2e76SPhilippe Mathieu-Daudé g_free(client);
31028d7f2e76SPhilippe Mathieu-Daudé }
31038d7f2e76SPhilippe Mathieu-Daudé
address_space_notify_map_clients_locked(AddressSpace * as)31045c627197SMattias Nissler static void address_space_notify_map_clients_locked(AddressSpace *as)
31058d7f2e76SPhilippe Mathieu-Daudé {
310669e78f1bSMattias Nissler AddressSpaceMapClient *client;
31078d7f2e76SPhilippe Mathieu-Daudé
310869e78f1bSMattias Nissler while (!QLIST_EMPTY(&as->map_client_list)) {
310969e78f1bSMattias Nissler client = QLIST_FIRST(&as->map_client_list);
31108d7f2e76SPhilippe Mathieu-Daudé qemu_bh_schedule(client->bh);
31115c627197SMattias Nissler address_space_unregister_map_client_do(client);
31128d7f2e76SPhilippe Mathieu-Daudé }
31138d7f2e76SPhilippe Mathieu-Daudé }
31148d7f2e76SPhilippe Mathieu-Daudé
address_space_register_map_client(AddressSpace * as,QEMUBH * bh)31155c627197SMattias Nissler void address_space_register_map_client(AddressSpace *as, QEMUBH *bh)
31168d7f2e76SPhilippe Mathieu-Daudé {
311769e78f1bSMattias Nissler AddressSpaceMapClient *client = g_malloc(sizeof(*client));
31188d7f2e76SPhilippe Mathieu-Daudé
311969e78f1bSMattias Nissler QEMU_LOCK_GUARD(&as->map_client_list_lock);
31208d7f2e76SPhilippe Mathieu-Daudé client->bh = bh;
312169e78f1bSMattias Nissler QLIST_INSERT_HEAD(&as->map_client_list, client, link);
3122637b0aa1SMattias Nissler /* Write map_client_list before reading bounce_buffer_size. */
31238d7f2e76SPhilippe Mathieu-Daudé smp_mb();
3124637b0aa1SMattias Nissler if (qatomic_read(&as->bounce_buffer_size) < as->max_bounce_buffer_size) {
31255c627197SMattias Nissler address_space_notify_map_clients_locked(as);
31268d7f2e76SPhilippe Mathieu-Daudé }
31278d7f2e76SPhilippe Mathieu-Daudé }
31288d7f2e76SPhilippe Mathieu-Daudé
cpu_exec_init_all(void)31298d7f2e76SPhilippe Mathieu-Daudé void cpu_exec_init_all(void)
31308d7f2e76SPhilippe Mathieu-Daudé {
31318d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_init(&ram_list.mutex);
31328d7f2e76SPhilippe Mathieu-Daudé /* The data structures we set up here depend on knowing the page size,
31338d7f2e76SPhilippe Mathieu-Daudé * so no more changes can be made after this point.
31348d7f2e76SPhilippe Mathieu-Daudé * In an ideal world, nothing we did before we had finished the
31358d7f2e76SPhilippe Mathieu-Daudé * machine setup would care about the target page size, and we could
31368d7f2e76SPhilippe Mathieu-Daudé * do this much later, rather than requiring board models to state
31378d7f2e76SPhilippe Mathieu-Daudé * up front what their requirements are.
31388d7f2e76SPhilippe Mathieu-Daudé */
31398d7f2e76SPhilippe Mathieu-Daudé finalize_target_page_bits();
31408d7f2e76SPhilippe Mathieu-Daudé io_mem_init();
31418d7f2e76SPhilippe Mathieu-Daudé memory_map_init();
31428d7f2e76SPhilippe Mathieu-Daudé }
31438d7f2e76SPhilippe Mathieu-Daudé
address_space_unregister_map_client(AddressSpace * as,QEMUBH * bh)31445c627197SMattias Nissler void address_space_unregister_map_client(AddressSpace *as, QEMUBH *bh)
31458d7f2e76SPhilippe Mathieu-Daudé {
314669e78f1bSMattias Nissler AddressSpaceMapClient *client;
31478d7f2e76SPhilippe Mathieu-Daudé
314869e78f1bSMattias Nissler QEMU_LOCK_GUARD(&as->map_client_list_lock);
314969e78f1bSMattias Nissler QLIST_FOREACH(client, &as->map_client_list, link) {
31508d7f2e76SPhilippe Mathieu-Daudé if (client->bh == bh) {
31515c627197SMattias Nissler address_space_unregister_map_client_do(client);
31528d7f2e76SPhilippe Mathieu-Daudé break;
31538d7f2e76SPhilippe Mathieu-Daudé }
31548d7f2e76SPhilippe Mathieu-Daudé }
31558d7f2e76SPhilippe Mathieu-Daudé }
31568d7f2e76SPhilippe Mathieu-Daudé
address_space_notify_map_clients(AddressSpace * as)31575c627197SMattias Nissler static void address_space_notify_map_clients(AddressSpace *as)
31588d7f2e76SPhilippe Mathieu-Daudé {
315969e78f1bSMattias Nissler QEMU_LOCK_GUARD(&as->map_client_list_lock);
31605c627197SMattias Nissler address_space_notify_map_clients_locked(as);
31618d7f2e76SPhilippe Mathieu-Daudé }
31628d7f2e76SPhilippe Mathieu-Daudé
flatview_access_valid(FlatView * fv,hwaddr addr,hwaddr len,bool is_write,MemTxAttrs attrs)31638d7f2e76SPhilippe Mathieu-Daudé static bool flatview_access_valid(FlatView *fv, hwaddr addr, hwaddr len,
31648d7f2e76SPhilippe Mathieu-Daudé bool is_write, MemTxAttrs attrs)
31658d7f2e76SPhilippe Mathieu-Daudé {
31668d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr;
31678d7f2e76SPhilippe Mathieu-Daudé hwaddr l, xlat;
31688d7f2e76SPhilippe Mathieu-Daudé
31698d7f2e76SPhilippe Mathieu-Daudé while (len > 0) {
31708d7f2e76SPhilippe Mathieu-Daudé l = len;
31718d7f2e76SPhilippe Mathieu-Daudé mr = flatview_translate(fv, addr, &xlat, &l, is_write, attrs);
31728d7f2e76SPhilippe Mathieu-Daudé if (!memory_access_is_direct(mr, is_write)) {
31738d7f2e76SPhilippe Mathieu-Daudé l = memory_access_size(mr, l, addr);
31748d7f2e76SPhilippe Mathieu-Daudé if (!memory_region_access_valid(mr, xlat, l, is_write, attrs)) {
31758d7f2e76SPhilippe Mathieu-Daudé return false;
31768d7f2e76SPhilippe Mathieu-Daudé }
31778d7f2e76SPhilippe Mathieu-Daudé }
31788d7f2e76SPhilippe Mathieu-Daudé
31798d7f2e76SPhilippe Mathieu-Daudé len -= l;
31808d7f2e76SPhilippe Mathieu-Daudé addr += l;
31818d7f2e76SPhilippe Mathieu-Daudé }
31828d7f2e76SPhilippe Mathieu-Daudé return true;
31838d7f2e76SPhilippe Mathieu-Daudé }
31848d7f2e76SPhilippe Mathieu-Daudé
address_space_access_valid(AddressSpace * as,hwaddr addr,hwaddr len,bool is_write,MemTxAttrs attrs)31858d7f2e76SPhilippe Mathieu-Daudé bool address_space_access_valid(AddressSpace *as, hwaddr addr,
31868d7f2e76SPhilippe Mathieu-Daudé hwaddr len, bool is_write,
31878d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs)
31888d7f2e76SPhilippe Mathieu-Daudé {
31898d7f2e76SPhilippe Mathieu-Daudé FlatView *fv;
31908d7f2e76SPhilippe Mathieu-Daudé
31918d7f2e76SPhilippe Mathieu-Daudé RCU_READ_LOCK_GUARD();
31928d7f2e76SPhilippe Mathieu-Daudé fv = address_space_to_flatview(as);
31938d7f2e76SPhilippe Mathieu-Daudé return flatview_access_valid(fv, addr, len, is_write, attrs);
31948d7f2e76SPhilippe Mathieu-Daudé }
31958d7f2e76SPhilippe Mathieu-Daudé
31968d7f2e76SPhilippe Mathieu-Daudé static hwaddr
flatview_extend_translation(FlatView * fv,hwaddr addr,hwaddr target_len,MemoryRegion * mr,hwaddr base,hwaddr len,bool is_write,MemTxAttrs attrs)31978d7f2e76SPhilippe Mathieu-Daudé flatview_extend_translation(FlatView *fv, hwaddr addr,
31988d7f2e76SPhilippe Mathieu-Daudé hwaddr target_len,
31998d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr, hwaddr base, hwaddr len,
32008d7f2e76SPhilippe Mathieu-Daudé bool is_write, MemTxAttrs attrs)
32018d7f2e76SPhilippe Mathieu-Daudé {
32028d7f2e76SPhilippe Mathieu-Daudé hwaddr done = 0;
32038d7f2e76SPhilippe Mathieu-Daudé hwaddr xlat;
32048d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *this_mr;
32058d7f2e76SPhilippe Mathieu-Daudé
32068d7f2e76SPhilippe Mathieu-Daudé for (;;) {
32078d7f2e76SPhilippe Mathieu-Daudé target_len -= len;
32088d7f2e76SPhilippe Mathieu-Daudé addr += len;
32098d7f2e76SPhilippe Mathieu-Daudé done += len;
32108d7f2e76SPhilippe Mathieu-Daudé if (target_len == 0) {
32118d7f2e76SPhilippe Mathieu-Daudé return done;
32128d7f2e76SPhilippe Mathieu-Daudé }
32138d7f2e76SPhilippe Mathieu-Daudé
32148d7f2e76SPhilippe Mathieu-Daudé len = target_len;
32158d7f2e76SPhilippe Mathieu-Daudé this_mr = flatview_translate(fv, addr, &xlat,
32168d7f2e76SPhilippe Mathieu-Daudé &len, is_write, attrs);
32178d7f2e76SPhilippe Mathieu-Daudé if (this_mr != mr || xlat != base + done) {
32188d7f2e76SPhilippe Mathieu-Daudé return done;
32198d7f2e76SPhilippe Mathieu-Daudé }
32208d7f2e76SPhilippe Mathieu-Daudé }
32218d7f2e76SPhilippe Mathieu-Daudé }
32228d7f2e76SPhilippe Mathieu-Daudé
32238d7f2e76SPhilippe Mathieu-Daudé /* Map a physical memory region into a host virtual address.
32248d7f2e76SPhilippe Mathieu-Daudé * May map a subset of the requested range, given by and returned in *plen.
32258d7f2e76SPhilippe Mathieu-Daudé * May return NULL if resources needed to perform the mapping are exhausted.
32268d7f2e76SPhilippe Mathieu-Daudé * Use only for reads OR writes - not for read-modify-write operations.
32275c627197SMattias Nissler * Use address_space_register_map_client() to know when retrying the map
32285c627197SMattias Nissler * operation is likely to succeed.
32298d7f2e76SPhilippe Mathieu-Daudé */
address_space_map(AddressSpace * as,hwaddr addr,hwaddr * plen,bool is_write,MemTxAttrs attrs)32308d7f2e76SPhilippe Mathieu-Daudé void *address_space_map(AddressSpace *as,
32318d7f2e76SPhilippe Mathieu-Daudé hwaddr addr,
32328d7f2e76SPhilippe Mathieu-Daudé hwaddr *plen,
32338d7f2e76SPhilippe Mathieu-Daudé bool is_write,
32348d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs)
32358d7f2e76SPhilippe Mathieu-Daudé {
32368d7f2e76SPhilippe Mathieu-Daudé hwaddr len = *plen;
32378d7f2e76SPhilippe Mathieu-Daudé hwaddr l, xlat;
32388d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr;
32398d7f2e76SPhilippe Mathieu-Daudé FlatView *fv;
32408d7f2e76SPhilippe Mathieu-Daudé
3241d44fe13bSAlex Bennée trace_address_space_map(as, addr, len, is_write, *(uint32_t *) &attrs);
3242d44fe13bSAlex Bennée
32438d7f2e76SPhilippe Mathieu-Daudé if (len == 0) {
32448d7f2e76SPhilippe Mathieu-Daudé return NULL;
32458d7f2e76SPhilippe Mathieu-Daudé }
32468d7f2e76SPhilippe Mathieu-Daudé
32478d7f2e76SPhilippe Mathieu-Daudé l = len;
32488d7f2e76SPhilippe Mathieu-Daudé RCU_READ_LOCK_GUARD();
32498d7f2e76SPhilippe Mathieu-Daudé fv = address_space_to_flatview(as);
32508d7f2e76SPhilippe Mathieu-Daudé mr = flatview_translate(fv, addr, &xlat, &l, is_write, attrs);
32518d7f2e76SPhilippe Mathieu-Daudé
32528d7f2e76SPhilippe Mathieu-Daudé if (!memory_access_is_direct(mr, is_write)) {
3253637b0aa1SMattias Nissler size_t used = qatomic_read(&as->bounce_buffer_size);
3254637b0aa1SMattias Nissler for (;;) {
3255637b0aa1SMattias Nissler hwaddr alloc = MIN(as->max_bounce_buffer_size - used, l);
3256637b0aa1SMattias Nissler size_t new_size = used + alloc;
3257637b0aa1SMattias Nissler size_t actual =
3258637b0aa1SMattias Nissler qatomic_cmpxchg(&as->bounce_buffer_size, used, new_size);
3259637b0aa1SMattias Nissler if (actual == used) {
3260637b0aa1SMattias Nissler l = alloc;
3261637b0aa1SMattias Nissler break;
3262637b0aa1SMattias Nissler }
3263637b0aa1SMattias Nissler used = actual;
3264637b0aa1SMattias Nissler }
3265637b0aa1SMattias Nissler
3266637b0aa1SMattias Nissler if (l == 0) {
32678d7f2e76SPhilippe Mathieu-Daudé *plen = 0;
32688d7f2e76SPhilippe Mathieu-Daudé return NULL;
32698d7f2e76SPhilippe Mathieu-Daudé }
32708d7f2e76SPhilippe Mathieu-Daudé
3271637b0aa1SMattias Nissler BounceBuffer *bounce = g_malloc0(l + sizeof(BounceBuffer));
3272637b0aa1SMattias Nissler bounce->magic = BOUNCE_BUFFER_MAGIC;
32738d7f2e76SPhilippe Mathieu-Daudé memory_region_ref(mr);
3274637b0aa1SMattias Nissler bounce->mr = mr;
3275637b0aa1SMattias Nissler bounce->addr = addr;
3276637b0aa1SMattias Nissler bounce->len = l;
3277637b0aa1SMattias Nissler
32788d7f2e76SPhilippe Mathieu-Daudé if (!is_write) {
3279d8d5ca40SFea.Wang flatview_read(fv, addr, attrs,
3280637b0aa1SMattias Nissler bounce->buffer, l);
32818d7f2e76SPhilippe Mathieu-Daudé }
32828d7f2e76SPhilippe Mathieu-Daudé
32838d7f2e76SPhilippe Mathieu-Daudé *plen = l;
3284637b0aa1SMattias Nissler return bounce->buffer;
32858d7f2e76SPhilippe Mathieu-Daudé }
32868d7f2e76SPhilippe Mathieu-Daudé
32878d7f2e76SPhilippe Mathieu-Daudé memory_region_ref(mr);
32888d7f2e76SPhilippe Mathieu-Daudé *plen = flatview_extend_translation(fv, addr, len, mr, xlat,
32898d7f2e76SPhilippe Mathieu-Daudé l, is_write, attrs);
32908d7f2e76SPhilippe Mathieu-Daudé fuzz_dma_read_cb(addr, *plen, mr);
32915a5585f4SEdgar E. Iglesias return qemu_ram_ptr_length(mr->ram_block, xlat, plen, true, is_write);
32928d7f2e76SPhilippe Mathieu-Daudé }
32938d7f2e76SPhilippe Mathieu-Daudé
32948d7f2e76SPhilippe Mathieu-Daudé /* Unmaps a memory region previously mapped by address_space_map().
32958d7f2e76SPhilippe Mathieu-Daudé * Will also mark the memory as dirty if is_write is true. access_len gives
32968d7f2e76SPhilippe Mathieu-Daudé * the amount of memory that was actually read or written by the caller.
32978d7f2e76SPhilippe Mathieu-Daudé */
address_space_unmap(AddressSpace * as,void * buffer,hwaddr len,bool is_write,hwaddr access_len)32988d7f2e76SPhilippe Mathieu-Daudé void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
32998d7f2e76SPhilippe Mathieu-Daudé bool is_write, hwaddr access_len)
33008d7f2e76SPhilippe Mathieu-Daudé {
33018d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr;
33028d7f2e76SPhilippe Mathieu-Daudé ram_addr_t addr1;
33038d7f2e76SPhilippe Mathieu-Daudé
33048d7f2e76SPhilippe Mathieu-Daudé mr = memory_region_from_host(buffer, &addr1);
3305637b0aa1SMattias Nissler if (mr != NULL) {
33068d7f2e76SPhilippe Mathieu-Daudé if (is_write) {
33078d7f2e76SPhilippe Mathieu-Daudé invalidate_and_set_dirty(mr, addr1, access_len);
33088d7f2e76SPhilippe Mathieu-Daudé }
33098d7f2e76SPhilippe Mathieu-Daudé if (xen_enabled()) {
33108d7f2e76SPhilippe Mathieu-Daudé xen_invalidate_map_cache_entry(buffer);
33118d7f2e76SPhilippe Mathieu-Daudé }
33128d7f2e76SPhilippe Mathieu-Daudé memory_region_unref(mr);
33138d7f2e76SPhilippe Mathieu-Daudé return;
33148d7f2e76SPhilippe Mathieu-Daudé }
3315637b0aa1SMattias Nissler
3316637b0aa1SMattias Nissler
3317637b0aa1SMattias Nissler BounceBuffer *bounce = container_of(buffer, BounceBuffer, buffer);
3318637b0aa1SMattias Nissler assert(bounce->magic == BOUNCE_BUFFER_MAGIC);
3319637b0aa1SMattias Nissler
33208d7f2e76SPhilippe Mathieu-Daudé if (is_write) {
3321637b0aa1SMattias Nissler address_space_write(as, bounce->addr, MEMTXATTRS_UNSPECIFIED,
3322637b0aa1SMattias Nissler bounce->buffer, access_len);
33238d7f2e76SPhilippe Mathieu-Daudé }
3324637b0aa1SMattias Nissler
3325637b0aa1SMattias Nissler qatomic_sub(&as->bounce_buffer_size, bounce->len);
3326637b0aa1SMattias Nissler bounce->magic = ~BOUNCE_BUFFER_MAGIC;
3327637b0aa1SMattias Nissler memory_region_unref(bounce->mr);
3328637b0aa1SMattias Nissler g_free(bounce);
3329637b0aa1SMattias Nissler /* Write bounce_buffer_size before reading map_client_list. */
3330637b0aa1SMattias Nissler smp_mb();
33315c627197SMattias Nissler address_space_notify_map_clients(as);
33328d7f2e76SPhilippe Mathieu-Daudé }
33338d7f2e76SPhilippe Mathieu-Daudé
cpu_physical_memory_map(hwaddr addr,hwaddr * plen,bool is_write)33348d7f2e76SPhilippe Mathieu-Daudé void *cpu_physical_memory_map(hwaddr addr,
33358d7f2e76SPhilippe Mathieu-Daudé hwaddr *plen,
33368d7f2e76SPhilippe Mathieu-Daudé bool is_write)
33378d7f2e76SPhilippe Mathieu-Daudé {
33388d7f2e76SPhilippe Mathieu-Daudé return address_space_map(&address_space_memory, addr, plen, is_write,
33398d7f2e76SPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED);
33408d7f2e76SPhilippe Mathieu-Daudé }
33418d7f2e76SPhilippe Mathieu-Daudé
cpu_physical_memory_unmap(void * buffer,hwaddr len,bool is_write,hwaddr access_len)33428d7f2e76SPhilippe Mathieu-Daudé void cpu_physical_memory_unmap(void *buffer, hwaddr len,
33438d7f2e76SPhilippe Mathieu-Daudé bool is_write, hwaddr access_len)
33448d7f2e76SPhilippe Mathieu-Daudé {
33458d7f2e76SPhilippe Mathieu-Daudé return address_space_unmap(&address_space_memory, buffer, len, is_write, access_len);
33468d7f2e76SPhilippe Mathieu-Daudé }
33478d7f2e76SPhilippe Mathieu-Daudé
33488d7f2e76SPhilippe Mathieu-Daudé #define ARG1_DECL AddressSpace *as
33498d7f2e76SPhilippe Mathieu-Daudé #define ARG1 as
33508d7f2e76SPhilippe Mathieu-Daudé #define SUFFIX
33518d7f2e76SPhilippe Mathieu-Daudé #define TRANSLATE(...) address_space_translate(as, __VA_ARGS__)
33528d7f2e76SPhilippe Mathieu-Daudé #define RCU_READ_LOCK(...) rcu_read_lock()
33538d7f2e76SPhilippe Mathieu-Daudé #define RCU_READ_UNLOCK(...) rcu_read_unlock()
33548d7f2e76SPhilippe Mathieu-Daudé #include "memory_ldst.c.inc"
33558d7f2e76SPhilippe Mathieu-Daudé
address_space_cache_init(MemoryRegionCache * cache,AddressSpace * as,hwaddr addr,hwaddr len,bool is_write)33568d7f2e76SPhilippe Mathieu-Daudé int64_t address_space_cache_init(MemoryRegionCache *cache,
33578d7f2e76SPhilippe Mathieu-Daudé AddressSpace *as,
33588d7f2e76SPhilippe Mathieu-Daudé hwaddr addr,
33598d7f2e76SPhilippe Mathieu-Daudé hwaddr len,
33608d7f2e76SPhilippe Mathieu-Daudé bool is_write)
33618d7f2e76SPhilippe Mathieu-Daudé {
33628d7f2e76SPhilippe Mathieu-Daudé AddressSpaceDispatch *d;
33638d7f2e76SPhilippe Mathieu-Daudé hwaddr l;
33648d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr;
33658d7f2e76SPhilippe Mathieu-Daudé Int128 diff;
33668d7f2e76SPhilippe Mathieu-Daudé
33678d7f2e76SPhilippe Mathieu-Daudé assert(len > 0);
33688d7f2e76SPhilippe Mathieu-Daudé
33698d7f2e76SPhilippe Mathieu-Daudé l = len;
33708d7f2e76SPhilippe Mathieu-Daudé cache->fv = address_space_get_flatview(as);
33718d7f2e76SPhilippe Mathieu-Daudé d = flatview_to_dispatch(cache->fv);
33728d7f2e76SPhilippe Mathieu-Daudé cache->mrs = *address_space_translate_internal(d, addr, &cache->xlat, &l, true);
33738d7f2e76SPhilippe Mathieu-Daudé
33748d7f2e76SPhilippe Mathieu-Daudé /*
33758d7f2e76SPhilippe Mathieu-Daudé * cache->xlat is now relative to cache->mrs.mr, not to the section itself.
33768d7f2e76SPhilippe Mathieu-Daudé * Take that into account to compute how many bytes are there between
33778d7f2e76SPhilippe Mathieu-Daudé * cache->xlat and the end of the section.
33788d7f2e76SPhilippe Mathieu-Daudé */
33798d7f2e76SPhilippe Mathieu-Daudé diff = int128_sub(cache->mrs.size,
33808d7f2e76SPhilippe Mathieu-Daudé int128_make64(cache->xlat - cache->mrs.offset_within_region));
33818d7f2e76SPhilippe Mathieu-Daudé l = int128_get64(int128_min(diff, int128_make64(l)));
33828d7f2e76SPhilippe Mathieu-Daudé
33838d7f2e76SPhilippe Mathieu-Daudé mr = cache->mrs.mr;
33848d7f2e76SPhilippe Mathieu-Daudé memory_region_ref(mr);
33858d7f2e76SPhilippe Mathieu-Daudé if (memory_access_is_direct(mr, is_write)) {
33868d7f2e76SPhilippe Mathieu-Daudé /* We don't care about the memory attributes here as we're only
33878d7f2e76SPhilippe Mathieu-Daudé * doing this if we found actual RAM, which behaves the same
33888d7f2e76SPhilippe Mathieu-Daudé * regardless of attributes; so UNSPECIFIED is fine.
33898d7f2e76SPhilippe Mathieu-Daudé */
33908d7f2e76SPhilippe Mathieu-Daudé l = flatview_extend_translation(cache->fv, addr, len, mr,
33918d7f2e76SPhilippe Mathieu-Daudé cache->xlat, l, is_write,
33928d7f2e76SPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED);
33935a5585f4SEdgar E. Iglesias cache->ptr = qemu_ram_ptr_length(mr->ram_block, cache->xlat, &l, true,
33945a5585f4SEdgar E. Iglesias is_write);
33958d7f2e76SPhilippe Mathieu-Daudé } else {
33968d7f2e76SPhilippe Mathieu-Daudé cache->ptr = NULL;
33978d7f2e76SPhilippe Mathieu-Daudé }
33988d7f2e76SPhilippe Mathieu-Daudé
33998d7f2e76SPhilippe Mathieu-Daudé cache->len = l;
34008d7f2e76SPhilippe Mathieu-Daudé cache->is_write = is_write;
34018d7f2e76SPhilippe Mathieu-Daudé return l;
34028d7f2e76SPhilippe Mathieu-Daudé }
34038d7f2e76SPhilippe Mathieu-Daudé
address_space_cache_invalidate(MemoryRegionCache * cache,hwaddr addr,hwaddr access_len)34048d7f2e76SPhilippe Mathieu-Daudé void address_space_cache_invalidate(MemoryRegionCache *cache,
34058d7f2e76SPhilippe Mathieu-Daudé hwaddr addr,
34068d7f2e76SPhilippe Mathieu-Daudé hwaddr access_len)
34078d7f2e76SPhilippe Mathieu-Daudé {
34088d7f2e76SPhilippe Mathieu-Daudé assert(cache->is_write);
34098d7f2e76SPhilippe Mathieu-Daudé if (likely(cache->ptr)) {
34108d7f2e76SPhilippe Mathieu-Daudé invalidate_and_set_dirty(cache->mrs.mr, addr + cache->xlat, access_len);
34118d7f2e76SPhilippe Mathieu-Daudé }
34128d7f2e76SPhilippe Mathieu-Daudé }
34138d7f2e76SPhilippe Mathieu-Daudé
address_space_cache_destroy(MemoryRegionCache * cache)34148d7f2e76SPhilippe Mathieu-Daudé void address_space_cache_destroy(MemoryRegionCache *cache)
34158d7f2e76SPhilippe Mathieu-Daudé {
34168d7f2e76SPhilippe Mathieu-Daudé if (!cache->mrs.mr) {
34178d7f2e76SPhilippe Mathieu-Daudé return;
34188d7f2e76SPhilippe Mathieu-Daudé }
34198d7f2e76SPhilippe Mathieu-Daudé
34208d7f2e76SPhilippe Mathieu-Daudé if (xen_enabled()) {
34218d7f2e76SPhilippe Mathieu-Daudé xen_invalidate_map_cache_entry(cache->ptr);
34228d7f2e76SPhilippe Mathieu-Daudé }
34238d7f2e76SPhilippe Mathieu-Daudé memory_region_unref(cache->mrs.mr);
34248d7f2e76SPhilippe Mathieu-Daudé flatview_unref(cache->fv);
34258d7f2e76SPhilippe Mathieu-Daudé cache->mrs.mr = NULL;
34268d7f2e76SPhilippe Mathieu-Daudé cache->fv = NULL;
34278d7f2e76SPhilippe Mathieu-Daudé }
34288d7f2e76SPhilippe Mathieu-Daudé
34298d7f2e76SPhilippe Mathieu-Daudé /* Called from RCU critical section. This function has the same
34308d7f2e76SPhilippe Mathieu-Daudé * semantics as address_space_translate, but it only works on a
34318d7f2e76SPhilippe Mathieu-Daudé * predefined range of a MemoryRegion that was mapped with
34328d7f2e76SPhilippe Mathieu-Daudé * address_space_cache_init.
34338d7f2e76SPhilippe Mathieu-Daudé */
address_space_translate_cached(MemoryRegionCache * cache,hwaddr addr,hwaddr * xlat,hwaddr * plen,bool is_write,MemTxAttrs attrs)34348d7f2e76SPhilippe Mathieu-Daudé static inline MemoryRegion *address_space_translate_cached(
34358d7f2e76SPhilippe Mathieu-Daudé MemoryRegionCache *cache, hwaddr addr, hwaddr *xlat,
34368d7f2e76SPhilippe Mathieu-Daudé hwaddr *plen, bool is_write, MemTxAttrs attrs)
34378d7f2e76SPhilippe Mathieu-Daudé {
34388d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection section;
34398d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr;
34408d7f2e76SPhilippe Mathieu-Daudé IOMMUMemoryRegion *iommu_mr;
34418d7f2e76SPhilippe Mathieu-Daudé AddressSpace *target_as;
34428d7f2e76SPhilippe Mathieu-Daudé
34438d7f2e76SPhilippe Mathieu-Daudé assert(!cache->ptr);
34448d7f2e76SPhilippe Mathieu-Daudé *xlat = addr + cache->xlat;
34458d7f2e76SPhilippe Mathieu-Daudé
34468d7f2e76SPhilippe Mathieu-Daudé mr = cache->mrs.mr;
34478d7f2e76SPhilippe Mathieu-Daudé iommu_mr = memory_region_get_iommu(mr);
34488d7f2e76SPhilippe Mathieu-Daudé if (!iommu_mr) {
34498d7f2e76SPhilippe Mathieu-Daudé /* MMIO region. */
34508d7f2e76SPhilippe Mathieu-Daudé return mr;
34518d7f2e76SPhilippe Mathieu-Daudé }
34528d7f2e76SPhilippe Mathieu-Daudé
34538d7f2e76SPhilippe Mathieu-Daudé section = address_space_translate_iommu(iommu_mr, xlat, plen,
34548d7f2e76SPhilippe Mathieu-Daudé NULL, is_write, true,
34558d7f2e76SPhilippe Mathieu-Daudé &target_as, attrs);
34568d7f2e76SPhilippe Mathieu-Daudé return section.mr;
34578d7f2e76SPhilippe Mathieu-Daudé }
34588d7f2e76SPhilippe Mathieu-Daudé
345947293c92SJonathan Cameron /* Called within RCU critical section. */
address_space_write_continue_cached(MemTxAttrs attrs,const void * ptr,hwaddr len,hwaddr mr_addr,hwaddr l,MemoryRegion * mr)346047293c92SJonathan Cameron static MemTxResult address_space_write_continue_cached(MemTxAttrs attrs,
346147293c92SJonathan Cameron const void *ptr,
346247293c92SJonathan Cameron hwaddr len,
346347293c92SJonathan Cameron hwaddr mr_addr,
346447293c92SJonathan Cameron hwaddr l,
346547293c92SJonathan Cameron MemoryRegion *mr)
346647293c92SJonathan Cameron {
346747293c92SJonathan Cameron MemTxResult result = MEMTX_OK;
346847293c92SJonathan Cameron const uint8_t *buf = ptr;
346947293c92SJonathan Cameron
347047293c92SJonathan Cameron for (;;) {
347147293c92SJonathan Cameron result |= flatview_write_continue_step(attrs, buf, len, mr_addr, &l,
347247293c92SJonathan Cameron mr);
347347293c92SJonathan Cameron
347447293c92SJonathan Cameron len -= l;
347547293c92SJonathan Cameron buf += l;
347647293c92SJonathan Cameron mr_addr += l;
347747293c92SJonathan Cameron
347847293c92SJonathan Cameron if (!len) {
347947293c92SJonathan Cameron break;
348047293c92SJonathan Cameron }
348147293c92SJonathan Cameron
348247293c92SJonathan Cameron l = len;
348347293c92SJonathan Cameron }
348447293c92SJonathan Cameron
348547293c92SJonathan Cameron return result;
348647293c92SJonathan Cameron }
348747293c92SJonathan Cameron
348847293c92SJonathan Cameron /* Called within RCU critical section. */
address_space_read_continue_cached(MemTxAttrs attrs,void * ptr,hwaddr len,hwaddr mr_addr,hwaddr l,MemoryRegion * mr)348947293c92SJonathan Cameron static MemTxResult address_space_read_continue_cached(MemTxAttrs attrs,
349047293c92SJonathan Cameron void *ptr, hwaddr len,
349147293c92SJonathan Cameron hwaddr mr_addr, hwaddr l,
349247293c92SJonathan Cameron MemoryRegion *mr)
349347293c92SJonathan Cameron {
349447293c92SJonathan Cameron MemTxResult result = MEMTX_OK;
349547293c92SJonathan Cameron uint8_t *buf = ptr;
349647293c92SJonathan Cameron
349747293c92SJonathan Cameron for (;;) {
349847293c92SJonathan Cameron result |= flatview_read_continue_step(attrs, buf, len, mr_addr, &l, mr);
349947293c92SJonathan Cameron len -= l;
350047293c92SJonathan Cameron buf += l;
350147293c92SJonathan Cameron mr_addr += l;
350247293c92SJonathan Cameron
350347293c92SJonathan Cameron if (!len) {
350447293c92SJonathan Cameron break;
350547293c92SJonathan Cameron }
350647293c92SJonathan Cameron l = len;
350747293c92SJonathan Cameron }
350847293c92SJonathan Cameron
350947293c92SJonathan Cameron return result;
351047293c92SJonathan Cameron }
351147293c92SJonathan Cameron
35128d7f2e76SPhilippe Mathieu-Daudé /* Called from RCU critical section. address_space_read_cached uses this
35138d7f2e76SPhilippe Mathieu-Daudé * out of line function when the target is an MMIO or IOMMU region.
35148d7f2e76SPhilippe Mathieu-Daudé */
35158d7f2e76SPhilippe Mathieu-Daudé MemTxResult
address_space_read_cached_slow(MemoryRegionCache * cache,hwaddr addr,void * buf,hwaddr len)35168d7f2e76SPhilippe Mathieu-Daudé address_space_read_cached_slow(MemoryRegionCache *cache, hwaddr addr,
35178d7f2e76SPhilippe Mathieu-Daudé void *buf, hwaddr len)
35188d7f2e76SPhilippe Mathieu-Daudé {
35194c7c8563SJonathan Cameron hwaddr mr_addr, l;
35208d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr;
35218d7f2e76SPhilippe Mathieu-Daudé
35228d7f2e76SPhilippe Mathieu-Daudé l = len;
35234c7c8563SJonathan Cameron mr = address_space_translate_cached(cache, addr, &mr_addr, &l, false,
35248d7f2e76SPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED);
352547293c92SJonathan Cameron return address_space_read_continue_cached(MEMTXATTRS_UNSPECIFIED,
352647293c92SJonathan Cameron buf, len, mr_addr, l, mr);
35278d7f2e76SPhilippe Mathieu-Daudé }
35288d7f2e76SPhilippe Mathieu-Daudé
35298d7f2e76SPhilippe Mathieu-Daudé /* Called from RCU critical section. address_space_write_cached uses this
35308d7f2e76SPhilippe Mathieu-Daudé * out of line function when the target is an MMIO or IOMMU region.
35318d7f2e76SPhilippe Mathieu-Daudé */
35328d7f2e76SPhilippe Mathieu-Daudé MemTxResult
address_space_write_cached_slow(MemoryRegionCache * cache,hwaddr addr,const void * buf,hwaddr len)35338d7f2e76SPhilippe Mathieu-Daudé address_space_write_cached_slow(MemoryRegionCache *cache, hwaddr addr,
35348d7f2e76SPhilippe Mathieu-Daudé const void *buf, hwaddr len)
35358d7f2e76SPhilippe Mathieu-Daudé {
35364c7c8563SJonathan Cameron hwaddr mr_addr, l;
35378d7f2e76SPhilippe Mathieu-Daudé MemoryRegion *mr;
35388d7f2e76SPhilippe Mathieu-Daudé
35398d7f2e76SPhilippe Mathieu-Daudé l = len;
35404c7c8563SJonathan Cameron mr = address_space_translate_cached(cache, addr, &mr_addr, &l, true,
35418d7f2e76SPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED);
354247293c92SJonathan Cameron return address_space_write_continue_cached(MEMTXATTRS_UNSPECIFIED,
354347293c92SJonathan Cameron buf, len, mr_addr, l, mr);
35448d7f2e76SPhilippe Mathieu-Daudé }
35458d7f2e76SPhilippe Mathieu-Daudé
35468d7f2e76SPhilippe Mathieu-Daudé #define ARG1_DECL MemoryRegionCache *cache
35478d7f2e76SPhilippe Mathieu-Daudé #define ARG1 cache
35488d7f2e76SPhilippe Mathieu-Daudé #define SUFFIX _cached_slow
35498d7f2e76SPhilippe Mathieu-Daudé #define TRANSLATE(...) address_space_translate_cached(cache, __VA_ARGS__)
35508d7f2e76SPhilippe Mathieu-Daudé #define RCU_READ_LOCK() ((void)0)
35518d7f2e76SPhilippe Mathieu-Daudé #define RCU_READ_UNLOCK() ((void)0)
35528d7f2e76SPhilippe Mathieu-Daudé #include "memory_ldst.c.inc"
35538d7f2e76SPhilippe Mathieu-Daudé
35548d7f2e76SPhilippe Mathieu-Daudé /* virtual memory access for debug (includes writing to ROM) */
cpu_memory_rw_debug(CPUState * cpu,vaddr addr,void * ptr,size_t len,bool is_write)35558d7f2e76SPhilippe Mathieu-Daudé int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
35568d7f2e76SPhilippe Mathieu-Daudé void *ptr, size_t len, bool is_write)
35578d7f2e76SPhilippe Mathieu-Daudé {
35588d7f2e76SPhilippe Mathieu-Daudé hwaddr phys_addr;
35598d7f2e76SPhilippe Mathieu-Daudé vaddr l, page;
35608d7f2e76SPhilippe Mathieu-Daudé uint8_t *buf = ptr;
35618d7f2e76SPhilippe Mathieu-Daudé
35628d7f2e76SPhilippe Mathieu-Daudé cpu_synchronize_state(cpu);
35638d7f2e76SPhilippe Mathieu-Daudé while (len > 0) {
35648d7f2e76SPhilippe Mathieu-Daudé int asidx;
35658d7f2e76SPhilippe Mathieu-Daudé MemTxAttrs attrs;
35668d7f2e76SPhilippe Mathieu-Daudé MemTxResult res;
35678d7f2e76SPhilippe Mathieu-Daudé
35688d7f2e76SPhilippe Mathieu-Daudé page = addr & TARGET_PAGE_MASK;
35698d7f2e76SPhilippe Mathieu-Daudé phys_addr = cpu_get_phys_page_attrs_debug(cpu, page, &attrs);
35708d7f2e76SPhilippe Mathieu-Daudé asidx = cpu_asidx_from_attrs(cpu, attrs);
35718d7f2e76SPhilippe Mathieu-Daudé /* if no physical page mapped, return an error */
35728d7f2e76SPhilippe Mathieu-Daudé if (phys_addr == -1)
35738d7f2e76SPhilippe Mathieu-Daudé return -1;
35748d7f2e76SPhilippe Mathieu-Daudé l = (page + TARGET_PAGE_SIZE) - addr;
35758d7f2e76SPhilippe Mathieu-Daudé if (l > len)
35768d7f2e76SPhilippe Mathieu-Daudé l = len;
35778d7f2e76SPhilippe Mathieu-Daudé phys_addr += (addr & ~TARGET_PAGE_MASK);
35788d7f2e76SPhilippe Mathieu-Daudé if (is_write) {
35798d7f2e76SPhilippe Mathieu-Daudé res = address_space_write_rom(cpu->cpu_ases[asidx].as, phys_addr,
35808d7f2e76SPhilippe Mathieu-Daudé attrs, buf, l);
35818d7f2e76SPhilippe Mathieu-Daudé } else {
35828d7f2e76SPhilippe Mathieu-Daudé res = address_space_read(cpu->cpu_ases[asidx].as, phys_addr,
35838d7f2e76SPhilippe Mathieu-Daudé attrs, buf, l);
35848d7f2e76SPhilippe Mathieu-Daudé }
35858d7f2e76SPhilippe Mathieu-Daudé if (res != MEMTX_OK) {
35868d7f2e76SPhilippe Mathieu-Daudé return -1;
35878d7f2e76SPhilippe Mathieu-Daudé }
35888d7f2e76SPhilippe Mathieu-Daudé len -= l;
35898d7f2e76SPhilippe Mathieu-Daudé buf += l;
35908d7f2e76SPhilippe Mathieu-Daudé addr += l;
35918d7f2e76SPhilippe Mathieu-Daudé }
35928d7f2e76SPhilippe Mathieu-Daudé return 0;
35938d7f2e76SPhilippe Mathieu-Daudé }
35948d7f2e76SPhilippe Mathieu-Daudé
cpu_physical_memory_is_io(hwaddr phys_addr)35958d7f2e76SPhilippe Mathieu-Daudé bool cpu_physical_memory_is_io(hwaddr phys_addr)
35968d7f2e76SPhilippe Mathieu-Daudé {
35978d7f2e76SPhilippe Mathieu-Daudé MemoryRegion*mr;
35988d7f2e76SPhilippe Mathieu-Daudé hwaddr l = 1;
35998d7f2e76SPhilippe Mathieu-Daudé
36008d7f2e76SPhilippe Mathieu-Daudé RCU_READ_LOCK_GUARD();
36018d7f2e76SPhilippe Mathieu-Daudé mr = address_space_translate(&address_space_memory,
36028d7f2e76SPhilippe Mathieu-Daudé phys_addr, &phys_addr, &l, false,
36038d7f2e76SPhilippe Mathieu-Daudé MEMTXATTRS_UNSPECIFIED);
36048d7f2e76SPhilippe Mathieu-Daudé
36058d7f2e76SPhilippe Mathieu-Daudé return !(memory_region_is_ram(mr) || memory_region_is_romd(mr));
36068d7f2e76SPhilippe Mathieu-Daudé }
36078d7f2e76SPhilippe Mathieu-Daudé
qemu_ram_foreach_block(RAMBlockIterFunc func,void * opaque)36088d7f2e76SPhilippe Mathieu-Daudé int qemu_ram_foreach_block(RAMBlockIterFunc func, void *opaque)
36098d7f2e76SPhilippe Mathieu-Daudé {
36108d7f2e76SPhilippe Mathieu-Daudé RAMBlock *block;
36118d7f2e76SPhilippe Mathieu-Daudé int ret = 0;
36128d7f2e76SPhilippe Mathieu-Daudé
36138d7f2e76SPhilippe Mathieu-Daudé RCU_READ_LOCK_GUARD();
36148d7f2e76SPhilippe Mathieu-Daudé RAMBLOCK_FOREACH(block) {
36158d7f2e76SPhilippe Mathieu-Daudé ret = func(block, opaque);
36168d7f2e76SPhilippe Mathieu-Daudé if (ret) {
36178d7f2e76SPhilippe Mathieu-Daudé break;
36188d7f2e76SPhilippe Mathieu-Daudé }
36198d7f2e76SPhilippe Mathieu-Daudé }
36208d7f2e76SPhilippe Mathieu-Daudé return ret;
36218d7f2e76SPhilippe Mathieu-Daudé }
36228d7f2e76SPhilippe Mathieu-Daudé
36238d7f2e76SPhilippe Mathieu-Daudé /*
36248d7f2e76SPhilippe Mathieu-Daudé * Unmap pages of memory from start to start+length such that
36258d7f2e76SPhilippe Mathieu-Daudé * they a) read as 0, b) Trigger whatever fault mechanism
36268d7f2e76SPhilippe Mathieu-Daudé * the OS provides for postcopy.
36278d7f2e76SPhilippe Mathieu-Daudé * The pages must be unmapped by the end of the function.
36288d7f2e76SPhilippe Mathieu-Daudé * Returns: 0 on success, none-0 on failure
36298d7f2e76SPhilippe Mathieu-Daudé *
36308d7f2e76SPhilippe Mathieu-Daudé */
ram_block_discard_range(RAMBlock * rb,uint64_t start,size_t length)36318d7f2e76SPhilippe Mathieu-Daudé int ram_block_discard_range(RAMBlock *rb, uint64_t start, size_t length)
36328d7f2e76SPhilippe Mathieu-Daudé {
36338d7f2e76SPhilippe Mathieu-Daudé int ret = -1;
36348d7f2e76SPhilippe Mathieu-Daudé
36358d7f2e76SPhilippe Mathieu-Daudé uint8_t *host_startaddr = rb->host + start;
36368d7f2e76SPhilippe Mathieu-Daudé
36378d7f2e76SPhilippe Mathieu-Daudé if (!QEMU_PTR_IS_ALIGNED(host_startaddr, rb->page_size)) {
3638ea18be78SXiaoyao Li error_report("%s: Unaligned start address: %p",
3639ea18be78SXiaoyao Li __func__, host_startaddr);
36408d7f2e76SPhilippe Mathieu-Daudé goto err;
36418d7f2e76SPhilippe Mathieu-Daudé }
36428d7f2e76SPhilippe Mathieu-Daudé
36438d7f2e76SPhilippe Mathieu-Daudé if ((start + length) <= rb->max_length) {
36448d7f2e76SPhilippe Mathieu-Daudé bool need_madvise, need_fallocate;
36458d7f2e76SPhilippe Mathieu-Daudé if (!QEMU_IS_ALIGNED(length, rb->page_size)) {
3646ea18be78SXiaoyao Li error_report("%s: Unaligned length: %zx", __func__, length);
36478d7f2e76SPhilippe Mathieu-Daudé goto err;
36488d7f2e76SPhilippe Mathieu-Daudé }
36498d7f2e76SPhilippe Mathieu-Daudé
36508d7f2e76SPhilippe Mathieu-Daudé errno = ENOTSUP; /* If we are missing MADVISE etc */
36518d7f2e76SPhilippe Mathieu-Daudé
36528d7f2e76SPhilippe Mathieu-Daudé /* The logic here is messy;
36538d7f2e76SPhilippe Mathieu-Daudé * madvise DONTNEED fails for hugepages
36548d7f2e76SPhilippe Mathieu-Daudé * fallocate works on hugepages and shmem
36558d7f2e76SPhilippe Mathieu-Daudé * shared anonymous memory requires madvise REMOVE
36568d7f2e76SPhilippe Mathieu-Daudé */
365780c3aeefSRichard Henderson need_madvise = (rb->page_size == qemu_real_host_page_size());
36588d7f2e76SPhilippe Mathieu-Daudé need_fallocate = rb->fd != -1;
36598d7f2e76SPhilippe Mathieu-Daudé if (need_fallocate) {
36608d7f2e76SPhilippe Mathieu-Daudé /* For a file, this causes the area of the file to be zero'd
36618d7f2e76SPhilippe Mathieu-Daudé * if read, and for hugetlbfs also causes it to be unmapped
36628d7f2e76SPhilippe Mathieu-Daudé * so a userfault will trigger.
36638d7f2e76SPhilippe Mathieu-Daudé */
36648d7f2e76SPhilippe Mathieu-Daudé #ifdef CONFIG_FALLOCATE_PUNCH_HOLE
36658d7f2e76SPhilippe Mathieu-Daudé /*
36668d7f2e76SPhilippe Mathieu-Daudé * fallocate() will fail with readonly files. Let's print a
36678d7f2e76SPhilippe Mathieu-Daudé * proper error message.
36688d7f2e76SPhilippe Mathieu-Daudé */
36698d7f2e76SPhilippe Mathieu-Daudé if (rb->flags & RAM_READONLY_FD) {
3670ea18be78SXiaoyao Li error_report("%s: Discarding RAM with readonly files is not"
3671ea18be78SXiaoyao Li " supported", __func__);
36728d7f2e76SPhilippe Mathieu-Daudé goto err;
36738d7f2e76SPhilippe Mathieu-Daudé
36748d7f2e76SPhilippe Mathieu-Daudé }
36758d7f2e76SPhilippe Mathieu-Daudé /*
36768d7f2e76SPhilippe Mathieu-Daudé * We'll discard data from the actual file, even though we only
36778d7f2e76SPhilippe Mathieu-Daudé * have a MAP_PRIVATE mapping, possibly messing with other
36788d7f2e76SPhilippe Mathieu-Daudé * MAP_PRIVATE/MAP_SHARED mappings. There is no easy way to
36798d7f2e76SPhilippe Mathieu-Daudé * change that behavior whithout violating the promised
36808d7f2e76SPhilippe Mathieu-Daudé * semantics of ram_block_discard_range().
36818d7f2e76SPhilippe Mathieu-Daudé *
36828d7f2e76SPhilippe Mathieu-Daudé * Only warn, because it works as long as nobody else uses that
36838d7f2e76SPhilippe Mathieu-Daudé * file.
36848d7f2e76SPhilippe Mathieu-Daudé */
36858d7f2e76SPhilippe Mathieu-Daudé if (!qemu_ram_is_shared(rb)) {
3686ea18be78SXiaoyao Li warn_report_once("%s: Discarding RAM"
36878d7f2e76SPhilippe Mathieu-Daudé " in private file mappings is possibly"
36888d7f2e76SPhilippe Mathieu-Daudé " dangerous, because it will modify the"
36898d7f2e76SPhilippe Mathieu-Daudé " underlying file and will affect other"
3690ea18be78SXiaoyao Li " users of the file", __func__);
36918d7f2e76SPhilippe Mathieu-Daudé }
36928d7f2e76SPhilippe Mathieu-Daudé
36938d7f2e76SPhilippe Mathieu-Daudé ret = fallocate(rb->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
36948d7f2e76SPhilippe Mathieu-Daudé start, length);
36958d7f2e76SPhilippe Mathieu-Daudé if (ret) {
36968d7f2e76SPhilippe Mathieu-Daudé ret = -errno;
3697ea18be78SXiaoyao Li error_report("%s: Failed to fallocate %s:%" PRIx64 " +%zx (%d)",
3698ea18be78SXiaoyao Li __func__, rb->idstr, start, length, ret);
36998d7f2e76SPhilippe Mathieu-Daudé goto err;
37008d7f2e76SPhilippe Mathieu-Daudé }
37018d7f2e76SPhilippe Mathieu-Daudé #else
37028d7f2e76SPhilippe Mathieu-Daudé ret = -ENOSYS;
3703ea18be78SXiaoyao Li error_report("%s: fallocate not available/file"
37048d7f2e76SPhilippe Mathieu-Daudé "%s:%" PRIx64 " +%zx (%d)",
3705ea18be78SXiaoyao Li __func__, rb->idstr, start, length, ret);
37068d7f2e76SPhilippe Mathieu-Daudé goto err;
37078d7f2e76SPhilippe Mathieu-Daudé #endif
37088d7f2e76SPhilippe Mathieu-Daudé }
37098d7f2e76SPhilippe Mathieu-Daudé if (need_madvise) {
37108d7f2e76SPhilippe Mathieu-Daudé /* For normal RAM this causes it to be unmapped,
37118d7f2e76SPhilippe Mathieu-Daudé * for shared memory it causes the local mapping to disappear
37128d7f2e76SPhilippe Mathieu-Daudé * and to fall back on the file contents (which we just
37138d7f2e76SPhilippe Mathieu-Daudé * fallocate'd away).
37148d7f2e76SPhilippe Mathieu-Daudé */
37158d7f2e76SPhilippe Mathieu-Daudé #if defined(CONFIG_MADVISE)
37168d7f2e76SPhilippe Mathieu-Daudé if (qemu_ram_is_shared(rb) && rb->fd < 0) {
37178d7f2e76SPhilippe Mathieu-Daudé ret = madvise(host_startaddr, length, QEMU_MADV_REMOVE);
37188d7f2e76SPhilippe Mathieu-Daudé } else {
37198d7f2e76SPhilippe Mathieu-Daudé ret = madvise(host_startaddr, length, QEMU_MADV_DONTNEED);
37208d7f2e76SPhilippe Mathieu-Daudé }
37218d7f2e76SPhilippe Mathieu-Daudé if (ret) {
37228d7f2e76SPhilippe Mathieu-Daudé ret = -errno;
3723ea18be78SXiaoyao Li error_report("%s: Failed to discard range "
37248d7f2e76SPhilippe Mathieu-Daudé "%s:%" PRIx64 " +%zx (%d)",
3725ea18be78SXiaoyao Li __func__, rb->idstr, start, length, ret);
37268d7f2e76SPhilippe Mathieu-Daudé goto err;
37278d7f2e76SPhilippe Mathieu-Daudé }
37288d7f2e76SPhilippe Mathieu-Daudé #else
37298d7f2e76SPhilippe Mathieu-Daudé ret = -ENOSYS;
3730ea18be78SXiaoyao Li error_report("%s: MADVISE not available %s:%" PRIx64 " +%zx (%d)",
3731ea18be78SXiaoyao Li __func__, rb->idstr, start, length, ret);
37328d7f2e76SPhilippe Mathieu-Daudé goto err;
37338d7f2e76SPhilippe Mathieu-Daudé #endif
37348d7f2e76SPhilippe Mathieu-Daudé }
37358d7f2e76SPhilippe Mathieu-Daudé trace_ram_block_discard_range(rb->idstr, host_startaddr, length,
37368d7f2e76SPhilippe Mathieu-Daudé need_madvise, need_fallocate, ret);
37378d7f2e76SPhilippe Mathieu-Daudé } else {
3738ea18be78SXiaoyao Li error_report("%s: Overrun block '%s' (%" PRIu64 "/%zx/" RAM_ADDR_FMT")",
3739ea18be78SXiaoyao Li __func__, rb->idstr, start, length, rb->max_length);
37408d7f2e76SPhilippe Mathieu-Daudé }
37418d7f2e76SPhilippe Mathieu-Daudé
37428d7f2e76SPhilippe Mathieu-Daudé err:
37438d7f2e76SPhilippe Mathieu-Daudé return ret;
37448d7f2e76SPhilippe Mathieu-Daudé }
37458d7f2e76SPhilippe Mathieu-Daudé
ram_block_discard_guest_memfd_range(RAMBlock * rb,uint64_t start,size_t length)3746b2e9426cSXiaoyao Li int ram_block_discard_guest_memfd_range(RAMBlock *rb, uint64_t start,
3747b2e9426cSXiaoyao Li size_t length)
3748b2e9426cSXiaoyao Li {
3749b2e9426cSXiaoyao Li int ret = -1;
3750b2e9426cSXiaoyao Li
3751b2e9426cSXiaoyao Li #ifdef CONFIG_FALLOCATE_PUNCH_HOLE
3752b2e9426cSXiaoyao Li ret = fallocate(rb->guest_memfd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
3753b2e9426cSXiaoyao Li start, length);
3754b2e9426cSXiaoyao Li
3755b2e9426cSXiaoyao Li if (ret) {
3756b2e9426cSXiaoyao Li ret = -errno;
3757b2e9426cSXiaoyao Li error_report("%s: Failed to fallocate %s:%" PRIx64 " +%zx (%d)",
3758b2e9426cSXiaoyao Li __func__, rb->idstr, start, length, ret);
3759b2e9426cSXiaoyao Li }
3760b2e9426cSXiaoyao Li #else
3761b2e9426cSXiaoyao Li ret = -ENOSYS;
3762b2e9426cSXiaoyao Li error_report("%s: fallocate not available %s:%" PRIx64 " +%zx (%d)",
3763b2e9426cSXiaoyao Li __func__, rb->idstr, start, length, ret);
3764b2e9426cSXiaoyao Li #endif
3765b2e9426cSXiaoyao Li
3766b2e9426cSXiaoyao Li return ret;
3767b2e9426cSXiaoyao Li }
3768b2e9426cSXiaoyao Li
ramblock_is_pmem(RAMBlock * rb)37698d7f2e76SPhilippe Mathieu-Daudé bool ramblock_is_pmem(RAMBlock *rb)
37708d7f2e76SPhilippe Mathieu-Daudé {
37718d7f2e76SPhilippe Mathieu-Daudé return rb->flags & RAM_PMEM;
37728d7f2e76SPhilippe Mathieu-Daudé }
37738d7f2e76SPhilippe Mathieu-Daudé
mtree_print_phys_entries(int start,int end,int skip,int ptr)37748d7f2e76SPhilippe Mathieu-Daudé static void mtree_print_phys_entries(int start, int end, int skip, int ptr)
37758d7f2e76SPhilippe Mathieu-Daudé {
37768d7f2e76SPhilippe Mathieu-Daudé if (start == end - 1) {
37778d7f2e76SPhilippe Mathieu-Daudé qemu_printf("\t%3d ", start);
37788d7f2e76SPhilippe Mathieu-Daudé } else {
37798d7f2e76SPhilippe Mathieu-Daudé qemu_printf("\t%3d..%-3d ", start, end - 1);
37808d7f2e76SPhilippe Mathieu-Daudé }
37818d7f2e76SPhilippe Mathieu-Daudé qemu_printf(" skip=%d ", skip);
37828d7f2e76SPhilippe Mathieu-Daudé if (ptr == PHYS_MAP_NODE_NIL) {
37838d7f2e76SPhilippe Mathieu-Daudé qemu_printf(" ptr=NIL");
37848d7f2e76SPhilippe Mathieu-Daudé } else if (!skip) {
37858d7f2e76SPhilippe Mathieu-Daudé qemu_printf(" ptr=#%d", ptr);
37868d7f2e76SPhilippe Mathieu-Daudé } else {
37878d7f2e76SPhilippe Mathieu-Daudé qemu_printf(" ptr=[%d]", ptr);
37888d7f2e76SPhilippe Mathieu-Daudé }
37898d7f2e76SPhilippe Mathieu-Daudé qemu_printf("\n");
37908d7f2e76SPhilippe Mathieu-Daudé }
37918d7f2e76SPhilippe Mathieu-Daudé
37928d7f2e76SPhilippe Mathieu-Daudé #define MR_SIZE(size) (int128_nz(size) ? (hwaddr)int128_get64( \
37938d7f2e76SPhilippe Mathieu-Daudé int128_sub((size), int128_one())) : 0)
37948d7f2e76SPhilippe Mathieu-Daudé
mtree_print_dispatch(AddressSpaceDispatch * d,MemoryRegion * root)37958d7f2e76SPhilippe Mathieu-Daudé void mtree_print_dispatch(AddressSpaceDispatch *d, MemoryRegion *root)
37968d7f2e76SPhilippe Mathieu-Daudé {
37978d7f2e76SPhilippe Mathieu-Daudé int i;
37988d7f2e76SPhilippe Mathieu-Daudé
37998d7f2e76SPhilippe Mathieu-Daudé qemu_printf(" Dispatch\n");
38008d7f2e76SPhilippe Mathieu-Daudé qemu_printf(" Physical sections\n");
38018d7f2e76SPhilippe Mathieu-Daudé
38028d7f2e76SPhilippe Mathieu-Daudé for (i = 0; i < d->map.sections_nb; ++i) {
38038d7f2e76SPhilippe Mathieu-Daudé MemoryRegionSection *s = d->map.sections + i;
38048d7f2e76SPhilippe Mathieu-Daudé const char *names[] = { " [unassigned]", " [not dirty]",
38058d7f2e76SPhilippe Mathieu-Daudé " [ROM]", " [watch]" };
38068d7f2e76SPhilippe Mathieu-Daudé
38078d7f2e76SPhilippe Mathieu-Daudé qemu_printf(" #%d @" HWADDR_FMT_plx ".." HWADDR_FMT_plx
38088d7f2e76SPhilippe Mathieu-Daudé " %s%s%s%s%s",
38098d7f2e76SPhilippe Mathieu-Daudé i,
38108d7f2e76SPhilippe Mathieu-Daudé s->offset_within_address_space,
38118d7f2e76SPhilippe Mathieu-Daudé s->offset_within_address_space + MR_SIZE(s->size),
38128d7f2e76SPhilippe Mathieu-Daudé s->mr->name ? s->mr->name : "(noname)",
38138d7f2e76SPhilippe Mathieu-Daudé i < ARRAY_SIZE(names) ? names[i] : "",
38148d7f2e76SPhilippe Mathieu-Daudé s->mr == root ? " [ROOT]" : "",
38158d7f2e76SPhilippe Mathieu-Daudé s == d->mru_section ? " [MRU]" : "",
38168d7f2e76SPhilippe Mathieu-Daudé s->mr->is_iommu ? " [iommu]" : "");
38178d7f2e76SPhilippe Mathieu-Daudé
38188d7f2e76SPhilippe Mathieu-Daudé if (s->mr->alias) {
38198d7f2e76SPhilippe Mathieu-Daudé qemu_printf(" alias=%s", s->mr->alias->name ?
38208d7f2e76SPhilippe Mathieu-Daudé s->mr->alias->name : "noname");
38218d7f2e76SPhilippe Mathieu-Daudé }
38228d7f2e76SPhilippe Mathieu-Daudé qemu_printf("\n");
38238d7f2e76SPhilippe Mathieu-Daudé }
38248d7f2e76SPhilippe Mathieu-Daudé
38258d7f2e76SPhilippe Mathieu-Daudé qemu_printf(" Nodes (%d bits per level, %d levels) ptr=[%d] skip=%d\n",
38268d7f2e76SPhilippe Mathieu-Daudé P_L2_BITS, P_L2_LEVELS, d->phys_map.ptr, d->phys_map.skip);
38278d7f2e76SPhilippe Mathieu-Daudé for (i = 0; i < d->map.nodes_nb; ++i) {
38288d7f2e76SPhilippe Mathieu-Daudé int j, jprev;
38298d7f2e76SPhilippe Mathieu-Daudé PhysPageEntry prev;
38308d7f2e76SPhilippe Mathieu-Daudé Node *n = d->map.nodes + i;
38318d7f2e76SPhilippe Mathieu-Daudé
38328d7f2e76SPhilippe Mathieu-Daudé qemu_printf(" [%d]\n", i);
38338d7f2e76SPhilippe Mathieu-Daudé
38348d7f2e76SPhilippe Mathieu-Daudé for (j = 0, jprev = 0, prev = *n[0]; j < ARRAY_SIZE(*n); ++j) {
38358d7f2e76SPhilippe Mathieu-Daudé PhysPageEntry *pe = *n + j;
38368d7f2e76SPhilippe Mathieu-Daudé
38378d7f2e76SPhilippe Mathieu-Daudé if (pe->ptr == prev.ptr && pe->skip == prev.skip) {
38388d7f2e76SPhilippe Mathieu-Daudé continue;
38398d7f2e76SPhilippe Mathieu-Daudé }
38408d7f2e76SPhilippe Mathieu-Daudé
38418d7f2e76SPhilippe Mathieu-Daudé mtree_print_phys_entries(jprev, j, prev.skip, prev.ptr);
38428d7f2e76SPhilippe Mathieu-Daudé
38438d7f2e76SPhilippe Mathieu-Daudé jprev = j;
38448d7f2e76SPhilippe Mathieu-Daudé prev = *pe;
38458d7f2e76SPhilippe Mathieu-Daudé }
38468d7f2e76SPhilippe Mathieu-Daudé
38478d7f2e76SPhilippe Mathieu-Daudé if (jprev != ARRAY_SIZE(*n)) {
38488d7f2e76SPhilippe Mathieu-Daudé mtree_print_phys_entries(jprev, j, prev.skip, prev.ptr);
38498d7f2e76SPhilippe Mathieu-Daudé }
38508d7f2e76SPhilippe Mathieu-Daudé }
38518d7f2e76SPhilippe Mathieu-Daudé }
38528d7f2e76SPhilippe Mathieu-Daudé
38538d7f2e76SPhilippe Mathieu-Daudé /* Require any discards to work. */
38548d7f2e76SPhilippe Mathieu-Daudé static unsigned int ram_block_discard_required_cnt;
38558d7f2e76SPhilippe Mathieu-Daudé /* Require only coordinated discards to work. */
38568d7f2e76SPhilippe Mathieu-Daudé static unsigned int ram_block_coordinated_discard_required_cnt;
38578d7f2e76SPhilippe Mathieu-Daudé /* Disable any discards. */
38588d7f2e76SPhilippe Mathieu-Daudé static unsigned int ram_block_discard_disabled_cnt;
38598d7f2e76SPhilippe Mathieu-Daudé /* Disable only uncoordinated discards. */
38608d7f2e76SPhilippe Mathieu-Daudé static unsigned int ram_block_uncoordinated_discard_disabled_cnt;
38618d7f2e76SPhilippe Mathieu-Daudé static QemuMutex ram_block_discard_disable_mutex;
38628d7f2e76SPhilippe Mathieu-Daudé
ram_block_discard_disable_mutex_lock(void)38638d7f2e76SPhilippe Mathieu-Daudé static void ram_block_discard_disable_mutex_lock(void)
38648d7f2e76SPhilippe Mathieu-Daudé {
38658d7f2e76SPhilippe Mathieu-Daudé static gsize initialized;
38668d7f2e76SPhilippe Mathieu-Daudé
38678d7f2e76SPhilippe Mathieu-Daudé if (g_once_init_enter(&initialized)) {
38688d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_init(&ram_block_discard_disable_mutex);
38698d7f2e76SPhilippe Mathieu-Daudé g_once_init_leave(&initialized, 1);
38708d7f2e76SPhilippe Mathieu-Daudé }
38718d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_lock(&ram_block_discard_disable_mutex);
38728d7f2e76SPhilippe Mathieu-Daudé }
38738d7f2e76SPhilippe Mathieu-Daudé
ram_block_discard_disable_mutex_unlock(void)38748d7f2e76SPhilippe Mathieu-Daudé static void ram_block_discard_disable_mutex_unlock(void)
38758d7f2e76SPhilippe Mathieu-Daudé {
38768d7f2e76SPhilippe Mathieu-Daudé qemu_mutex_unlock(&ram_block_discard_disable_mutex);
38778d7f2e76SPhilippe Mathieu-Daudé }
38788d7f2e76SPhilippe Mathieu-Daudé
ram_block_discard_disable(bool state)38798d7f2e76SPhilippe Mathieu-Daudé int ram_block_discard_disable(bool state)
38808d7f2e76SPhilippe Mathieu-Daudé {
38818d7f2e76SPhilippe Mathieu-Daudé int ret = 0;
38828d7f2e76SPhilippe Mathieu-Daudé
38838d7f2e76SPhilippe Mathieu-Daudé ram_block_discard_disable_mutex_lock();
38848d7f2e76SPhilippe Mathieu-Daudé if (!state) {
38858d7f2e76SPhilippe Mathieu-Daudé ram_block_discard_disabled_cnt--;
38868d7f2e76SPhilippe Mathieu-Daudé } else if (ram_block_discard_required_cnt ||
38878d7f2e76SPhilippe Mathieu-Daudé ram_block_coordinated_discard_required_cnt) {
38888d7f2e76SPhilippe Mathieu-Daudé ret = -EBUSY;
38898d7f2e76SPhilippe Mathieu-Daudé } else {
38908d7f2e76SPhilippe Mathieu-Daudé ram_block_discard_disabled_cnt++;
38918d7f2e76SPhilippe Mathieu-Daudé }
38928d7f2e76SPhilippe Mathieu-Daudé ram_block_discard_disable_mutex_unlock();
38938d7f2e76SPhilippe Mathieu-Daudé return ret;
38948d7f2e76SPhilippe Mathieu-Daudé }
38958d7f2e76SPhilippe Mathieu-Daudé
ram_block_uncoordinated_discard_disable(bool state)38968d7f2e76SPhilippe Mathieu-Daudé int ram_block_uncoordinated_discard_disable(bool state)
38978d7f2e76SPhilippe Mathieu-Daudé {
38988d7f2e76SPhilippe Mathieu-Daudé int ret = 0;
38998d7f2e76SPhilippe Mathieu-Daudé
39008d7f2e76SPhilippe Mathieu-Daudé ram_block_discard_disable_mutex_lock();
39018d7f2e76SPhilippe Mathieu-Daudé if (!state) {
39028d7f2e76SPhilippe Mathieu-Daudé ram_block_uncoordinated_discard_disabled_cnt--;
39038d7f2e76SPhilippe Mathieu-Daudé } else if (ram_block_discard_required_cnt) {
39048d7f2e76SPhilippe Mathieu-Daudé ret = -EBUSY;
39058d7f2e76SPhilippe Mathieu-Daudé } else {
39068d7f2e76SPhilippe Mathieu-Daudé ram_block_uncoordinated_discard_disabled_cnt++;
39078d7f2e76SPhilippe Mathieu-Daudé }
39088d7f2e76SPhilippe Mathieu-Daudé ram_block_discard_disable_mutex_unlock();
39098d7f2e76SPhilippe Mathieu-Daudé return ret;
39108d7f2e76SPhilippe Mathieu-Daudé }
39118d7f2e76SPhilippe Mathieu-Daudé
ram_block_discard_require(bool state)39128d7f2e76SPhilippe Mathieu-Daudé int ram_block_discard_require(bool state)
39138d7f2e76SPhilippe Mathieu-Daudé {
39148d7f2e76SPhilippe Mathieu-Daudé int ret = 0;
39158d7f2e76SPhilippe Mathieu-Daudé
39168d7f2e76SPhilippe Mathieu-Daudé ram_block_discard_disable_mutex_lock();
39178d7f2e76SPhilippe Mathieu-Daudé if (!state) {
39188d7f2e76SPhilippe Mathieu-Daudé ram_block_discard_required_cnt--;
39198d7f2e76SPhilippe Mathieu-Daudé } else if (ram_block_discard_disabled_cnt ||
39208d7f2e76SPhilippe Mathieu-Daudé ram_block_uncoordinated_discard_disabled_cnt) {
39218d7f2e76SPhilippe Mathieu-Daudé ret = -EBUSY;
39228d7f2e76SPhilippe Mathieu-Daudé } else {
39238d7f2e76SPhilippe Mathieu-Daudé ram_block_discard_required_cnt++;
39248d7f2e76SPhilippe Mathieu-Daudé }
39258d7f2e76SPhilippe Mathieu-Daudé ram_block_discard_disable_mutex_unlock();
39268d7f2e76SPhilippe Mathieu-Daudé return ret;
39278d7f2e76SPhilippe Mathieu-Daudé }
39288d7f2e76SPhilippe Mathieu-Daudé
ram_block_coordinated_discard_require(bool state)39298d7f2e76SPhilippe Mathieu-Daudé int ram_block_coordinated_discard_require(bool state)
39308d7f2e76SPhilippe Mathieu-Daudé {
39318d7f2e76SPhilippe Mathieu-Daudé int ret = 0;
39328d7f2e76SPhilippe Mathieu-Daudé
39338d7f2e76SPhilippe Mathieu-Daudé ram_block_discard_disable_mutex_lock();
39348d7f2e76SPhilippe Mathieu-Daudé if (!state) {
39358d7f2e76SPhilippe Mathieu-Daudé ram_block_coordinated_discard_required_cnt--;
39368d7f2e76SPhilippe Mathieu-Daudé } else if (ram_block_discard_disabled_cnt) {
39378d7f2e76SPhilippe Mathieu-Daudé ret = -EBUSY;
39388d7f2e76SPhilippe Mathieu-Daudé } else {
39398d7f2e76SPhilippe Mathieu-Daudé ram_block_coordinated_discard_required_cnt++;
39408d7f2e76SPhilippe Mathieu-Daudé }
39418d7f2e76SPhilippe Mathieu-Daudé ram_block_discard_disable_mutex_unlock();
39428d7f2e76SPhilippe Mathieu-Daudé return ret;
39438d7f2e76SPhilippe Mathieu-Daudé }
39448d7f2e76SPhilippe Mathieu-Daudé
ram_block_discard_is_disabled(void)39458d7f2e76SPhilippe Mathieu-Daudé bool ram_block_discard_is_disabled(void)
39468d7f2e76SPhilippe Mathieu-Daudé {
39478d7f2e76SPhilippe Mathieu-Daudé return qatomic_read(&ram_block_discard_disabled_cnt) ||
39488d7f2e76SPhilippe Mathieu-Daudé qatomic_read(&ram_block_uncoordinated_discard_disabled_cnt);
39498d7f2e76SPhilippe Mathieu-Daudé }
39508d7f2e76SPhilippe Mathieu-Daudé
ram_block_discard_is_required(void)39518d7f2e76SPhilippe Mathieu-Daudé bool ram_block_discard_is_required(void)
39528d7f2e76SPhilippe Mathieu-Daudé {
39538d7f2e76SPhilippe Mathieu-Daudé return qatomic_read(&ram_block_discard_required_cnt) ||
39548d7f2e76SPhilippe Mathieu-Daudé qatomic_read(&ram_block_coordinated_discard_required_cnt);
39558d7f2e76SPhilippe Mathieu-Daudé }
3956