From e1a4e4208f4140c83c3742d1e606d8888d170424 Mon Sep 17 00:00:00 2001
From: Peter Maydell <peter.maydell@linaro.org>
Date: Sat, 17 Feb 2018 17:02:55 -0500
Subject: [PATCH] pc: resizeable ROM blocks

This makes ROM blocks resizeable. This infrastructure is required for other
functionality we have queued.

Backports commit aaf03019175949eda5087329448b8a0033b89479 from qemu
---
 include/qemu.h               |  16 +++-
 qemu/aarch64.h               |   3 +
 qemu/aarch64eb.h             |   3 +
 qemu/arm.h                   |   3 +
 qemu/armeb.h                 |   3 +
 qemu/exec.c                  | 142 +++++++++++++++++++++++++++--------
 qemu/header_gen.py           |   3 +
 qemu/include/exec/memory.h   |  26 +++++++
 qemu/include/exec/ram_addr.h |  10 ++-
 qemu/m68k.h                  |   3 +
 qemu/memory.c                |  19 +++++
 qemu/mips.h                  |   3 +
 qemu/mips64.h                |   3 +
 qemu/mips64el.h              |   3 +
 qemu/mipsel.h                |   3 +
 qemu/powerpc.h               |   3 +
 qemu/sparc.h                 |   3 +
 qemu/sparc64.h               |   3 +
 qemu/x86_64.h                |   3 +
 19 files changed, 217 insertions(+), 38 deletions(-)

diff --git a/include/qemu.h b/include/qemu.h
index 05ef07fb..cf4f0421 100644
--- a/include/qemu.h
+++ b/include/qemu.h
@@ -19,11 +19,14 @@ struct uc_struct;
 
 // This two struct is originally from qemu/include/exec/cpu-all.h
 // Temporarily moved here since there is circular inclusion.
-typedef struct RAMBlock {
+typedef struct RAMBlock RAMBlock;
+struct RAMBlock {
     struct MemoryRegion *mr;
     uint8_t *host;
     ram_addr_t offset;
-    ram_addr_t length;
+    ram_addr_t used_length;
+    ram_addr_t max_length;
+    void (*resized)(const char*, uint64_t length, void *host);
     uint32_t flags;
     char idstr[256];
     /* Reads can take either the iothread or the ramlist lock.
@@ -31,7 +34,14 @@ typedef struct RAMBlock {
      */
     QTAILQ_ENTRY(RAMBlock) next;
     int fd;
-} RAMBlock;
+};
+
+static inline void *ramblock_ptr(RAMBlock *block, ram_addr_t offset)
+{
+    assert(offset < block->used_length);
+    assert(block->host);
+    return (char *)block->host + offset;
+}
 
 typedef struct {
     MemoryRegion *mr;
diff --git a/qemu/aarch64.h b/qemu/aarch64.h
index eae340ed..e51f654a 100644
--- a/qemu/aarch64.h
+++ b/qemu/aarch64.h
@@ -2085,6 +2085,7 @@
 #define memory_region_init_ram memory_region_init_ram_aarch64
 #define memory_region_init_ram_ptr memory_region_init_ram_ptr_aarch64
 #define memory_region_init_reservation memory_region_init_reservation_aarch64
+#define memory_region_init_resizeable_ram memory_region_init_resizeable_ram_aarch64
 #define memory_region_is_iommu memory_region_is_iommu_aarch64
 #define memory_region_is_logging memory_region_is_logging_aarch64
 #define memory_region_is_mapped memory_region_is_mapped_aarch64
@@ -2434,11 +2435,13 @@
 #define qemu_ram_addr_from_host_nofail qemu_ram_addr_from_host_nofail_aarch64
 #define qemu_ram_alloc qemu_ram_alloc_aarch64
 #define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_aarch64
+#define qemu_ram_alloc_resizeable qemu_ram_alloc_resizeable_aarch64
 #define qemu_ram_foreach_block qemu_ram_foreach_block_aarch64
 #define qemu_ram_free qemu_ram_free_aarch64
 #define qemu_ram_free_from_ptr qemu_ram_free_from_ptr_aarch64
 #define qemu_ram_ptr_length qemu_ram_ptr_length_aarch64
 #define qemu_ram_remap qemu_ram_remap_aarch64
+#define qemu_ram_resize qemu_ram_resize_aarch64
 #define qemu_ram_setup_dump qemu_ram_setup_dump_aarch64
 #define qemu_ram_unset_idstr qemu_ram_unset_idstr_aarch64
 #define qemu_real_host_page_size qemu_real_host_page_size_aarch64
diff --git a/qemu/aarch64eb.h b/qemu/aarch64eb.h
index 3b004e73..c04abd4d 100644
--- a/qemu/aarch64eb.h
+++ b/qemu/aarch64eb.h
@@ -2085,6 +2085,7 @@
 #define memory_region_init_ram memory_region_init_ram_aarch64eb
 #define memory_region_init_ram_ptr memory_region_init_ram_ptr_aarch64eb
 #define memory_region_init_reservation memory_region_init_reservation_aarch64eb
+#define memory_region_init_resizeable_ram memory_region_init_resizeable_ram_aarch64eb
 #define memory_region_is_iommu memory_region_is_iommu_aarch64eb
 #define memory_region_is_logging memory_region_is_logging_aarch64eb
 #define memory_region_is_mapped memory_region_is_mapped_aarch64eb
@@ -2434,11 +2435,13 @@
 #define qemu_ram_addr_from_host_nofail qemu_ram_addr_from_host_nofail_aarch64eb
 #define qemu_ram_alloc qemu_ram_alloc_aarch64eb
 #define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_aarch64eb
+#define qemu_ram_alloc_resizeable qemu_ram_alloc_resizeable_aarch64eb
 #define qemu_ram_foreach_block qemu_ram_foreach_block_aarch64eb
 #define qemu_ram_free qemu_ram_free_aarch64eb
 #define qemu_ram_free_from_ptr qemu_ram_free_from_ptr_aarch64eb
 #define qemu_ram_ptr_length qemu_ram_ptr_length_aarch64eb
 #define qemu_ram_remap qemu_ram_remap_aarch64eb
+#define qemu_ram_resize qemu_ram_resize_aarch64eb
 #define qemu_ram_setup_dump qemu_ram_setup_dump_aarch64eb
 #define qemu_ram_unset_idstr qemu_ram_unset_idstr_aarch64eb
 #define qemu_real_host_page_size qemu_real_host_page_size_aarch64eb
diff --git a/qemu/arm.h b/qemu/arm.h
index 3d358a3c..52fe98f4 100644
--- a/qemu/arm.h
+++ b/qemu/arm.h
@@ -2085,6 +2085,7 @@
 #define memory_region_init_ram memory_region_init_ram_arm
 #define memory_region_init_ram_ptr memory_region_init_ram_ptr_arm
 #define memory_region_init_reservation memory_region_init_reservation_arm
+#define memory_region_init_resizeable_ram memory_region_init_resizeable_ram_arm
 #define memory_region_is_iommu memory_region_is_iommu_arm
 #define memory_region_is_logging memory_region_is_logging_arm
 #define memory_region_is_mapped memory_region_is_mapped_arm
@@ -2434,11 +2435,13 @@
 #define qemu_ram_addr_from_host_nofail qemu_ram_addr_from_host_nofail_arm
 #define qemu_ram_alloc qemu_ram_alloc_arm
 #define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_arm
+#define qemu_ram_alloc_resizeable qemu_ram_alloc_resizeable_arm
 #define qemu_ram_foreach_block qemu_ram_foreach_block_arm
 #define qemu_ram_free qemu_ram_free_arm
 #define qemu_ram_free_from_ptr qemu_ram_free_from_ptr_arm
 #define qemu_ram_ptr_length qemu_ram_ptr_length_arm
 #define qemu_ram_remap qemu_ram_remap_arm
+#define qemu_ram_resize qemu_ram_resize_arm
 #define qemu_ram_setup_dump qemu_ram_setup_dump_arm
 #define qemu_ram_unset_idstr qemu_ram_unset_idstr_arm
 #define qemu_real_host_page_size qemu_real_host_page_size_arm
diff --git a/qemu/armeb.h b/qemu/armeb.h
index a47d0579..ba4ff239 100644
--- a/qemu/armeb.h
+++ b/qemu/armeb.h
@@ -2085,6 +2085,7 @@
 #define memory_region_init_ram memory_region_init_ram_armeb
 #define memory_region_init_ram_ptr memory_region_init_ram_ptr_armeb
 #define memory_region_init_reservation memory_region_init_reservation_armeb
+#define memory_region_init_resizeable_ram memory_region_init_resizeable_ram_armeb
 #define memory_region_is_iommu memory_region_is_iommu_armeb
 #define memory_region_is_logging memory_region_is_logging_armeb
 #define memory_region_is_mapped memory_region_is_mapped_armeb
@@ -2434,11 +2435,13 @@
 #define qemu_ram_addr_from_host_nofail qemu_ram_addr_from_host_nofail_armeb
 #define qemu_ram_alloc qemu_ram_alloc_armeb
 #define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_armeb
+#define qemu_ram_alloc_resizeable qemu_ram_alloc_resizeable_armeb
 #define qemu_ram_foreach_block qemu_ram_foreach_block_armeb
 #define qemu_ram_free qemu_ram_free_armeb
 #define qemu_ram_free_from_ptr qemu_ram_free_from_ptr_armeb
 #define qemu_ram_ptr_length qemu_ram_ptr_length_armeb
 #define qemu_ram_remap qemu_ram_remap_armeb
+#define qemu_ram_resize qemu_ram_resize_armeb
 #define qemu_ram_setup_dump qemu_ram_setup_dump_armeb
 #define qemu_ram_unset_idstr qemu_ram_unset_idstr_armeb
 #define qemu_real_host_page_size qemu_real_host_page_size_armeb
diff --git a/qemu/exec.c b/qemu/exec.c
index c090198a..9e5af124 100644
--- a/qemu/exec.c
+++ b/qemu/exec.c
@@ -62,6 +62,11 @@
 /* RAM is mmap-ed with MAP_SHARED */
 #define RAM_SHARED     (1 << 1)
 
+/* Only a portion of RAM (used_length) is actually used, and migrated.
+ * This used_length size can change across reboots.
+ */
+#define RAM_RESIZEABLE (1 << 2)
+
 #endif
 
 #if !defined(CONFIG_USER_ONLY)
@@ -677,11 +682,11 @@ static RAMBlock *qemu_get_ram_block(struct uc_struct *uc, ram_addr_t addr)
 
     /* The list is protected by the iothread lock here.  */
     block = uc->ram_list.mru_block;
-    if (block && addr - block->offset < block->length) {
+    if (block && addr - block->offset < block->max_length) {
         goto found;
     }
     QTAILQ_FOREACH(block, &uc->ram_list.blocks, next) {
-        if (addr - block->offset < block->length) {
+        if (addr - block->offset < block->max_length) {
             goto found;
         }
     }
@@ -706,7 +711,7 @@ static void tlb_reset_dirty_range_all(struct uc_struct* uc,
 
     block = qemu_get_ram_block(uc, start);
     assert(block == qemu_get_ram_block(uc, end - 1));
-    start1 = (uintptr_t)block->host + (start - block->offset);
+    start1 = (uintptr_t)ramblock_ptr(block, start - block->offset);
     cpu_tlb_reset_dirty_all(uc, start1, length);
 }
 
@@ -931,7 +936,7 @@ static ram_addr_t find_ram_offset(struct uc_struct *uc, ram_addr_t size)
     QTAILQ_FOREACH(block, &uc->ram_list.blocks, next) {
         ram_addr_t end, next = RAM_ADDR_MAX;
 
-        end = block->offset + block->length;
+        end = block->offset + block->max_length;
 
         QTAILQ_FOREACH(next_block, &uc->ram_list.blocks, next) {
             if (next_block->offset >= end) {
@@ -959,7 +964,7 @@ ram_addr_t last_ram_offset(struct uc_struct *uc)
     ram_addr_t last = 0;
 
     QTAILQ_FOREACH(block, &uc->ram_list.blocks, next)
-        last = MAX(last, block->offset + block->length);
+        last = MAX(last, block->offset + block->max_length);
 
     return last;
 }
@@ -995,6 +1000,50 @@ static int memory_try_enable_merging(void *addr, size_t len)
     return 0;
 }
 
+/* Only legal before guest might have detected the memory size: e.g. on
+ * incoming migration, or right after reset.
+ *
+ * As memory core doesn't know how is memory accessed, it is up to
+ * resize callback to update device state and/or add assertions to detect
+ * misuse, if necessary.
+ */
+int qemu_ram_resize(struct uc_struct *uc, ram_addr_t base, ram_addr_t newsize, Error **errp)
+{
+    RAMBlock *block = find_ram_block(uc, base);
+
+    assert(block);
+
+    if (block->used_length == newsize) {
+        return 0;
+    }
+
+    if (!(block->flags & RAM_RESIZEABLE)) {
+        error_setg_errno(errp, EINVAL,
+                         "Length mismatch: %s: 0x" RAM_ADDR_FMT
+                         " in != 0x" RAM_ADDR_FMT, block->idstr,
+                         newsize, block->used_length);
+        return -EINVAL;
+    }
+
+    if (block->max_length < newsize) {
+        error_setg_errno(errp, EINVAL,
+                         "Length too large: %s: 0x" RAM_ADDR_FMT
+                         " > 0x" RAM_ADDR_FMT, block->idstr,
+                         newsize, block->max_length);
+        return -EINVAL;
+    }
+
+    cpu_physical_memory_clear_dirty_range(uc, block->offset, block->used_length);
+    block->used_length = newsize;
+    cpu_physical_memory_set_dirty_range(uc, block->offset, block->used_length,
+                                        DIRTY_CLIENTS_ALL);
+    memory_region_set_size(block->mr, newsize);
+    if (block->resized) {
+        block->resized(block->idstr, newsize, block->host);
+    }
+    return 0;
+}
+
 static ram_addr_t ram_block_add(struct uc_struct *uc, RAMBlock *new_block, Error **errp)
 {
     RAMBlock *block;
@@ -1002,23 +1051,23 @@ static ram_addr_t ram_block_add(struct uc_struct *uc, RAMBlock *new_block, Error
 
     old_ram_size = last_ram_offset(uc) >> TARGET_PAGE_BITS;
 
-    new_block->offset = find_ram_offset(uc, new_block->length);
+    new_block->offset = find_ram_offset(uc, new_block->max_length);
 
     if (!new_block->host) {
-        new_block->host = phys_mem_alloc(new_block->length,
-                &new_block->mr->align);
+        new_block->host = phys_mem_alloc(new_block->max_length,
+                                         &new_block->mr->align);
         if (!new_block->host) {
             error_setg_errno(errp, errno,
-                    "cannot set up guest memory '%s'",
-                    memory_region_name(new_block->mr));
+                             "cannot set up guest memory '%s'",
+                             memory_region_name(new_block->mr));
             return -1;
         }
-        memory_try_enable_merging(new_block->host, new_block->length);
+        memory_try_enable_merging(new_block->host, new_block->max_length);
     }
 
     /* Keep the list sorted from biggest to smallest block.  */
     QTAILQ_FOREACH(block, &uc->ram_list.blocks, next) {
-        if (block->length < new_block->length) {
+        if (block->max_length < new_block->max_length) {
             break;
         }
     }
@@ -1042,36 +1091,48 @@ static ram_addr_t ram_block_add(struct uc_struct *uc, RAMBlock *new_block, Error
         }
     }
     cpu_physical_memory_set_dirty_range(uc, new_block->offset,
-                                        new_block->length,
+                                        new_block->used_length,
                                         DIRTY_CLIENTS_ALL);
 
-    qemu_ram_setup_dump(new_block->host, new_block->length);
-    //qemu_madvise(new_block->host, new_block->length, QEMU_MADV_HUGEPAGE);
-    //qemu_madvise(new_block->host, new_block->length, QEMU_MADV_DONTFORK);
+    qemu_ram_setup_dump(new_block->host, new_block->max_length);
+    //qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_HUGEPAGE);
+    //qemu_madvise(new_block->host, new_block->max_length, QEMU_MADV_DONTFORK);
 
     return new_block->offset;
 }
 
 // return -1 on error
-ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
-        MemoryRegion *mr, Error **errp)
+static
+ram_addr_t qemu_ram_alloc_internal(ram_addr_t size, ram_addr_t max_size,
+                                   void (*resized)(const char*,
+                                                   uint64_t length,
+                                                   void *host),
+                                   void *host, bool resizeable,
+                                   MemoryRegion *mr, Error **errp)
 {
     RAMBlock *new_block;
     ram_addr_t addr;
     Error *local_err = NULL;
 
     size = TARGET_PAGE_ALIGN(size);
+    max_size = TARGET_PAGE_ALIGN(max_size);
     new_block = g_malloc0(sizeof(*new_block));
-    if (new_block == NULL)
+    if (new_block == NULL) {
         return -1;
-
+    }
     new_block->mr = mr;
-    new_block->length = size;
+    new_block->resized = resized;
+    new_block->used_length = size;
+    new_block->max_length = max_size;
+    assert(max_size >= size);
     new_block->fd = -1;
     new_block->host = host;
     if (host) {
         new_block->flags |= RAM_PREALLOC;
     }
+    if (resizeable) {
+        new_block->flags |= RAM_RESIZEABLE;
+    }
     addr = ram_block_add(mr->uc, new_block, &local_err);
     if (local_err) {
         g_free(new_block);
@@ -1081,9 +1142,24 @@ ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
     return addr;
 }
 
+ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
+                                   MemoryRegion *mr, Error **errp)
+{
+    return qemu_ram_alloc_internal(size, size, NULL, host, false, mr, errp);
+}
+
 ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr, Error **errp)
 {
-    return qemu_ram_alloc_from_ptr(size, NULL, mr, errp);
+    return qemu_ram_alloc_internal(size, size, NULL, NULL, false, mr, errp);
+}
+
+ram_addr_t 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)
+{
+    return qemu_ram_alloc_internal(size, maxsz, resized, NULL, true, mr, errp);
 }
 
 void qemu_ram_free_from_ptr(struct uc_struct *uc, ram_addr_t addr)
@@ -1114,11 +1190,11 @@ void qemu_ram_free(struct uc_struct *uc, ram_addr_t addr)
                 ;
 #ifndef _WIN32
             } else if (block->fd >= 0) {
-                munmap(block->host, block->length);
+                munmap(block->host, block->max_length);
                 close(block->fd);
 #endif
             } else {
-                qemu_anon_ram_free(block->host, block->length);
+                qemu_anon_ram_free(block->host, block->max_length);
             }
             g_free(block);
             break;
@@ -1136,8 +1212,8 @@ void qemu_ram_remap(struct uc_struct *uc, ram_addr_t addr, ram_addr_t length)
 
     QTAILQ_FOREACH(block, &uc->ram_list.blocks, next) {
         offset = addr - block->offset;
-        if (offset < block->length) {
-            vaddr = block->host + offset;
+        if (offset < block->max_length) {
+            vaddr = ramblock_ptr(block, offset);
             if (block->flags & RAM_PREALLOC) {
                 ;
             } else {
@@ -1214,10 +1290,10 @@ static void *qemu_ram_ptr_length(struct uc_struct *uc, ram_addr_t addr, hwaddr *
     }
 
     QTAILQ_FOREACH(block, &uc->ram_list.blocks, next) {
-        if (addr - block->offset < block->length) {
-            if (addr - block->offset + *size > block->length)
-                *size = block->length - addr + block->offset;
-            return block->host + (addr - block->offset);
+        if (addr - block->offset < block->max_length) {
+            if (addr - block->offset + *size > block->max_length)
+                *size = block->max_length - addr + block->offset;
+            return ramblock_ptr(block, addr - block->offset);
         }
     }
 
@@ -1233,7 +1309,7 @@ MemoryRegion *qemu_ram_addr_from_host(struct uc_struct *uc, void *ptr, ram_addr_
     uint8_t *host = ptr;
 
     block = uc->ram_list.mru_block;
-    if (block && block->host && host - block->host < block->length) {
+    if (block && block->host && host - block->host < block->max_length) {
         goto found;
     }
 
@@ -1242,7 +1318,7 @@ MemoryRegion *qemu_ram_addr_from_host(struct uc_struct *uc, void *ptr, ram_addr_
         if (block->host == NULL) {
             continue;
         }
-        if (host - block->host < block->length) {
+        if (host - block->host < block->max_length) {
             goto found;
         }
     }
@@ -2596,7 +2672,7 @@ void qemu_ram_foreach_block(struct uc_struct *uc, RAMBlockIterFunc func, void *o
     RAMBlock *block;
 
     QTAILQ_FOREACH(block, &uc->ram_list.blocks, next) {
-        func(block->host, block->offset, block->length, opaque);
+        func(block->host, block->offset, block->used_length, opaque);
     }
 }
 #endif
diff --git a/qemu/header_gen.py b/qemu/header_gen.py
index 8e917619..f1179ebc 100644
--- a/qemu/header_gen.py
+++ b/qemu/header_gen.py
@@ -2091,6 +2091,7 @@ symbols = (
     'memory_region_init_ram',
     'memory_region_init_ram_ptr',
     'memory_region_init_reservation',
+    'memory_region_init_resizeable_ram',
     'memory_region_is_iommu',
     'memory_region_is_logging',
     'memory_region_is_mapped',
@@ -2440,11 +2441,13 @@ symbols = (
     'qemu_ram_addr_from_host_nofail',
     'qemu_ram_alloc',
     'qemu_ram_alloc_from_ptr',
+    'qemu_ram_alloc_resizeable',
     'qemu_ram_foreach_block',
     'qemu_ram_free',
     'qemu_ram_free_from_ptr',
     'qemu_ram_ptr_length',
     'qemu_ram_remap',
+    'qemu_ram_resize',
     'qemu_ram_setup_dump',
     'qemu_ram_unset_idstr',
     'qemu_real_host_page_size',
diff --git a/qemu/include/exec/memory.h b/qemu/include/exec/memory.h
index 73dfabe1..a4627f29 100644
--- a/qemu/include/exec/memory.h
+++ b/qemu/include/exec/memory.h
@@ -395,6 +395,32 @@ void memory_region_init_rom_device(MemoryRegion *mr,
                                    uint64_t size,
                                    Error **errp);
 
+/**
+ * memory_region_init_resizeable_ram:  Initialize memory region with resizeable
+ *                                     RAM.  Accesses into the region will
+ *                                     modify memory directly.  Only an initial
+ *                                     portion of this RAM is actually used.
+ *                                     The used size can change across reboots.
+ *
+ * @mr: the #MemoryRegion to be initialized.
+ * @owner: the object that tracks the region's reference count
+ * @name: the name of the region.
+ * @size: used size of the region.
+ * @max_size: max size of the region.
+ * @resized: callback to notify owner about used size change.
+ * @errp: pointer to Error*, to store an error if it happens.
+ */
+void memory_region_init_resizeable_ram(struct uc_struct *uc,
+                                       MemoryRegion *mr,
+                                       struct Object *owner,
+                                       const char *name,
+                                       uint64_t size,
+                                       uint64_t max_size,
+                                       void (*resized)(const char*,
+                                                       uint64_t length,
+                                                       void *host),
+                                       Error **errp);
+
 /**
  * memory_region_init_reservation: Initialize a memory region that reserves
  *                                 I/O space.
diff --git a/qemu/include/exec/ram_addr.h b/qemu/include/exec/ram_addr.h
index 5453aa35..34791d70 100644
--- a/qemu/include/exec/ram_addr.h
+++ b/qemu/include/exec/ram_addr.h
@@ -26,12 +26,19 @@
 ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
                                    MemoryRegion *mr, Error **errp);
 ram_addr_t qemu_ram_alloc(ram_addr_t size, MemoryRegion *mr, Error **errp);
+ram_addr_t qemu_ram_alloc_resizeable(ram_addr_t size, ram_addr_t max_size,
+                                     void (*resized)(const char*,
+                                                     uint64_t length,
+                                                     void *host),
+                                     MemoryRegion *mr, Error **errp);
 int qemu_get_ram_fd(struct uc_struct *uc, ram_addr_t addr);
 void *qemu_get_ram_block_host_ptr(struct uc_struct *uc, ram_addr_t addr);
 void *qemu_get_ram_ptr(struct uc_struct *uc, ram_addr_t addr);
 void qemu_ram_free(struct uc_struct *c, ram_addr_t addr);
 void qemu_ram_free_from_ptr(struct uc_struct *uc, ram_addr_t addr);
 
+int qemu_ram_resize(struct uc_struct *c, ram_addr_t base, ram_addr_t newsize, Error **errp);
+
 #define DIRTY_CLIENTS_ALL     ((1 << DIRTY_MEMORY_NUM) - 1)
 #define DIRTY_CLIENTS_NOCODE  (DIRTY_CLIENTS_ALL & ~(1 << DIRTY_MEMORY_CODE))
 
@@ -169,8 +176,7 @@ bool cpu_physical_memory_test_and_clear_dirty(struct uc_struct *uc,
                                               unsigned client);
 
 static inline void cpu_physical_memory_clear_dirty_range(struct uc_struct *uc, ram_addr_t start,
-                                                         ram_addr_t length,
-                                                         unsigned client)
+                                                         ram_addr_t length)
 {
     cpu_physical_memory_test_and_clear_dirty(uc, start, length, DIRTY_MEMORY_CODE);
 }
diff --git a/qemu/m68k.h b/qemu/m68k.h
index 47ab4d52..54f14515 100644
--- a/qemu/m68k.h
+++ b/qemu/m68k.h
@@ -2085,6 +2085,7 @@
 #define memory_region_init_ram memory_region_init_ram_m68k
 #define memory_region_init_ram_ptr memory_region_init_ram_ptr_m68k
 #define memory_region_init_reservation memory_region_init_reservation_m68k
+#define memory_region_init_resizeable_ram memory_region_init_resizeable_ram_m68k
 #define memory_region_is_iommu memory_region_is_iommu_m68k
 #define memory_region_is_logging memory_region_is_logging_m68k
 #define memory_region_is_mapped memory_region_is_mapped_m68k
@@ -2434,11 +2435,13 @@
 #define qemu_ram_addr_from_host_nofail qemu_ram_addr_from_host_nofail_m68k
 #define qemu_ram_alloc qemu_ram_alloc_m68k
 #define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_m68k
+#define qemu_ram_alloc_resizeable qemu_ram_alloc_resizeable_m68k
 #define qemu_ram_foreach_block qemu_ram_foreach_block_m68k
 #define qemu_ram_free qemu_ram_free_m68k
 #define qemu_ram_free_from_ptr qemu_ram_free_from_ptr_m68k
 #define qemu_ram_ptr_length qemu_ram_ptr_length_m68k
 #define qemu_ram_remap qemu_ram_remap_m68k
+#define qemu_ram_resize qemu_ram_resize_m68k
 #define qemu_ram_setup_dump qemu_ram_setup_dump_m68k
 #define qemu_ram_unset_idstr qemu_ram_unset_idstr_m68k
 #define qemu_real_host_page_size qemu_real_host_page_size_m68k
diff --git a/qemu/memory.c b/qemu/memory.c
index 7fe2db50..6a614798 100644
--- a/qemu/memory.c
+++ b/qemu/memory.c
@@ -1186,6 +1186,25 @@ void memory_region_init_ram_ptr(struct uc_struct *uc, MemoryRegion *mr,
     mr->ram_addr = qemu_ram_alloc_from_ptr(size, ptr, mr, &error_abort);
 }
 
+void memory_region_init_resizeable_ram(struct uc_struct *uc,
+                                       MemoryRegion *mr,
+                                       Object *owner,
+                                       const char *name,
+                                       uint64_t size,
+                                       uint64_t max_size,
+                                       void (*resized)(const char*,
+                                                       uint64_t length,
+                                                       void *host),
+                                       Error **errp)
+{
+    memory_region_init(uc, mr, owner, name, size);
+    mr->ram = true;
+    mr->terminates = true;
+    mr->destructor = memory_region_destructor_ram;
+    mr->ram_addr = qemu_ram_alloc_resizeable(size, max_size, resized, mr, errp);
+    mr->dirty_log_mask = tcg_enabled(uc) ? (1 << DIRTY_MEMORY_CODE) : 0;
+}
+
 void memory_region_set_skip_dump(MemoryRegion *mr)
 {
     mr->skip_dump = true;
diff --git a/qemu/mips.h b/qemu/mips.h
index 63570e07..aada73d9 100644
--- a/qemu/mips.h
+++ b/qemu/mips.h
@@ -2085,6 +2085,7 @@
 #define memory_region_init_ram memory_region_init_ram_mips
 #define memory_region_init_ram_ptr memory_region_init_ram_ptr_mips
 #define memory_region_init_reservation memory_region_init_reservation_mips
+#define memory_region_init_resizeable_ram memory_region_init_resizeable_ram_mips
 #define memory_region_is_iommu memory_region_is_iommu_mips
 #define memory_region_is_logging memory_region_is_logging_mips
 #define memory_region_is_mapped memory_region_is_mapped_mips
@@ -2434,11 +2435,13 @@
 #define qemu_ram_addr_from_host_nofail qemu_ram_addr_from_host_nofail_mips
 #define qemu_ram_alloc qemu_ram_alloc_mips
 #define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_mips
+#define qemu_ram_alloc_resizeable qemu_ram_alloc_resizeable_mips
 #define qemu_ram_foreach_block qemu_ram_foreach_block_mips
 #define qemu_ram_free qemu_ram_free_mips
 #define qemu_ram_free_from_ptr qemu_ram_free_from_ptr_mips
 #define qemu_ram_ptr_length qemu_ram_ptr_length_mips
 #define qemu_ram_remap qemu_ram_remap_mips
+#define qemu_ram_resize qemu_ram_resize_mips
 #define qemu_ram_setup_dump qemu_ram_setup_dump_mips
 #define qemu_ram_unset_idstr qemu_ram_unset_idstr_mips
 #define qemu_real_host_page_size qemu_real_host_page_size_mips
diff --git a/qemu/mips64.h b/qemu/mips64.h
index f0ee34c1..cad2cd26 100644
--- a/qemu/mips64.h
+++ b/qemu/mips64.h
@@ -2085,6 +2085,7 @@
 #define memory_region_init_ram memory_region_init_ram_mips64
 #define memory_region_init_ram_ptr memory_region_init_ram_ptr_mips64
 #define memory_region_init_reservation memory_region_init_reservation_mips64
+#define memory_region_init_resizeable_ram memory_region_init_resizeable_ram_mips64
 #define memory_region_is_iommu memory_region_is_iommu_mips64
 #define memory_region_is_logging memory_region_is_logging_mips64
 #define memory_region_is_mapped memory_region_is_mapped_mips64
@@ -2434,11 +2435,13 @@
 #define qemu_ram_addr_from_host_nofail qemu_ram_addr_from_host_nofail_mips64
 #define qemu_ram_alloc qemu_ram_alloc_mips64
 #define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_mips64
+#define qemu_ram_alloc_resizeable qemu_ram_alloc_resizeable_mips64
 #define qemu_ram_foreach_block qemu_ram_foreach_block_mips64
 #define qemu_ram_free qemu_ram_free_mips64
 #define qemu_ram_free_from_ptr qemu_ram_free_from_ptr_mips64
 #define qemu_ram_ptr_length qemu_ram_ptr_length_mips64
 #define qemu_ram_remap qemu_ram_remap_mips64
+#define qemu_ram_resize qemu_ram_resize_mips64
 #define qemu_ram_setup_dump qemu_ram_setup_dump_mips64
 #define qemu_ram_unset_idstr qemu_ram_unset_idstr_mips64
 #define qemu_real_host_page_size qemu_real_host_page_size_mips64
diff --git a/qemu/mips64el.h b/qemu/mips64el.h
index c0db6e31..bda5fe07 100644
--- a/qemu/mips64el.h
+++ b/qemu/mips64el.h
@@ -2085,6 +2085,7 @@
 #define memory_region_init_ram memory_region_init_ram_mips64el
 #define memory_region_init_ram_ptr memory_region_init_ram_ptr_mips64el
 #define memory_region_init_reservation memory_region_init_reservation_mips64el
+#define memory_region_init_resizeable_ram memory_region_init_resizeable_ram_mips64el
 #define memory_region_is_iommu memory_region_is_iommu_mips64el
 #define memory_region_is_logging memory_region_is_logging_mips64el
 #define memory_region_is_mapped memory_region_is_mapped_mips64el
@@ -2434,11 +2435,13 @@
 #define qemu_ram_addr_from_host_nofail qemu_ram_addr_from_host_nofail_mips64el
 #define qemu_ram_alloc qemu_ram_alloc_mips64el
 #define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_mips64el
+#define qemu_ram_alloc_resizeable qemu_ram_alloc_resizeable_mips64el
 #define qemu_ram_foreach_block qemu_ram_foreach_block_mips64el
 #define qemu_ram_free qemu_ram_free_mips64el
 #define qemu_ram_free_from_ptr qemu_ram_free_from_ptr_mips64el
 #define qemu_ram_ptr_length qemu_ram_ptr_length_mips64el
 #define qemu_ram_remap qemu_ram_remap_mips64el
+#define qemu_ram_resize qemu_ram_resize_mips64el
 #define qemu_ram_setup_dump qemu_ram_setup_dump_mips64el
 #define qemu_ram_unset_idstr qemu_ram_unset_idstr_mips64el
 #define qemu_real_host_page_size qemu_real_host_page_size_mips64el
diff --git a/qemu/mipsel.h b/qemu/mipsel.h
index ea39989f..9dc605c3 100644
--- a/qemu/mipsel.h
+++ b/qemu/mipsel.h
@@ -2085,6 +2085,7 @@
 #define memory_region_init_ram memory_region_init_ram_mipsel
 #define memory_region_init_ram_ptr memory_region_init_ram_ptr_mipsel
 #define memory_region_init_reservation memory_region_init_reservation_mipsel
+#define memory_region_init_resizeable_ram memory_region_init_resizeable_ram_mipsel
 #define memory_region_is_iommu memory_region_is_iommu_mipsel
 #define memory_region_is_logging memory_region_is_logging_mipsel
 #define memory_region_is_mapped memory_region_is_mapped_mipsel
@@ -2434,11 +2435,13 @@
 #define qemu_ram_addr_from_host_nofail qemu_ram_addr_from_host_nofail_mipsel
 #define qemu_ram_alloc qemu_ram_alloc_mipsel
 #define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_mipsel
+#define qemu_ram_alloc_resizeable qemu_ram_alloc_resizeable_mipsel
 #define qemu_ram_foreach_block qemu_ram_foreach_block_mipsel
 #define qemu_ram_free qemu_ram_free_mipsel
 #define qemu_ram_free_from_ptr qemu_ram_free_from_ptr_mipsel
 #define qemu_ram_ptr_length qemu_ram_ptr_length_mipsel
 #define qemu_ram_remap qemu_ram_remap_mipsel
+#define qemu_ram_resize qemu_ram_resize_mipsel
 #define qemu_ram_setup_dump qemu_ram_setup_dump_mipsel
 #define qemu_ram_unset_idstr qemu_ram_unset_idstr_mipsel
 #define qemu_real_host_page_size qemu_real_host_page_size_mipsel
diff --git a/qemu/powerpc.h b/qemu/powerpc.h
index ea2c1054..33ad67b6 100644
--- a/qemu/powerpc.h
+++ b/qemu/powerpc.h
@@ -2085,6 +2085,7 @@
 #define memory_region_init_ram memory_region_init_ram_powerpc
 #define memory_region_init_ram_ptr memory_region_init_ram_ptr_powerpc
 #define memory_region_init_reservation memory_region_init_reservation_powerpc
+#define memory_region_init_resizeable_ram memory_region_init_resizeable_ram_powerpc
 #define memory_region_is_iommu memory_region_is_iommu_powerpc
 #define memory_region_is_logging memory_region_is_logging_powerpc
 #define memory_region_is_mapped memory_region_is_mapped_powerpc
@@ -2434,11 +2435,13 @@
 #define qemu_ram_addr_from_host_nofail qemu_ram_addr_from_host_nofail_powerpc
 #define qemu_ram_alloc qemu_ram_alloc_powerpc
 #define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_powerpc
+#define qemu_ram_alloc_resizeable qemu_ram_alloc_resizeable_powerpc
 #define qemu_ram_foreach_block qemu_ram_foreach_block_powerpc
 #define qemu_ram_free qemu_ram_free_powerpc
 #define qemu_ram_free_from_ptr qemu_ram_free_from_ptr_powerpc
 #define qemu_ram_ptr_length qemu_ram_ptr_length_powerpc
 #define qemu_ram_remap qemu_ram_remap_powerpc
+#define qemu_ram_resize qemu_ram_resize_powerpc
 #define qemu_ram_setup_dump qemu_ram_setup_dump_powerpc
 #define qemu_ram_unset_idstr qemu_ram_unset_idstr_powerpc
 #define qemu_real_host_page_size qemu_real_host_page_size_powerpc
diff --git a/qemu/sparc.h b/qemu/sparc.h
index 7774c8a1..4f7437b2 100644
--- a/qemu/sparc.h
+++ b/qemu/sparc.h
@@ -2085,6 +2085,7 @@
 #define memory_region_init_ram memory_region_init_ram_sparc
 #define memory_region_init_ram_ptr memory_region_init_ram_ptr_sparc
 #define memory_region_init_reservation memory_region_init_reservation_sparc
+#define memory_region_init_resizeable_ram memory_region_init_resizeable_ram_sparc
 #define memory_region_is_iommu memory_region_is_iommu_sparc
 #define memory_region_is_logging memory_region_is_logging_sparc
 #define memory_region_is_mapped memory_region_is_mapped_sparc
@@ -2434,11 +2435,13 @@
 #define qemu_ram_addr_from_host_nofail qemu_ram_addr_from_host_nofail_sparc
 #define qemu_ram_alloc qemu_ram_alloc_sparc
 #define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_sparc
+#define qemu_ram_alloc_resizeable qemu_ram_alloc_resizeable_sparc
 #define qemu_ram_foreach_block qemu_ram_foreach_block_sparc
 #define qemu_ram_free qemu_ram_free_sparc
 #define qemu_ram_free_from_ptr qemu_ram_free_from_ptr_sparc
 #define qemu_ram_ptr_length qemu_ram_ptr_length_sparc
 #define qemu_ram_remap qemu_ram_remap_sparc
+#define qemu_ram_resize qemu_ram_resize_sparc
 #define qemu_ram_setup_dump qemu_ram_setup_dump_sparc
 #define qemu_ram_unset_idstr qemu_ram_unset_idstr_sparc
 #define qemu_real_host_page_size qemu_real_host_page_size_sparc
diff --git a/qemu/sparc64.h b/qemu/sparc64.h
index 2ddfde3f..4347750e 100644
--- a/qemu/sparc64.h
+++ b/qemu/sparc64.h
@@ -2085,6 +2085,7 @@
 #define memory_region_init_ram memory_region_init_ram_sparc64
 #define memory_region_init_ram_ptr memory_region_init_ram_ptr_sparc64
 #define memory_region_init_reservation memory_region_init_reservation_sparc64
+#define memory_region_init_resizeable_ram memory_region_init_resizeable_ram_sparc64
 #define memory_region_is_iommu memory_region_is_iommu_sparc64
 #define memory_region_is_logging memory_region_is_logging_sparc64
 #define memory_region_is_mapped memory_region_is_mapped_sparc64
@@ -2434,11 +2435,13 @@
 #define qemu_ram_addr_from_host_nofail qemu_ram_addr_from_host_nofail_sparc64
 #define qemu_ram_alloc qemu_ram_alloc_sparc64
 #define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_sparc64
+#define qemu_ram_alloc_resizeable qemu_ram_alloc_resizeable_sparc64
 #define qemu_ram_foreach_block qemu_ram_foreach_block_sparc64
 #define qemu_ram_free qemu_ram_free_sparc64
 #define qemu_ram_free_from_ptr qemu_ram_free_from_ptr_sparc64
 #define qemu_ram_ptr_length qemu_ram_ptr_length_sparc64
 #define qemu_ram_remap qemu_ram_remap_sparc64
+#define qemu_ram_resize qemu_ram_resize_sparc64
 #define qemu_ram_setup_dump qemu_ram_setup_dump_sparc64
 #define qemu_ram_unset_idstr qemu_ram_unset_idstr_sparc64
 #define qemu_real_host_page_size qemu_real_host_page_size_sparc64
diff --git a/qemu/x86_64.h b/qemu/x86_64.h
index 41723893..6766b97f 100644
--- a/qemu/x86_64.h
+++ b/qemu/x86_64.h
@@ -2085,6 +2085,7 @@
 #define memory_region_init_ram memory_region_init_ram_x86_64
 #define memory_region_init_ram_ptr memory_region_init_ram_ptr_x86_64
 #define memory_region_init_reservation memory_region_init_reservation_x86_64
+#define memory_region_init_resizeable_ram memory_region_init_resizeable_ram_x86_64
 #define memory_region_is_iommu memory_region_is_iommu_x86_64
 #define memory_region_is_logging memory_region_is_logging_x86_64
 #define memory_region_is_mapped memory_region_is_mapped_x86_64
@@ -2434,11 +2435,13 @@
 #define qemu_ram_addr_from_host_nofail qemu_ram_addr_from_host_nofail_x86_64
 #define qemu_ram_alloc qemu_ram_alloc_x86_64
 #define qemu_ram_alloc_from_ptr qemu_ram_alloc_from_ptr_x86_64
+#define qemu_ram_alloc_resizeable qemu_ram_alloc_resizeable_x86_64
 #define qemu_ram_foreach_block qemu_ram_foreach_block_x86_64
 #define qemu_ram_free qemu_ram_free_x86_64
 #define qemu_ram_free_from_ptr qemu_ram_free_from_ptr_x86_64
 #define qemu_ram_ptr_length qemu_ram_ptr_length_x86_64
 #define qemu_ram_remap qemu_ram_remap_x86_64
+#define qemu_ram_resize qemu_ram_resize_x86_64
 #define qemu_ram_setup_dump qemu_ram_setup_dump_x86_64
 #define qemu_ram_unset_idstr qemu_ram_unset_idstr_x86_64
 #define qemu_real_host_page_size qemu_real_host_page_size_x86_64