All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/6] Implement memory_region_new_* functions
@ 2026-02-10 20:02 BALATON Zoltan
  2026-02-10 20:02 ` [PATCH v3 1/6] memory: Add memory_region_new* functions BALATON Zoltan
                   ` (7 more replies)
  0 siblings, 8 replies; 14+ messages in thread
From: BALATON Zoltan @ 2026-02-10 20:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, Mark Cave-Ayland,
	Gerd Hoffmann, Max Filippov, Peter Maydell,
	Philippe Mathieu-Daudé

Our documentation says that memory regions are automatically freed
when the owner dies and the reference counting to do this is also
implemented. However this relies on the QOM free funtion that can only
be set by creating objects with object_new but memory API only
provides constructors that call object_initialize which clears the
free function that prevents QOM to manage the memory region lifetime.
Implement corresponding memory_region_new_* functions that do the same
as the memory_region_init_* functions but create the memory region
with object_new so the lifetime can be automatically managed by QOM as
documented. The memory_region_init functions are kept because they are
useful for memory regions embedded in other object or managed
externally and not by QOM for some reason.

v3:
Based-on: <cover.1770753117.git.balaton@eik.bme.hu>
- convert xtfpga from nomigrate as this has no migration compatibility
issue

v2:
- rebase on master
- update documentation
- use these function to fix some leaks (there may be more, e.g. in
hw/pci-host/bonito but I leave that for later and/or others)

BALATON Zoltan (6):
  memory: Add memory_region_new* functions
  memory: Update documentation for memory_region_new*()
  hw/ide/sii3112: Use memory_region_new to avoid leaking regions
  hw/pci-host/articia: Map PCI memory windows in realize
  hw/pci-host/articia: Add variable for common type cast
  hw/xtensa/xtfpga: Fix leaking memory region

 docs/devel/memory.rst   |  21 ++---
 hw/ide/sii3112.c        |  30 +++----
 hw/pci-host/articia.c   |  22 +++--
 hw/ppc/amigaone.c       |  28 ++-----
 hw/ppc/pegasos.c        |  13 ---
 hw/xtensa/xtfpga.c      |   7 +-
 include/system/memory.h | 179 +++++++++++++++++++++++++++++++++++++++
 system/memory.c         | 181 ++++++++++++++++++++++++++++++++++++++++
 8 files changed, 407 insertions(+), 74 deletions(-)

-- 
2.41.3



^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v3 1/6] memory: Add memory_region_new* functions
  2026-02-10 20:02 [PATCH v3 0/6] Implement memory_region_new_* functions BALATON Zoltan
@ 2026-02-10 20:02 ` BALATON Zoltan
  2026-02-10 20:02 ` [PATCH v3 2/6] memory: Update documentation for memory_region_new*() BALATON Zoltan
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: BALATON Zoltan @ 2026-02-10 20:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, Mark Cave-Ayland,
	Gerd Hoffmann, Max Filippov, Peter Maydell,
	Philippe Mathieu-Daudé

These are counterparts of similar memory_region_init* functions but
differ in that these allocate the memory region with object_new so the
memory region will be managed by QOM and freed with the owner. This
behaviour was already documented and the reference tracking is
implemented but it could not be used without these functions because
memory_region_init* functions call object_initialize that clears the
free function of the object so it would not be freed.

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---
 include/system/memory.h |  81 ++++++++++++++++++
 system/memory.c         | 181 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 262 insertions(+)

diff --git a/include/system/memory.h b/include/system/memory.h
index d4793a08a7..ab76433c54 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -1324,6 +1324,10 @@ void memory_region_init(MemoryRegion *mr,
                         const char *name,
                         uint64_t size);
 
+MemoryRegion *memory_region_new(Object *owner,
+                                const char *name,
+                                uint64_t size);
+
 /**
  * memory_region_ref: Add 1 to a memory region's reference count
  *
@@ -1374,6 +1378,12 @@ void memory_region_init_io(MemoryRegion *mr,
                            const char *name,
                            uint64_t size);
 
+MemoryRegion *memory_region_new_io(Object *owner,
+                                   const MemoryRegionOps *ops,
+                                   void *opaque,
+                                   const char *name,
+                                   uint64_t size);
+
 /**
  * memory_region_init_ram_flags_nomigrate:  Initialize RAM memory region.
  *                                          Accesses into the region will
@@ -1400,6 +1410,12 @@ bool memory_region_init_ram_flags_nomigrate(MemoryRegion *mr,
                                             uint32_t ram_flags,
                                             Error **errp);
 
+MemoryRegion *memory_region_new_ram_flags_nomigrate(Object *owner,
+                                                    const char *name,
+                                                    uint64_t size,
+                                                    uint32_t ram_flags,
+                                                    Error **errp);
+
 /**
  * memory_region_init_resizeable_ram:  Initialize memory region with resizable
  *                                     RAM.  Accesses into the region will
@@ -1432,6 +1448,16 @@ bool memory_region_init_resizeable_ram(MemoryRegion *mr,
                                                        uint64_t length,
                                                        void *host),
                                        Error **errp);
+
+MemoryRegion *memory_region_new_resizeable_ram(Object *owner,
+                                               const char *name,
+                                               uint64_t size,
+                                               uint64_t max_size,
+                                               void (*resized)(const char*,
+                                                               uint64_t length,
+                                                               void *host),
+                                               Error **errp);
+
 #ifdef CONFIG_POSIX
 
 /**
@@ -1467,6 +1493,15 @@ bool memory_region_init_ram_from_file(MemoryRegion *mr,
                                       ram_addr_t offset,
                                       Error **errp);
 
+MemoryRegion *memory_region_new_ram_from_file(Object *owner,
+                                              const char *name,
+                                              uint64_t size,
+                                              uint64_t align,
+                                              uint32_t ram_flags,
+                                              const char *path,
+                                              ram_addr_t offset,
+                                              Error **errp);
+
 /**
  * memory_region_init_ram_from_fd:  Initialize RAM memory region with a
  *                                  mmap-ed backend.
@@ -1495,6 +1530,15 @@ bool memory_region_init_ram_from_fd(MemoryRegion *mr,
                                     int fd,
                                     ram_addr_t offset,
                                     Error **errp);
+
+MemoryRegion *memory_region_new_ram_from_fd(Object *owner,
+                                            const char *name,
+                                            uint64_t size,
+                                            uint32_t ram_flags,
+                                            int fd,
+                                            ram_addr_t offset,
+                                            Error **errp);
+
 #endif
 
 /**
@@ -1518,6 +1562,11 @@ void memory_region_init_ram_ptr(MemoryRegion *mr,
                                 uint64_t size,
                                 void *ptr);
 
+MemoryRegion *memory_region_new_ram_ptr(Object *owner,
+                                        const char *name,
+                                        uint64_t size,
+                                        void *ptr);
+
 /**
  * memory_region_init_ram_device_ptr:  Initialize RAM device memory region from
  *                                     a user-provided pointer.
@@ -1546,6 +1595,11 @@ void memory_region_init_ram_device_ptr(MemoryRegion *mr,
                                        uint64_t size,
                                        void *ptr);
 
+MemoryRegion *memory_region_new_ram_device_ptr(Object *owner,
+                                               const char *name,
+                                               uint64_t size,
+                                               void *ptr);
+
 /**
  * memory_region_init_alias: Initialize a memory region that aliases all or a
  *                           part of another memory region.
@@ -1565,6 +1619,12 @@ void memory_region_init_alias(MemoryRegion *mr,
                               hwaddr offset,
                               uint64_t size);
 
+MemoryRegion *memory_region_new_alias(Object *owner,
+                                      const char *name,
+                                      MemoryRegion *orig,
+                                      hwaddr offset,
+                                      uint64_t size);
+
 /**
  * memory_region_init_iommu: Initialize a memory region of a custom type
  * that translates addresses
@@ -1630,6 +1690,16 @@ bool memory_region_init_ram_guest_memfd(MemoryRegion *mr,
                                         uint64_t size,
                                         Error **errp);
 
+MemoryRegion *memory_region_new_ram(Object *owner,
+                                    const char *name,
+                                    uint64_t size,
+                                    Error **errp);
+
+MemoryRegion *memory_region_new_ram_guest_memfd(Object *owner,
+                                                const char *name,
+                                                uint64_t size,
+                                                Error **errp);
+
 /**
  * memory_region_init_rom: Initialize a ROM memory region.
  *
@@ -1659,6 +1729,11 @@ bool memory_region_init_rom(MemoryRegion *mr,
                             uint64_t size,
                             Error **errp);
 
+MemoryRegion *memory_region_new_rom(Object *owner,
+                                    const char *name,
+                                    uint64_t size,
+                                    Error **errp);
+
 /**
  * memory_region_init_rom_device:  Initialize a ROM memory region.
  *                                 Writes are handled via callbacks.
@@ -1694,6 +1769,12 @@ bool memory_region_init_rom_device(MemoryRegion *mr,
                                    uint64_t size,
                                    Error **errp);
 
+MemoryRegion *memory_region_new_rom_device(Object *owner,
+                                           const MemoryRegionOps *ops,
+                                           void *opaque,
+                                           const char *name,
+                                           uint64_t size,
+                                           Error **errp);
 
 /**
  * memory_region_owner: get a memory region's owner.
diff --git a/system/memory.c b/system/memory.c
index fa3e19e1fd..d125e8102b 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -1251,6 +1251,15 @@ void memory_region_init(MemoryRegion *mr,
     memory_region_do_init(mr, owner, name, size);
 }
 
+MemoryRegion *memory_region_new(Object *owner, const char *name, uint64_t size)
+{
+    MemoryRegion *mr = MEMORY_REGION(object_new(TYPE_MEMORY_REGION));
+
+    assert(name); /* mr is attached to owner by name */
+    memory_region_do_init(mr, owner, name, size);
+    return mr;
+}
+
 static void memory_region_get_container(Object *obj, Visitor *v,
                                         const char *name, void *opaque,
                                         Error **errp)
@@ -1576,6 +1585,16 @@ void memory_region_init_io(MemoryRegion *mr, Object *owner,
     memory_region_set_ops(mr, ops, opaque);
 }
 
+MemoryRegion *memory_region_new_io(Object *owner,
+                                   const MemoryRegionOps *ops, void *opaque,
+                                   const char *name, uint64_t size)
+{
+    MemoryRegion *mr = memory_region_new(owner, name, size);
+
+    memory_region_set_ops(mr, ops, opaque);
+    return mr;
+}
+
 static void memory_region_setup_ram(MemoryRegion *mr)
 {
     mr->ram = true;
@@ -1607,6 +1626,20 @@ bool memory_region_init_ram_flags_nomigrate(MemoryRegion *mr, Object *owner,
     return memory_region_error_propagate(mr, err, errp);
 }
 
+MemoryRegion *memory_region_new_ram_flags_nomigrate(Object *owner,
+                                                    const char *name,
+                                                    uint64_t size,
+                                                    uint32_t ram_flags,
+                                                    Error **errp)
+{
+    MemoryRegion *mr = memory_region_new(owner, name, size);
+    Error *err = NULL;
+
+    memory_region_setup_ram(mr);
+    mr->ram_block = qemu_ram_alloc(size, ram_flags, mr, &err);
+    return memory_region_error_propagate(mr, err, errp) ? mr : NULL;
+}
+
 bool memory_region_init_resizeable_ram(MemoryRegion *mr,
                                        Object *owner,
                                        const char *name,
@@ -1626,6 +1659,24 @@ bool memory_region_init_resizeable_ram(MemoryRegion *mr,
     return memory_region_error_propagate(mr, err, errp);
 }
 
+MemoryRegion *memory_region_new_resizeable_ram(Object *owner,
+                                               const char *name,
+                                               uint64_t size,
+                                               uint64_t max_size,
+                                               void (*resized)(const char*,
+                                                               uint64_t length,
+                                                               void *host),
+                                               Error **errp)
+{
+    MemoryRegion *mr = memory_region_new(owner, name, size);
+    Error *err = NULL;
+
+    memory_region_setup_ram(mr);
+    mr->ram_block = qemu_ram_alloc_resizeable(size, max_size, resized, mr,
+                                              &err);
+    return memory_region_error_propagate(mr, err, errp) ? mr : NULL;
+}
+
 #if defined(CONFIG_POSIX) && !defined(EMSCRIPTEN)
 bool memory_region_init_ram_from_file(MemoryRegion *mr, Object *owner,
                                       const char *name, uint64_t size,
@@ -1644,6 +1695,26 @@ bool memory_region_init_ram_from_file(MemoryRegion *mr, Object *owner,
     return memory_region_error_propagate(mr, err, errp);
 }
 
+MemoryRegion *memory_region_new_ram_from_file(Object *owner,
+                                              const char *name,
+                                              uint64_t size,
+                                              uint64_t align,
+                                              uint32_t ram_flags,
+                                              const char *path,
+                                              ram_addr_t offset,
+                                              Error **errp)
+{
+    MemoryRegion *mr = memory_region_new(owner, name, size);
+    Error *err = NULL;
+
+    memory_region_setup_ram(mr);
+    mr->readonly = !!(ram_flags & RAM_READONLY);
+    mr->align = align;
+    mr->ram_block = qemu_ram_alloc_from_file(size, mr, ram_flags, path, offset,
+                                             &err);
+    return memory_region_error_propagate(mr, err, errp) ? mr : NULL;
+}
+
 bool memory_region_init_ram_from_fd(MemoryRegion *mr, Object *owner,
                                     const char *name, uint64_t size,
                                     uint32_t ram_flags, int fd,
@@ -1658,6 +1729,21 @@ bool memory_region_init_ram_from_fd(MemoryRegion *mr, Object *owner,
                                            offset, false, &err);
     return memory_region_error_propagate(mr, err, errp);
 }
+
+MemoryRegion *memory_region_new_ram_from_fd(Object *owner,
+                                            const char *name, uint64_t size,
+                                            uint32_t ram_flags, int fd,
+                                            ram_addr_t offset, Error **errp)
+{
+    MemoryRegion *mr = memory_region_new(owner, name, size);
+    Error *err = NULL;
+
+    memory_region_setup_ram(mr);
+    mr->readonly = !!(ram_flags & RAM_READONLY);
+    mr->ram_block = qemu_ram_alloc_from_fd(size, size, NULL, mr, ram_flags, fd,
+                                           offset, false, &err);
+    return memory_region_error_propagate(mr, err, errp) ? mr : NULL;
+}
 #endif
 
 static void memory_region_setup_ram_ptr(MemoryRegion *mr, uint64_t size,
@@ -1676,6 +1762,15 @@ void memory_region_init_ram_ptr(MemoryRegion *mr, Object *owner,
     memory_region_setup_ram_ptr(mr, size, ptr);
 }
 
+MemoryRegion *memory_region_new_ram_ptr(Object *owner, const char *name,
+                                        uint64_t size, void *ptr)
+{
+    MemoryRegion *mr = memory_region_new(owner, name, size);
+
+    memory_region_setup_ram_ptr(mr, size, ptr);
+    return mr;
+}
+
 void memory_region_init_ram_device_ptr(MemoryRegion *mr, Object *owner,
                                        const char *name, uint64_t size,
                                        void *ptr)
@@ -1685,6 +1780,17 @@ void memory_region_init_ram_device_ptr(MemoryRegion *mr, Object *owner,
     mr->ram_device = true;
 }
 
+MemoryRegion *memory_region_new_ram_device_ptr(Object *owner, const char *name,
+                                               uint64_t size, void *ptr)
+{
+    MemoryRegion *mr = memory_region_new(owner, name, size);
+
+    memory_region_set_ops(mr, &ram_device_mem_ops, mr);
+    memory_region_setup_ram_ptr(mr, size, ptr);
+    mr->ram_device = true;
+    return mr;
+}
+
 void memory_region_init_alias(MemoryRegion *mr, Object *owner,
                               const char *name, MemoryRegion *orig,
                               hwaddr offset, uint64_t size)
@@ -1694,6 +1800,17 @@ void memory_region_init_alias(MemoryRegion *mr, Object *owner,
     mr->alias_offset = offset;
 }
 
+MemoryRegion *memory_region_new_alias(Object *owner,
+                                      const char *name, MemoryRegion *orig,
+                                      hwaddr offset, uint64_t size)
+{
+    MemoryRegion *mr = memory_region_new(owner, name, size);
+
+    mr->alias = orig;
+    mr->alias_offset = offset;
+    return mr;
+}
+
 void memory_region_init_iommu(void *_iommu_mr,
                               size_t instance_size,
                               const char *mrtypename,
@@ -3669,6 +3786,19 @@ bool memory_region_init_ram(MemoryRegion *mr, Object *owner,
     return true;
 }
 
+MemoryRegion *memory_region_new_ram(Object *owner,
+                                    const char *name, uint64_t size,
+                                    Error **errp)
+{
+    MemoryRegion *mr;
+
+    mr = memory_region_new_ram_flags_nomigrate(owner, name, size, 0, errp);
+    if (mr) {
+        memory_region_register_ram(mr, owner);
+    }
+    return mr;
+}
+
 bool memory_region_init_ram_guest_memfd(MemoryRegion *mr, Object *owner,
                                         const char *name, uint64_t size,
                                         Error **errp)
@@ -3681,6 +3811,21 @@ bool memory_region_init_ram_guest_memfd(MemoryRegion *mr, Object *owner,
     return true;
 }
 
+MemoryRegion *memory_region_new_ram_guest_memfd(Object *owner,
+                                                const char *name,
+                                                uint64_t size,
+                                                Error **errp)
+{
+    MemoryRegion *mr;
+
+    mr = memory_region_new_ram_flags_nomigrate(owner, name, size,
+                                               RAM_GUEST_MEMFD, errp);
+    if (mr) {
+        memory_region_register_ram(mr, owner);
+    }
+    return mr;
+}
+
 bool memory_region_init_rom(MemoryRegion *mr, Object *owner,
                             const char *name, uint64_t size,
                             Error **errp)
@@ -3694,6 +3839,20 @@ bool memory_region_init_rom(MemoryRegion *mr, Object *owner,
     return true;
 }
 
+MemoryRegion *memory_region_new_rom(Object *owner,
+                                    const char *name, uint64_t size,
+                                    Error **errp)
+{
+    MemoryRegion *mr;
+
+    mr = memory_region_new_ram_flags_nomigrate(owner, name, size, 0, errp);
+    if (mr) {
+        mr->readonly = true;
+        memory_region_register_ram(mr, owner);
+    }
+    return mr;
+}
+
 bool memory_region_init_rom_device(MemoryRegion *mr, Object *owner,
                                    const MemoryRegionOps *ops, void *opaque,
                                    const char *name, uint64_t size,
@@ -3714,6 +3873,28 @@ bool memory_region_init_rom_device(MemoryRegion *mr, Object *owner,
     return true;
 }
 
+MemoryRegion *memory_region_new_rom_device(Object *owner,
+                                           const MemoryRegionOps *ops,
+                                           void *opaque,
+                                           const char *name, uint64_t size,
+                                           Error **errp)
+{
+    MemoryRegion *mr;
+    Error *err = NULL;
+
+    assert(ops);
+    mr = memory_region_new_io(owner, ops, opaque, name, size);
+    memory_region_setup_ram(mr);
+    mr->ram_block = qemu_ram_alloc(size, 0, mr, &err);
+    if (!memory_region_error_propagate(mr, err, errp)) {
+        return NULL;
+    }
+    mr->ram = false;
+    mr->rom_device = true;
+    memory_region_register_ram(mr, owner);
+    return mr;
+}
+
 /*
  * Support system builds with CONFIG_FUZZ using a weak symbol and a stub for
  * the fuzz_dma_read_cb callback
-- 
2.41.3



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v3 2/6] memory: Update documentation for memory_region_new*()
  2026-02-10 20:02 [PATCH v3 0/6] Implement memory_region_new_* functions BALATON Zoltan
  2026-02-10 20:02 ` [PATCH v3 1/6] memory: Add memory_region_new* functions BALATON Zoltan
@ 2026-02-10 20:02 ` BALATON Zoltan
  2026-02-10 20:02 ` [PATCH v3 3/6] hw/ide/sii3112: Use memory_region_new to avoid leaking regions BALATON Zoltan
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: BALATON Zoltan @ 2026-02-10 20:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, Mark Cave-Ayland,
	Gerd Hoffmann, Max Filippov, Peter Maydell,
	Philippe Mathieu-Daudé

Clarify the difference between memory_region_new() and
memory_region_init() with regard to region lifecycle.

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---
 docs/devel/memory.rst   | 21 ++++-----
 include/system/memory.h | 98 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 109 insertions(+), 10 deletions(-)

diff --git a/docs/devel/memory.rst b/docs/devel/memory.rst
index 9083b18f08..988380c632 100644
--- a/docs/devel/memory.rst
+++ b/docs/devel/memory.rst
@@ -138,7 +138,8 @@ stability.
 Region lifecycle
 ----------------
 
-A region is created by one of the memory_region_init*() functions and
+A region is allocated by one of the memory_region_new*() functions or
+pre-allocated and initialized by memory_region_init*() functions and
 attached to an object, which acts as its owner or parent.  QEMU ensures
 that the owner object remains alive as long as the region is visible to
 the guest, or as long as the region is in use by a virtual CPU or another
@@ -154,16 +155,16 @@ ioeventfd) can be changed during the region lifecycle.  They take effect
 as soon as the region is made visible.  This can be immediately, later,
 or never.
 
-Destruction of a memory region happens automatically when the owner object
-dies.  When there are multiple memory regions under the same owner object,
-the memory API will guarantee all memory regions will be properly detached
-and finalized one by one.  The order in which memory regions will be
-finalized is not guaranteed.
+Destruction of a memory region allocated with memory_region_new*() functions
+happens automatically when the owner object dies.  When there are multiple
+memory regions under the same owner object, the memory API will guarantee all
+memory regions will be properly detached and finalized one by one.  The order
+in which memory regions will be finalized is not guaranteed.
 
-If however the memory region is part of a dynamically allocated data
-structure, you should free the memory region in the instance_finalize
-callback.  For an example see VFIOMSIXInfo and VFIOQuirk in
-hw/vfio/pci.c.
+If however the memory region is part of a separately allocated data structure
+and initialized with one of the memory_region_init*() functions, you may have
+to free the memory region e.g. in an instance_finalize callback.  For an
+example see VFIOMSIXInfo and VFIOQuirk in hw/vfio/pci.c.
 
 You must not destroy a memory region as long as it may be in use by a
 device or CPU.  In order to do this, as a general rule do not create or
diff --git a/include/system/memory.h b/include/system/memory.h
index ab76433c54..017c290f27 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -1324,6 +1324,13 @@ void memory_region_init(MemoryRegion *mr,
                         const char *name,
                         uint64_t size);
 
+/**
+ * memory_region_new: Allocate and initialize a memory region
+ *
+ * Like memory_region_init() but @mr is allocated and managed by QOM.
+ *
+ * Return: Pointer to allocated #MemoryRegion.
+ */
 MemoryRegion *memory_region_new(Object *owner,
                                 const char *name,
                                 uint64_t size);
@@ -1378,6 +1385,13 @@ void memory_region_init_io(MemoryRegion *mr,
                            const char *name,
                            uint64_t size);
 
+/**
+ * memory_region_new_io: Allocate and initialize an I/O memory region.
+ *
+ * Like memory_region_init_io() but @mr is allocated and managed by QOM.
+ *
+ * Return: Pointer to allocated #MemoryRegion.
+ */
 MemoryRegion *memory_region_new_io(Object *owner,
                                    const MemoryRegionOps *ops,
                                    void *opaque,
@@ -1410,6 +1424,15 @@ bool memory_region_init_ram_flags_nomigrate(MemoryRegion *mr,
                                             uint32_t ram_flags,
                                             Error **errp);
 
+/**
+ * memory_region_new_ram_flags_nomigrate:  Allocate and initialize RAM memory
+ *                                         region with flags.
+ *
+ * Like memory_region_init_ram_flags_nomigrate() but @mr is allocated and
+ * managed by QOM.
+ *
+ * Return: Pointer to allocated #MemoryRegion.
+ */
 MemoryRegion *memory_region_new_ram_flags_nomigrate(Object *owner,
                                                     const char *name,
                                                     uint64_t size,
@@ -1449,6 +1472,15 @@ bool memory_region_init_resizeable_ram(MemoryRegion *mr,
                                                        void *host),
                                        Error **errp);
 
+/**
+ * memory_region_new_resizeable_ram:  Allocate and initialize memory region
+ *                                    with resizable RAM.
+ *
+ * Like memory_region_init_resizeable_ram() but @mr is allocated and managed
+ * by QOM.
+ *
+ * Return: Pointer to allocated #MemoryRegion.
+ */
 MemoryRegion *memory_region_new_resizeable_ram(Object *owner,
                                                const char *name,
                                                uint64_t size,
@@ -1493,6 +1525,15 @@ bool memory_region_init_ram_from_file(MemoryRegion *mr,
                                       ram_addr_t offset,
                                       Error **errp);
 
+/**
+ * memory_region_new_ram_from_file:  Allocate and initialize RAM memory region
+ *                                   with a mmap-ed backend.
+ *
+ * Like memory_region_init_ram_from_file() but @mr is allocated and managed
+ * by QOM.
+ *
+ * Return: Pointer to allocated #MemoryRegion.
+ */
 MemoryRegion *memory_region_new_ram_from_file(Object *owner,
                                               const char *name,
                                               uint64_t size,
@@ -1531,6 +1572,15 @@ bool memory_region_init_ram_from_fd(MemoryRegion *mr,
                                     ram_addr_t offset,
                                     Error **errp);
 
+/**
+ * memory_region_new_ram_from_fd:  Allocate and initialize RAM memory region
+ *                                 with a mmap-ed backend.
+ *
+ * Like memory_region_init_ram_from_fd() but @mr is allocated and managed
+ * by QOM.
+ *
+ * Return: Pointer to allocated #MemoryRegion.
+ */
 MemoryRegion *memory_region_new_ram_from_fd(Object *owner,
                                             const char *name,
                                             uint64_t size,
@@ -1562,6 +1612,14 @@ void memory_region_init_ram_ptr(MemoryRegion *mr,
                                 uint64_t size,
                                 void *ptr);
 
+/**
+ * memory_region_new_ram_ptr:  Allocate and initialize RAM memory region from a
+ *                             user-provided pointer.
+ *
+ * Like memory_region_init_ram_ptr() but @mr is allocated and managed by QOM.
+ *
+ * Return: Pointer to allocated #MemoryRegion.
+ */
 MemoryRegion *memory_region_new_ram_ptr(Object *owner,
                                         const char *name,
                                         uint64_t size,
@@ -1595,6 +1653,15 @@ void memory_region_init_ram_device_ptr(MemoryRegion *mr,
                                        uint64_t size,
                                        void *ptr);
 
+/**
+ * memory_region_new_ram_device_ptr:  Allocate and initialize RAM device memory
+ *                                    region from a user-provided pointer.
+ *
+ * Like memory_region_init_ram_device_ptr() but @mr is allocated and managed
+ * by QOM.
+ *
+ * Return: Pointer to allocated #MemoryRegion.
+ */
 MemoryRegion *memory_region_new_ram_device_ptr(Object *owner,
                                                const char *name,
                                                uint64_t size,
@@ -1619,6 +1686,14 @@ void memory_region_init_alias(MemoryRegion *mr,
                               hwaddr offset,
                               uint64_t size);
 
+/**
+ * memory_region_new_alias: Allocate and initialize a memory region that
+ *                          aliases all or a part of another memory region.
+ *
+ * Like memory_region_init_alias() but @mr is allocated and managed by QOM.
+ *
+ * Return: Pointer to allocated #MemoryRegion.
+ */
 MemoryRegion *memory_region_new_alias(Object *owner,
                                       const char *name,
                                       MemoryRegion *orig,
@@ -1690,6 +1765,13 @@ bool memory_region_init_ram_guest_memfd(MemoryRegion *mr,
                                         uint64_t size,
                                         Error **errp);
 
+/**
+ * memory_region_new_ram: Allocate and initialize a RAM memory region.
+ *
+ * Like memory_region_init_ram() but @mr is allocated and managed by QOM.
+ *
+ * Return: Pointer to allocated #MemoryRegion.
+ */
 MemoryRegion *memory_region_new_ram(Object *owner,
                                     const char *name,
                                     uint64_t size,
@@ -1729,6 +1811,13 @@ bool memory_region_init_rom(MemoryRegion *mr,
                             uint64_t size,
                             Error **errp);
 
+/**
+ * memory_region_new_rom: Allocate and initialize a ROM memory region.
+ *
+ * Like memory_region_init_rom() but @mr is allocated and managed by QOM.
+ *
+ * Return: Pointer to allocated #MemoryRegion.
+ */
 MemoryRegion *memory_region_new_rom(Object *owner,
                                     const char *name,
                                     uint64_t size,
@@ -1769,6 +1858,15 @@ bool memory_region_init_rom_device(MemoryRegion *mr,
                                    uint64_t size,
                                    Error **errp);
 
+/**
+ * memory_region_new_rom_device:  Allocate and initialize a ROM memory region.
+ *                                Writes are handled via callbacks.
+ *
+ * Like memory_region_init_rom_device() but @mr is allocated and managed
+ * by QOM.
+ *
+ * Return: Pointer to allocated #MemoryRegion.
+ */
 MemoryRegion *memory_region_new_rom_device(Object *owner,
                                            const MemoryRegionOps *ops,
                                            void *opaque,
-- 
2.41.3



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v3 3/6] hw/ide/sii3112: Use memory_region_new to avoid leaking regions
  2026-02-10 20:02 [PATCH v3 0/6] Implement memory_region_new_* functions BALATON Zoltan
  2026-02-10 20:02 ` [PATCH v3 1/6] memory: Add memory_region_new* functions BALATON Zoltan
  2026-02-10 20:02 ` [PATCH v3 2/6] memory: Update documentation for memory_region_new*() BALATON Zoltan
@ 2026-02-10 20:02 ` BALATON Zoltan
  2026-02-10 20:02 ` [PATCH v3 4/6] hw/pci-host/articia: Map PCI memory windows in realize BALATON Zoltan
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: BALATON Zoltan @ 2026-02-10 20:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, Mark Cave-Ayland,
	Gerd Hoffmann, Max Filippov, Peter Maydell,
	Philippe Mathieu-Daudé

Memory regions created with memory_region_init are not freed with
their owner. Use memory_region_new instead to let QOM manage the
lifetime of the memory regions.

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---
 hw/ide/sii3112.c | 30 ++++++++++++------------------
 1 file changed, 12 insertions(+), 18 deletions(-)

diff --git a/hw/ide/sii3112.c b/hw/ide/sii3112.c
index 9b28c691fd..d2dcfc3830 100644
--- a/hw/ide/sii3112.c
+++ b/hw/ide/sii3112.c
@@ -31,7 +31,7 @@ typedef struct SiI3112Regs {
 
 struct SiI3112PCIState {
     PCIIDEState i;
-    MemoryRegion mmio;
+
     SiI3112Regs regs[2];
 };
 
@@ -249,39 +249,33 @@ static void sii3112_reset(DeviceState *dev)
 
 static void sii3112_pci_realize(PCIDevice *dev, Error **errp)
 {
-    SiI3112PCIState *d = SII3112_PCI(dev);
     PCIIDEState *s = PCI_IDE(dev);
     DeviceState *ds = DEVICE(dev);
-    MemoryRegion *mr;
-    int i;
+    Object *o = OBJECT(dev);
+    MemoryRegion *mmio, *mr;
 
     pci_config_set_interrupt_pin(dev->config, 1);
     pci_set_byte(dev->config + PCI_CACHE_LINE_SIZE, 8);
 
     /* BAR5 is in PCI memory space */
-    memory_region_init_io(&d->mmio, OBJECT(d), &sii3112_reg_ops, d,
-                         "sii3112.bar5", 0x200);
-    pci_register_bar(dev, 5, PCI_BASE_ADDRESS_SPACE_MEMORY, &d->mmio);
+    mmio = memory_region_new_io(o, &sii3112_reg_ops, SII3112_PCI(dev),
+                                "sii3112.bar5", 0x200);
+    pci_register_bar(dev, 5, PCI_BASE_ADDRESS_SPACE_MEMORY, mmio);
 
     /* BAR0-BAR4 are PCI I/O space aliases into BAR5 */
-    mr = g_new(MemoryRegion, 1);
-    memory_region_init_alias(mr, OBJECT(d), "sii3112.bar0", &d->mmio, 0x80, 8);
+    mr = memory_region_new_alias(o, "sii3112.bar0", mmio, 0x80, 8);
     pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, mr);
-    mr = g_new(MemoryRegion, 1);
-    memory_region_init_alias(mr, OBJECT(d), "sii3112.bar1", &d->mmio, 0x88, 4);
+    mr = memory_region_new_alias(o, "sii3112.bar1", mmio, 0x88, 4);
     pci_register_bar(dev, 1, PCI_BASE_ADDRESS_SPACE_IO, mr);
-    mr = g_new(MemoryRegion, 1);
-    memory_region_init_alias(mr, OBJECT(d), "sii3112.bar2", &d->mmio, 0xc0, 8);
+    mr = memory_region_new_alias(o, "sii3112.bar2", mmio, 0xc0, 8);
     pci_register_bar(dev, 2, PCI_BASE_ADDRESS_SPACE_IO, mr);
-    mr = g_new(MemoryRegion, 1);
-    memory_region_init_alias(mr, OBJECT(d), "sii3112.bar3", &d->mmio, 0xc8, 4);
+    mr = memory_region_new_alias(o, "sii3112.bar3", mmio, 0xc8, 4);
     pci_register_bar(dev, 3, PCI_BASE_ADDRESS_SPACE_IO, mr);
-    mr = g_new(MemoryRegion, 1);
-    memory_region_init_alias(mr, OBJECT(d), "sii3112.bar4", &d->mmio, 0, 16);
+    mr = memory_region_new_alias(o, "sii3112.bar4", mmio, 0, 16);
     pci_register_bar(dev, 4, PCI_BASE_ADDRESS_SPACE_IO, mr);
 
     qdev_init_gpio_in(ds, sii3112_set_irq, 2);
-    for (i = 0; i < 2; i++) {
+    for (int i = 0; i < 2; i++) {
         ide_bus_init(&s->bus[i], sizeof(s->bus[i]), ds, i, 1);
         ide_bus_init_output_irq(&s->bus[i], qdev_get_gpio_in(ds, i));
 
-- 
2.41.3



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v3 4/6] hw/pci-host/articia: Map PCI memory windows in realize
  2026-02-10 20:02 [PATCH v3 0/6] Implement memory_region_new_* functions BALATON Zoltan
                   ` (2 preceding siblings ...)
  2026-02-10 20:02 ` [PATCH v3 3/6] hw/ide/sii3112: Use memory_region_new to avoid leaking regions BALATON Zoltan
@ 2026-02-10 20:02 ` BALATON Zoltan
  2026-02-10 20:02 ` [PATCH v3 5/6] hw/pci-host/articia: Add variable for common type cast BALATON Zoltan
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: BALATON Zoltan @ 2026-02-10 20:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, Mark Cave-Ayland,
	Gerd Hoffmann, Max Filippov, Peter Maydell,
	Philippe Mathieu-Daudé

These memory windows are a result of the address decoding in the
Articia S north bridge so better model it there and not in board code.

Suggested-by: Philippe Mathieu-Daudé <philmd@linaro.org>
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---
 hw/pci-host/articia.c | 14 +++++++++++++-
 hw/ppc/amigaone.c     | 28 +++++-----------------------
 hw/ppc/pegasos.c      | 13 -------------
 3 files changed, 18 insertions(+), 37 deletions(-)

diff --git a/hw/pci-host/articia.c b/hw/pci-host/articia.c
index 04623dfd84..203e0646df 100644
--- a/hw/pci-host/articia.c
+++ b/hw/pci-host/articia.c
@@ -22,6 +22,11 @@
  * Most features are missing but those are not needed by firmware and guests.
  */
 
+#define PCI_HIGH_ADDR 0x80000000
+#define PCI_HIGH_SIZE 0x7d000000
+#define PCI_LOW_ADDR  0xfd000000
+#define PCI_LOW_SIZE   0x1000000
+
 OBJECT_DECLARE_SIMPLE_TYPE(ArticiaState, ARTICIA)
 
 OBJECT_DECLARE_SIMPLE_TYPE(ArticiaHostState, ARTICIA_PCI_HOST)
@@ -169,6 +174,7 @@ static void articia_realize(DeviceState *dev, Error **errp)
 {
     ArticiaState *s = ARTICIA(dev);
     PCIHostState *h = PCI_HOST_BRIDGE(dev);
+    MemoryRegion *mr;
     PCIDevice *pdev;
 
     bitbang_i2c_init(&s->smbus, i2c_init_bus(dev, "smbus"));
@@ -181,6 +187,13 @@ static void articia_realize(DeviceState *dev, Error **errp)
                           TYPE_ARTICIA, 0x1000000);
     memory_region_add_subregion_overlap(&s->reg, 0, &s->io, 1);
 
+    mr = memory_region_new_alias(OBJECT(dev), "pci-mem-low", &s->mem, 0,
+                                 PCI_LOW_SIZE);
+    memory_region_add_subregion(get_system_memory(), PCI_LOW_ADDR, mr);
+    mr = memory_region_new_alias(OBJECT(dev), "pci-mem-high", &s->mem,
+                                 PCI_HIGH_ADDR, PCI_HIGH_SIZE);
+    memory_region_add_subregion(get_system_memory(), PCI_HIGH_ADDR, mr);
+
     /* devfn_min is 8 that matches first PCI slot in AmigaOne */
     h->bus = pci_register_root_bus(dev, NULL, articia_pcihost_set_irq,
                                    amigaone_pcihost_bus0_map_irq, dev, &s->mem,
@@ -191,7 +204,6 @@ static void articia_realize(DeviceState *dev, Error **errp)
     pci_create_simple(h->bus, PCI_DEVFN(0, 1), TYPE_ARTICIA_PCI_BRIDGE);
 
     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->reg);
-    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mem);
     qdev_init_gpio_out(dev, s->irq, ARRAY_SIZE(s->irq));
 }
 
diff --git a/hw/ppc/amigaone.c b/hw/ppc/amigaone.c
index 8074713fbe..17deacab44 100644
--- a/hw/ppc/amigaone.c
+++ b/hw/ppc/amigaone.c
@@ -35,13 +35,6 @@
 #define INITRD_MIN_ADDR 0x600000
 #define INIT_RAM_ADDR 0x40000000
 
-#define PCI_HIGH_ADDR 0x80000000
-#define PCI_HIGH_SIZE 0x7d000000
-#define PCI_LOW_ADDR  0xfd000000
-#define PCI_LOW_SIZE  0xe0000
-
-#define ARTICIA_ADDR 0xfe000000
-
 /*
  * Firmware binary available at
  * https://www.hyperion-entertainment.com/index.php/downloads?view=files&parent=28
@@ -267,7 +260,7 @@ static void amigaone_init(MachineState *machine)
 {
     PowerPCCPU *cpu;
     CPUPPCState *env;
-    MemoryRegion *rom, *pci_mem, *mr;
+    MemoryRegion *rom, *mr;
     ssize_t sz;
     PCIBus *pci_bus;
     Object *via;
@@ -308,8 +301,8 @@ static void amigaone_init(MachineState *machine)
         qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(di));
     }
     sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
-    memory_region_add_subregion(get_system_memory(), NVRAM_ADDR,
-                                sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
+    mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+    memory_region_add_subregion_overlap(get_system_memory(), NVRAM_ADDR, mr, 1);
 
     /* allocate and load firmware */
     rom = g_new(MemoryRegion, 1);
@@ -329,8 +322,8 @@ static void amigaone_init(MachineState *machine)
     }
 
     /* Articia S */
-    dev = sysbus_create_simple(TYPE_ARTICIA, ARTICIA_ADDR, NULL);
-
+    dev = sysbus_create_simple(TYPE_ARTICIA, 0xfe000000, NULL);
+    pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
     i2c_bus = I2C_BUS(qdev_get_child_bus(dev, "smbus"));
     if (machine->ram_size > 512 * MiB) {
         spd_data = spd_data_generate(SDR, machine->ram_size / 2);
@@ -343,17 +336,6 @@ static void amigaone_init(MachineState *machine)
         smbus_eeprom_init_one(i2c_bus, 0x52, spd_data);
     }
 
-    pci_mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1);
-    mr = g_new(MemoryRegion, 1);
-    memory_region_init_alias(mr, OBJECT(dev), "pci-mem-low", pci_mem,
-                             0, PCI_LOW_SIZE);
-    memory_region_add_subregion(get_system_memory(), PCI_LOW_ADDR, mr);
-    mr = g_new(MemoryRegion, 1);
-    memory_region_init_alias(mr, OBJECT(dev), "pci-mem-high", pci_mem,
-                             PCI_HIGH_ADDR, PCI_HIGH_SIZE);
-    memory_region_add_subregion(get_system_memory(), PCI_HIGH_ADDR, mr);
-    pci_bus = PCI_BUS(qdev_get_child_bus(dev, "pci.0"));
-
     /* VIA VT82c686B South Bridge (multifunction PCI device) */
     via = OBJECT(pci_create_simple_multifunction(pci_bus, PCI_DEVFN(7, 0),
                                                  TYPE_VT82C686B_ISA));
diff --git a/hw/ppc/pegasos.c b/hw/ppc/pegasos.c
index ac9fc5a654..e0e2e8815d 100644
--- a/hw/ppc/pegasos.c
+++ b/hw/ppc/pegasos.c
@@ -213,23 +213,10 @@ static void pegasos_init(MachineState *machine)
     /* north bridge */
     switch (pm->type) {
     case PEGASOS1:
-    {
-        MemoryRegion *pci_mem, *mr;
-
         /* Articia S */
         pm->nb = DEVICE(sysbus_create_simple(TYPE_ARTICIA, 0xfe000000, NULL));
-        pci_mem = sysbus_mmio_get_region(SYS_BUS_DEVICE(pm->nb), 1);
-        mr = g_new(MemoryRegion, 1);
-        memory_region_init_alias(mr, OBJECT(pm->nb), "pci-mem-low", pci_mem,
-                                 0, 0x1000000);
-        memory_region_add_subregion(get_system_memory(), 0xfd000000, mr);
-        mr = g_new(MemoryRegion, 1);
-        memory_region_init_alias(mr, OBJECT(pm->nb), "pci-mem-high", pci_mem,
-                                 0x80000000, 0x7d000000);
-        memory_region_add_subregion(get_system_memory(), 0x80000000, mr);
         pci_bus = PCI_BUS(qdev_get_child_bus(pm->nb, "pci.0"));
         break;
-    }
     case PEGASOS2:
         /* Marvell Discovery II system controller */
         pm->nb = DEVICE(sysbus_create_simple(TYPE_MV64361, -1,
-- 
2.41.3



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v3 5/6] hw/pci-host/articia: Add variable for common type cast
  2026-02-10 20:02 [PATCH v3 0/6] Implement memory_region_new_* functions BALATON Zoltan
                   ` (3 preceding siblings ...)
  2026-02-10 20:02 ` [PATCH v3 4/6] hw/pci-host/articia: Map PCI memory windows in realize BALATON Zoltan
@ 2026-02-10 20:02 ` BALATON Zoltan
  2026-02-10 20:02 ` [PATCH v3 6/6] hw/xtensa/xtfpga: Fix leaking memory region BALATON Zoltan
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: BALATON Zoltan @ 2026-02-10 20:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, Mark Cave-Ayland,
	Gerd Hoffmann, Max Filippov, Peter Maydell,
	Philippe Mathieu-Daudé

We need the device casted to OBJECT often enough in realize to store
it in a local variable that also makes function calls more readable.

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---
 hw/pci-host/articia.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/hw/pci-host/articia.c b/hw/pci-host/articia.c
index 203e0646df..d7676a166f 100644
--- a/hw/pci-host/articia.c
+++ b/hw/pci-host/articia.c
@@ -174,24 +174,24 @@ static void articia_realize(DeviceState *dev, Error **errp)
 {
     ArticiaState *s = ARTICIA(dev);
     PCIHostState *h = PCI_HOST_BRIDGE(dev);
+    Object *o = OBJECT(dev);
     MemoryRegion *mr;
     PCIDevice *pdev;
 
     bitbang_i2c_init(&s->smbus, i2c_init_bus(dev, "smbus"));
-    memory_region_init_io(&s->gpio_reg, OBJECT(s), &articia_gpio_ops, s,
+    memory_region_init_io(&s->gpio_reg, o, &articia_gpio_ops, s,
                           TYPE_ARTICIA, 4);
 
-    memory_region_init(&s->mem, OBJECT(dev), "pci-mem", UINT64_MAX);
-    memory_region_init(&s->io, OBJECT(dev), "pci-io", 0xc00000);
-    memory_region_init_io(&s->reg, OBJECT(s), &articia_reg_ops, s,
+    memory_region_init(&s->mem, o, "pci-mem", UINT64_MAX);
+    memory_region_init(&s->io, o, "pci-io", 0xc00000);
+    memory_region_init_io(&s->reg, o, &articia_reg_ops, s,
                           TYPE_ARTICIA, 0x1000000);
     memory_region_add_subregion_overlap(&s->reg, 0, &s->io, 1);
 
-    mr = memory_region_new_alias(OBJECT(dev), "pci-mem-low", &s->mem, 0,
-                                 PCI_LOW_SIZE);
+    mr = memory_region_new_alias(o, "pci-mem-low", &s->mem, 0, PCI_LOW_SIZE);
     memory_region_add_subregion(get_system_memory(), PCI_LOW_ADDR, mr);
-    mr = memory_region_new_alias(OBJECT(dev), "pci-mem-high", &s->mem,
-                                 PCI_HIGH_ADDR, PCI_HIGH_SIZE);
+    mr = memory_region_new_alias(o, "pci-mem-high", &s->mem, PCI_HIGH_ADDR,
+                                 PCI_HIGH_SIZE);
     memory_region_add_subregion(get_system_memory(), PCI_HIGH_ADDR, mr);
 
     /* devfn_min is 8 that matches first PCI slot in AmigaOne */
-- 
2.41.3



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v3 6/6] hw/xtensa/xtfpga: Fix leaking memory region
  2026-02-10 20:02 [PATCH v3 0/6] Implement memory_region_new_* functions BALATON Zoltan
                   ` (4 preceding siblings ...)
  2026-02-10 20:02 ` [PATCH v3 5/6] hw/pci-host/articia: Add variable for common type cast BALATON Zoltan
@ 2026-02-10 20:02 ` BALATON Zoltan
  2026-02-10 20:58 ` [PATCH v3 0/6] Implement memory_region_new_* functions BALATON Zoltan
  2026-02-11  7:00 ` Paolo Bonzini
  7 siblings, 0 replies; 14+ messages in thread
From: BALATON Zoltan @ 2026-02-10 20:02 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, Mark Cave-Ayland,
	Gerd Hoffmann, Max Filippov, Peter Maydell,
	Philippe Mathieu-Daudé

Use memory_region_new_ram to avoid leaking memory region. This would
be a migration break but the machines using this don't seem to support
migration and even if they did we make no compatibility guarantee for
these machines.

Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---
 hw/xtensa/xtfpga.c | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c
index b025cc53a8..b8ae1994d8 100644
--- a/hw/xtensa/xtfpga.c
+++ b/hw/xtensa/xtfpga.c
@@ -50,7 +50,6 @@
 #include "xtensa_memory.h"
 #include "hw/xtensa/mx_pic.h"
 #include "exec/cpu-common.h"
-#include "migration/vmstate.h"
 
 typedef struct XtfpgaFlashDesc {
     hwaddr base;
@@ -162,10 +161,8 @@ static void xtfpga_net_init(MemoryRegion *address_space,
     memory_region_add_subregion(address_space, descriptors,
             sysbus_mmio_get_region(s, 1));
 
-    ram = g_malloc(sizeof(*ram));
-    memory_region_init_ram_flags_nomigrate(ram, OBJECT(s), "open_eth.ram",
-                                           16 * KiB, 0, &error_fatal);
-    vmstate_register_ram_global(ram);
+    ram = memory_region_new_ram(OBJECT(s), "open_eth.ram", 16 * KiB,
+                                &error_fatal);
     memory_region_add_subregion(address_space, buffers, ram);
 }
 
-- 
2.41.3



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH v3 0/6] Implement memory_region_new_* functions
  2026-02-10 20:02 [PATCH v3 0/6] Implement memory_region_new_* functions BALATON Zoltan
                   ` (5 preceding siblings ...)
  2026-02-10 20:02 ` [PATCH v3 6/6] hw/xtensa/xtfpga: Fix leaking memory region BALATON Zoltan
@ 2026-02-10 20:58 ` BALATON Zoltan
  2026-02-11  7:00 ` Paolo Bonzini
  7 siblings, 0 replies; 14+ messages in thread
From: BALATON Zoltan @ 2026-02-10 20:58 UTC (permalink / raw)
  To: qemu-devel
  Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, Mark Cave-Ayland,
	Gerd Hoffmann, Max Filippov, Peter Maydell,
	Philippe Mathieu-Daudé

On Tue, 10 Feb 2026, BALATON Zoltan wrote:
> Our documentation says that memory regions are automatically freed
> when the owner dies and the reference counting to do this is also
> implemented. However this relies on the QOM free funtion that can only
> be set by creating objects with object_new but memory API only
> provides constructors that call object_initialize which clears the
> free function that prevents QOM to manage the memory region lifetime.
> Implement corresponding memory_region_new_* functions that do the same
> as the memory_region_init_* functions but create the memory region
> with object_new so the lifetime can be automatically managed by QOM as
> documented. The memory_region_init functions are kept because they are
> useful for memory regions embedded in other object or managed
> externally and not by QOM for some reason.
>
> v3:
> Based-on: <cover.1770753117.git.balaton@eik.bme.hu>

I mean
Based-on: <cover.1770253186.git.balaton@eik.bme.hu>
[PATCH v4 0/8] memory: Remove most _nomigrate variants
series.

> - convert xtfpga from nomigrate as this has no migration compatibility
> issue
>
> v2:
> - rebase on master
> - update documentation
> - use these function to fix some leaks (there may be more, e.g. in
> hw/pci-host/bonito but I leave that for later and/or others)
>
> BALATON Zoltan (6):
>  memory: Add memory_region_new* functions
>  memory: Update documentation for memory_region_new*()
>  hw/ide/sii3112: Use memory_region_new to avoid leaking regions
>  hw/pci-host/articia: Map PCI memory windows in realize
>  hw/pci-host/articia: Add variable for common type cast
>  hw/xtensa/xtfpga: Fix leaking memory region
>
> docs/devel/memory.rst   |  21 ++---
> hw/ide/sii3112.c        |  30 +++----
> hw/pci-host/articia.c   |  22 +++--
> hw/ppc/amigaone.c       |  28 ++-----
> hw/ppc/pegasos.c        |  13 ---
> hw/xtensa/xtfpga.c      |   7 +-
> include/system/memory.h | 179 +++++++++++++++++++++++++++++++++++++++
> system/memory.c         | 181 ++++++++++++++++++++++++++++++++++++++++
> 8 files changed, 407 insertions(+), 74 deletions(-)
>
>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v3 0/6] Implement memory_region_new_* functions
  2026-02-10 20:02 [PATCH v3 0/6] Implement memory_region_new_* functions BALATON Zoltan
                   ` (6 preceding siblings ...)
  2026-02-10 20:58 ` [PATCH v3 0/6] Implement memory_region_new_* functions BALATON Zoltan
@ 2026-02-11  7:00 ` Paolo Bonzini
  2026-02-11 11:47   ` BALATON Zoltan
  7 siblings, 1 reply; 14+ messages in thread
From: Paolo Bonzini @ 2026-02-11  7:00 UTC (permalink / raw)
  To: BALATON Zoltan
  Cc: qemu-devel, Peter Xu, Akihiko Odaki, Mark Cave-Ayland,
	Gerd Hoffmann, Max Filippov, Peter Maydell,
	Philippe Mathieu-Daudé

[-- Attachment #1: Type: text/plain, Size: 2099 bytes --]

Il mar 10 feb 2026, 21:02 BALATON Zoltan <balaton@eik.bme.hu> ha scritto:

> Our documentation says that memory regions are automatically freed
> when the owner dies and the reference counting to do this is also
> implemented. However this relies on the QOM free funtion that can only
> be set by creating objects with object_new but memory API only
> provides constructors that call object_initialize which clears the
> free function that prevents QOM to manage the memory region lifetime.
> Implement corresponding memory_region_new_* functions that do the same
> as the memory_region_init_* functions but create the memory region
> with object_new so the lifetime can be automatically managed by QOM as
> documented. The memory_region_init functions are kept because they are
> useful for memory regions embedded in other object or managed
> externally and not by QOM for some reason.
>

I think there was pretty much agreement *not* to do this?

Paolo

v3:
> Based-on: <cover.1770753117.git.balaton@eik.bme.hu>
> - convert xtfpga from nomigrate as this has no migration compatibility
> issue
>
> v2:
> - rebase on master
> - update documentation
> - use these function to fix some leaks (there may be more, e.g. in
> hw/pci-host/bonito but I leave that for later and/or others)
>
> BALATON Zoltan (6):
>   memory: Add memory_region_new* functions
>   memory: Update documentation for memory_region_new*()
>   hw/ide/sii3112: Use memory_region_new to avoid leaking regions
>   hw/pci-host/articia: Map PCI memory windows in realize
>   hw/pci-host/articia: Add variable for common type cast
>   hw/xtensa/xtfpga: Fix leaking memory region
>
>  docs/devel/memory.rst   |  21 ++---
>  hw/ide/sii3112.c        |  30 +++----
>  hw/pci-host/articia.c   |  22 +++--
>  hw/ppc/amigaone.c       |  28 ++-----
>  hw/ppc/pegasos.c        |  13 ---
>  hw/xtensa/xtfpga.c      |   7 +-
>  include/system/memory.h | 179 +++++++++++++++++++++++++++++++++++++++
>  system/memory.c         | 181 ++++++++++++++++++++++++++++++++++++++++
>  8 files changed, 407 insertions(+), 74 deletions(-)
>
> --
> 2.41.3
>
>

[-- Attachment #2: Type: text/html, Size: 3025 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v3 0/6] Implement memory_region_new_* functions
  2026-02-11  7:00 ` Paolo Bonzini
@ 2026-02-11 11:47   ` BALATON Zoltan
  2026-02-11 14:35     ` Peter Xu
  0 siblings, 1 reply; 14+ messages in thread
From: BALATON Zoltan @ 2026-02-11 11:47 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: qemu-devel, Peter Xu, Akihiko Odaki, Mark Cave-Ayland,
	Gerd Hoffmann, Max Filippov, Peter Maydell,
	Philippe Mathieu-Daudé

On Wed, 11 Feb 2026, Paolo Bonzini wrote:
> Il mar 10 feb 2026, 21:02 BALATON Zoltan <balaton@eik.bme.hu> ha scritto:
>
>> Our documentation says that memory regions are automatically freed
>> when the owner dies and the reference counting to do this is also
>> implemented. However this relies on the QOM free funtion that can only
>> be set by creating objects with object_new but memory API only
>> provides constructors that call object_initialize which clears the
>> free function that prevents QOM to manage the memory region lifetime.
>> Implement corresponding memory_region_new_* functions that do the same
>> as the memory_region_init_* functions but create the memory region
>> with object_new so the lifetime can be automatically managed by QOM as
>> documented. The memory_region_init functions are kept because they are
>> useful for memory regions embedded in other object or managed
>> externally and not by QOM for some reason.
>>
>
> I think there was pretty much agreement *not* to do this?

Who agreed on that? So far I got concerns that this was too big (that's 
why I split it from the clean ups to show it's not that big change, less 
than 200 lines plus the docs but the clean ups removed as many lines as 
the doc comments add) and others saying this should replace 
memory_region_init altogether (that's way too much churn and not needed 
IMO) but no clear explanation of why this was *not* needed. You as 
maintainer can say no but then please give a justification for why and 
some solution to the problems this tries to fix.

Regards,
BALATON Zoltan

> Paolo
>
> v3:
>> Based-on: <cover.1770753117.git.balaton@eik.bme.hu>
>> - convert xtfpga from nomigrate as this has no migration compatibility
>> issue
>>
>> v2:
>> - rebase on master
>> - update documentation
>> - use these function to fix some leaks (there may be more, e.g. in
>> hw/pci-host/bonito but I leave that for later and/or others)
>>
>> BALATON Zoltan (6):
>>   memory: Add memory_region_new* functions
>>   memory: Update documentation for memory_region_new*()
>>   hw/ide/sii3112: Use memory_region_new to avoid leaking regions
>>   hw/pci-host/articia: Map PCI memory windows in realize
>>   hw/pci-host/articia: Add variable for common type cast
>>   hw/xtensa/xtfpga: Fix leaking memory region
>>
>>  docs/devel/memory.rst   |  21 ++---
>>  hw/ide/sii3112.c        |  30 +++----
>>  hw/pci-host/articia.c   |  22 +++--
>>  hw/ppc/amigaone.c       |  28 ++-----
>>  hw/ppc/pegasos.c        |  13 ---
>>  hw/xtensa/xtfpga.c      |   7 +-
>>  include/system/memory.h | 179 +++++++++++++++++++++++++++++++++++++++
>>  system/memory.c         | 181 ++++++++++++++++++++++++++++++++++++++++
>>  8 files changed, 407 insertions(+), 74 deletions(-)
>>
>> --
>> 2.41.3
>>
>>
>


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v3 0/6] Implement memory_region_new_* functions
  2026-02-11 11:47   ` BALATON Zoltan
@ 2026-02-11 14:35     ` Peter Xu
  2026-02-12 17:37       ` BALATON Zoltan
  0 siblings, 1 reply; 14+ messages in thread
From: Peter Xu @ 2026-02-11 14:35 UTC (permalink / raw)
  To: BALATON Zoltan
  Cc: Paolo Bonzini, qemu-devel, Akihiko Odaki, Mark Cave-Ayland,
	Gerd Hoffmann, Max Filippov, Peter Maydell,
	Philippe Mathieu-Daudé

On Wed, Feb 11, 2026 at 12:47:53PM +0100, BALATON Zoltan wrote:
> On Wed, 11 Feb 2026, Paolo Bonzini wrote:
> > Il mar 10 feb 2026, 21:02 BALATON Zoltan <balaton@eik.bme.hu> ha scritto:
> > 
> > > Our documentation says that memory regions are automatically freed
> > > when the owner dies and the reference counting to do this is also
> > > implemented. However this relies on the QOM free funtion that can only
> > > be set by creating objects with object_new but memory API only
> > > provides constructors that call object_initialize which clears the
> > > free function that prevents QOM to manage the memory region lifetime.
> > > Implement corresponding memory_region_new_* functions that do the same
> > > as the memory_region_init_* functions but create the memory region
> > > with object_new so the lifetime can be automatically managed by QOM as
> > > documented. The memory_region_init functions are kept because they are
> > > useful for memory regions embedded in other object or managed
> > > externally and not by QOM for some reason.
> > > 
> > 
> > I think there was pretty much agreement *not* to do this?
> 
> Who agreed on that? So far I got concerns that this was too big (that's why
> I split it from the clean ups to show it's not that big change, less than
> 200 lines plus the docs but the clean ups removed as many lines as the doc
> comments add) and others saying this should replace memory_region_init
> altogether (that's way too much churn and not needed IMO) but no clear
> explanation of why this was *not* needed. You as maintainer can say no but
> then please give a justification for why and some solution to the problems
> this tries to fix.

I didn't participate much on this discussion, because I don't think I know
well on this topic.. especially on the Rust implications, comparing to most
of others who should be more familiar with.

However, IMHO, what we really need here is a justification on "why this is
needed", instead of requesting maintainer to say "why it's not needed"..

The rational should be simple to me: by default, we change nothing.  We fix
bugs, but that justifies itself.  If we change something else, we need to
justify the change worthwhile (by the author of the proposal).  If we
change a lot of things, we need serious and strong justifications.

At least I didn't see any Rust mentioned in this cover letter explaining
why we need this change.  I also don't know if the "documentation" issue is
a major flaw to introduce these whole set of new APIs.  For example, could
we fix the doc instead if it is flawed?

Thanks,

-- 
Peter Xu



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v3 0/6] Implement memory_region_new_* functions
  2026-02-11 14:35     ` Peter Xu
@ 2026-02-12 17:37       ` BALATON Zoltan
  2026-02-14 13:44         ` BALATON Zoltan
  0 siblings, 1 reply; 14+ messages in thread
From: BALATON Zoltan @ 2026-02-12 17:37 UTC (permalink / raw)
  To: Peter Xu
  Cc: Paolo Bonzini, qemu-devel, Akihiko Odaki, Mark Cave-Ayland,
	Gerd Hoffmann, Max Filippov, Peter Maydell,
	Philippe Mathieu-Daudé

On Wed, 11 Feb 2026, Peter Xu wrote:
> On Wed, Feb 11, 2026 at 12:47:53PM +0100, BALATON Zoltan wrote:
>> On Wed, 11 Feb 2026, Paolo Bonzini wrote:
>>> Il mar 10 feb 2026, 21:02 BALATON Zoltan <balaton@eik.bme.hu> ha scritto:
>>>
>>>> Our documentation says that memory regions are automatically freed
>>>> when the owner dies and the reference counting to do this is also
>>>> implemented. However this relies on the QOM free funtion that can only
>>>> be set by creating objects with object_new but memory API only
>>>> provides constructors that call object_initialize which clears the
>>>> free function that prevents QOM to manage the memory region lifetime.
>>>> Implement corresponding memory_region_new_* functions that do the same
>>>> as the memory_region_init_* functions but create the memory region
>>>> with object_new so the lifetime can be automatically managed by QOM as
>>>> documented. The memory_region_init functions are kept because they are
>>>> useful for memory regions embedded in other object or managed
>>>> externally and not by QOM for some reason.
>>>>
>>>
>>> I think there was pretty much agreement *not* to do this?
>>
>> Who agreed on that? So far I got concerns that this was too big (that's why
>> I split it from the clean ups to show it's not that big change, less than
>> 200 lines plus the docs but the clean ups removed as many lines as the doc
>> comments add) and others saying this should replace memory_region_init
>> altogether (that's way too much churn and not needed IMO) but no clear
>> explanation of why this was *not* needed. You as maintainer can say no but
>> then please give a justification for why and some solution to the problems
>> this tries to fix.
>
> I didn't participate much on this discussion, because I don't think I know
> well on this topic.. especially on the Rust implications, comparing to most
> of others who should be more familiar with.
>
> However, IMHO, what we really need here is a justification on "why this is
> needed", instead of requesting maintainer to say "why it's not needed"..
>
> The rational should be simple to me: by default, we change nothing.  We fix
> bugs, but that justifies itself.  If we change something else, we need to
> justify the change worthwhile (by the author of the proposal).  If we
> change a lot of things, we need serious and strong justifications.

When somebody submits a patch, the cover letter and commit messages 
describe what and why is prpoposed to be changed. I tried to do that and 
also replied to review comments trying to explain why I think the change 
would help. So I think I gave justification. If I get a reply saying that 
the proposed change is broken, won't work or breaks something then it's 
clear why it's not a good idea. If I get a reply that this would work but 
I don't think it's a good idea then I'd like to also get some explanation 
on why it's not a good idea and if there's a better solution for the 
problems that the poropsed patch tries to fix. That's where the maintainer 
should say why it's not needed.

I try to summarise the problem again briefly as it seems I did not manage 
to explain it in previous messages (or I wrote too much and people did not 
even read it). This again got a bit long but I don't know how to explain 
it better with less words.

Memory regions are registered as a child with an owner and when the owner 
is destroyed it unparents the memory region which decreases its ref count 
so it would be freed if there are no other uses of the memory region. This 
is implemented and documented like that but there's currently no way to 
actually create a memory region that would be managed and freed by QOM 
that way and a memory region created with memory_region_init would never 
be freed and the code to manage memory region lifecycle is effectively 
dead. Because of this we have all sorts of hacks to solve problems that 
arise from this such as memory_region_ref/unref not using the ref count of 
the memory region itself but the ref count of the owner and we embed 
memory regions in devices to avoid leaking them.

My immediate motivation was trying to keep device models simple and avoid 
any additional state or boiler plate code as much as possible because I 
think simple device models are easier to write and easier to find bugs in 
if boiler plate code is not obscuring the actual device functionality. 
Therefore the less additional lines we have to add to a device model is 
the better. A typical example is a memory region of a sysbus or PCI device 
where this would be created with the device and registered via 
sysbus_init_mmio or pci_register_bar. The SysBusDevice state has 
mmio[QDEV_MAX_MMIO] with a MemoryRegion *memory pointer in it and 
PCIDevice has PCIIORegion io_regions[PCI_NUM_REGIONS] where PCIIORegion 
has MemoryRegion *memory so the subclass should not need to store or embed 
these memory regions as QOM should be able to store and manage it. All 
that should be needed in the device model is to define memory ops, create 
the memory region and register it with the superclass and forget about it. 
Reading the documentation of memory regions I was under the impression it 
also works like that but when trying to create such memory regions I was 
told this would leak. Then I looked at why.

I've found that QOM lifecycle management relies on a free function that is 
set by object_new so anything not created with object_new won't be freed. 
QOM has two ways to create objects: object_new and object_initialize 
(latter of which zeroes the free function so this will never be freed by 
QOM) and there's no way to set a free function any other way. The 
memory_region_init* functions call object_initialze so they cannot create 
regions that QOM will manage. To understand this better look at: 
system/memory.c::memory_region_init(), qom/object.c::object_finalize(), 
qom/object.c::object_new() and qom/object.c::object_initialize_with_type() 
(note the memset in object_initialize_with_type).

There are two possible ways to fix this: remove object_initialize from 
memory_region_init so callers could do object_new; memory_region_init or 
object_initialize; memory_region_init or add corresponding 
memory_region_new functions. The latter seems to be less churn and more 
convenient to use so that's what this series does.

With this series we can have

struct SiI3112PCIState {
     PCIIDEState i;

     SiI3112Regs regs[2];
};

instead of

struct SiI3112PCIState {
     PCIIDEState i;

     MemoryRegion mmio;
     MemoryRegion bar0;
     MemoryRegion bar1;
     MemoryRegion bar2;
     MemoryRegion bar3;
     MemoryRegion bar4;
     SiI3112Regs regs[2];
};

or drop an unneeded field from PCIHostState as proposed here:

https://patchew.org/QEMU/cover.1761232472.git.balaton@eik.bme.hu/797587b52159d2db79ed924b4962be7e7ba84207.1761232472.git.balaton@eik.bme.hu/

and several similar simplifications in a lot of devices, that would be 
done as follow up patches not all in this series.

We may also be able to untangle memory_region_ref/unref and just use 
object_ref/unref with memory regions that would be more regular QOM usage 
and may be simpler to follow than the current way of piggy-backing on the 
owner which recently was also found to have some issues.

> At least I didn't see any Rust mentioned in this cover letter explaining
> why we need this change.  I also don't know if the "documentation" issue is
> a major flaw to introduce these whole set of new APIs.  For example, could
> we fix the doc instead if it is flawed?

I don't know if this helps Rust or not, that wasn't brought up by me but I 
guess making memory regions normally managed QOM objects would fit more 
with what Rust expects or can handle than the current way of embedding or 
strangely ref counting regions. As described above the main motivation is 
not to fix documentation but to make it possible to use memory regions as 
documented and intended to avoid some hacks that I think arise from not 
being able to create normal ref counted memory regions that would be freed 
by QOM.

If you think the above is not a problem or this is not the right solution 
for it then I'd like to see a justification on why and what would be a 
better solution. So far I got that it might be that people did not get why 
it is a problem and it works good enough as it is so best not touch it but 
I think the porposed change is simple enough and would allow removing some 
hacks so allow simplifying code and as it does not touch existing 
memory_region_init functions it would also not break anything. Again if 
this was not clear above the series does not add any new way of managing 
memory regions, that's already implemented and always was, this just adds 
the functions that allow it to be used.

Regards,
BALATON Zoltan


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v3 0/6] Implement memory_region_new_* functions
  2026-02-12 17:37       ` BALATON Zoltan
@ 2026-02-14 13:44         ` BALATON Zoltan
  2026-02-14 13:55           ` BALATON Zoltan
  0 siblings, 1 reply; 14+ messages in thread
From: BALATON Zoltan @ 2026-02-14 13:44 UTC (permalink / raw)
  To: Peter Xu
  Cc: Paolo Bonzini, qemu-devel, Akihiko Odaki, Mark Cave-Ayland,
	Gerd Hoffmann, Max Filippov, Peter Maydell,
	Philippe Mathieu-Daudé

On Thu, 12 Feb 2026, BALATON Zoltan wrote:
> Memory regions are registered as a child with an owner and when the owner is 
> destroyed it unparents the memory region which decreases its ref count so it 
> would be freed if there are no other uses of the memory region. This is 
> implemented and documented like that but there's currently no way to actually 
> create a memory region that would be managed and freed by QOM that way and a 
> memory region created with memory_region_init would never be freed and the 
> code to manage memory region lifecycle is effectively dead. Because of this 
> we have all sorts of hacks to solve problems that arise from this such as 
> memory_region_ref/unref not using the ref count of the memory region itself 
> but the ref count of the owner and we embed memory regions in devices to 
> avoid leaking them.

This is an example of hacks that I think arise from not being able to 
create a memory region that is freed with its parent:

https://lists.nongnu.org/archive/html/qemu-devel/2026-02/msg03876.html

This code does a few strange things meddling with internals of memory 
region trying to handle what the ref counts should already take care of. 
It also abuses the free function for something that I'd expect to be done 
in a finalize or unrealize method. I think this could be simplified with 
QOM managed memory regions that this series allow even without untangling 
memory region ref count from the owner but I don't know that code so not 
trying to do a fix. With the current memory_region_init we need to add 
more hacks to make it work but that's both confusing and fragile.

> or drop an unneeded field from PCIHostState as proposed here:
>
> https://patchew.org/QEMU/cover.1761232472.git.balaton@eik.bme.hu/797587b52159d2db79ed924b4962be7e7ba84207.1761232472.git.balaton@eik.bme.hu/

Another point I'd like to clear up here. For the linked patch I was told 
to do this:

struct PREPPCIState {
     PCIHostState parent_obj;

     MemoryRegion mmfg;
}

static void raven_pcihost_init(Object *obj)
{
     PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(obj);
     PCIHostState *h = PCI_HOST_BRIDGE(dev);

     memory_region_init_io(&s->mmcfg, OBJECT(h), &raven_mmcfg_ops, h->bus,
                           "pci-mmcfg", 0x00400000);
}

static void raven_pcihost_realize(DeviceState *d, Error **errp)
{
     PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev);

     memory_region_add_subregion(address_space_mem, 0x80800000, &s->mmcfg);
}

instead of what I think should also work and should be enough:

static void raven_pcihost_realize(DeviceState *d, Error **errp)
{
     PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev);
     PCIHostState *h = PCI_HOST_BRIDGE(dev);
     MemoryRegion *mr;

     mr = memory_region_new_io(OBJECT(s), &raven_mmcfg_ops, h->bus,
                               "pci-mmcfg", 0x00400000);
     memory_region_add_subregion(address_space_mem, 0x80800000, &s->mmcfg);
}

When asking why and if that's really necessary I got referred to some 
obscure conventions that may or may not exist but not documented anywhere 
or just because that's a more canonical way to do this. But is there 
really such convention or any reason to do it the hard way instead of 
allowing simpler device models? I'm all for simplifying devices and be 
able to do it with just the two lines in my second example which works as 
demonstrated by my prep clean up series but was not accepted for reasons I 
could not quite understand. So could this be cleared up too and if there 
are reasons for the first way then explain and document that somewhere?

Regards,
BALATON Zoltan


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v3 0/6] Implement memory_region_new_* functions
  2026-02-14 13:44         ` BALATON Zoltan
@ 2026-02-14 13:55           ` BALATON Zoltan
  0 siblings, 0 replies; 14+ messages in thread
From: BALATON Zoltan @ 2026-02-14 13:55 UTC (permalink / raw)
  To: Peter Xu
  Cc: Paolo Bonzini, qemu-devel, Akihiko Odaki, Mark Cave-Ayland,
	Gerd Hoffmann, Max Filippov, Peter Maydell,
	Philippe Mathieu-Daudé

On Sat, 14 Feb 2026, BALATON Zoltan wrote:
> On Thu, 12 Feb 2026, BALATON Zoltan wrote:
>> Memory regions are registered as a child with an owner and when the owner 
>> is destroyed it unparents the memory region which decreases its ref count 
>> so it would be freed if there are no other uses of the memory region. This 
>> is implemented and documented like that but there's currently no way to 
>> actually create a memory region that would be managed and freed by QOM that 
>> way and a memory region created with memory_region_init would never be 
>> freed and the code to manage memory region lifecycle is effectively dead. 
>> Because of this we have all sorts of hacks to solve problems that arise 
>> from this such as memory_region_ref/unref not using the ref count of the 
>> memory region itself but the ref count of the owner and we embed memory 
>> regions in devices to avoid leaking them.
>
> This is an example of hacks that I think arise from not being able to create 
> a memory region that is freed with its parent:
>
> https://lists.nongnu.org/archive/html/qemu-devel/2026-02/msg03876.html
>
> This code does a few strange things meddling with internals of memory region 
> trying to handle what the ref counts should already take care of. It also 
> abuses the free function for something that I'd expect to be done in a 
> finalize or unrealize method. I think this could be simplified with QOM 
> managed memory regions that this series allow even without untangling memory 
> region ref count from the owner but I don't know that code so not trying to 
> do a fix. With the current memory_region_init we need to add more hacks to 
> make it work but that's both confusing and fragile.
>
>> or drop an unneeded field from PCIHostState as proposed here:
>> 
>> https://patchew.org/QEMU/cover.1761232472.git.balaton@eik.bme.hu/797587b52159d2db79ed924b4962be7e7ba84207.1761232472.git.balaton@eik.bme.hu/
>
> Another point I'd like to clear up here. For the linked patch I was told to 
> do this:
>
> struct PREPPCIState {
>    PCIHostState parent_obj;
>
>    MemoryRegion mmfg;
> }
>
> static void raven_pcihost_init(Object *obj)
> {
>    PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(obj);
>    PCIHostState *h = PCI_HOST_BRIDGE(dev);
>
>    memory_region_init_io(&s->mmcfg, OBJECT(h), &raven_mmcfg_ops, h->bus,
>                          "pci-mmcfg", 0x00400000);
> }
>
> static void raven_pcihost_realize(DeviceState *d, Error **errp)
> {
>    PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev);
>
>    memory_region_add_subregion(address_space_mem, 0x80800000, &s->mmcfg);
> }
>
> instead of what I think should also work and should be enough:
>
> static void raven_pcihost_realize(DeviceState *d, Error **errp)
> {
>    PREPPCIState *s = RAVEN_PCI_HOST_BRIDGE(dev);
>    PCIHostState *h = PCI_HOST_BRIDGE(dev);

dev above is d or obj

>    MemoryRegion *mr;
>
>    mr = memory_region_new_io(OBJECT(s), &raven_mmcfg_ops, h->bus,
>                              "pci-mmcfg", 0x00400000);
>    memory_region_add_subregion(address_space_mem, 0x80800000, &s->mmcfg);

and s->mmcfg here is mr (just copy&pasted these) but you get the idea.

> }
>
> When asking why and if that's really necessary I got referred to some obscure 
> conventions that may or may not exist but not documented anywhere or just 
> because that's a more canonical way to do this. But is there really such 
> convention or any reason to do it the hard way instead of allowing simpler 
> device models? I'm all for simplifying devices and be able to do it with just 
> the two lines in my second example which works as demonstrated by my prep 
> clean up series but was not accepted for reasons I could not quite 
> understand. So could this be cleared up too and if there are reasons for the 
> first way then explain and document that somewhere?
>
> Regards,
> BALATON Zoltan
>
>


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2026-02-14 13:56 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-10 20:02 [PATCH v3 0/6] Implement memory_region_new_* functions BALATON Zoltan
2026-02-10 20:02 ` [PATCH v3 1/6] memory: Add memory_region_new* functions BALATON Zoltan
2026-02-10 20:02 ` [PATCH v3 2/6] memory: Update documentation for memory_region_new*() BALATON Zoltan
2026-02-10 20:02 ` [PATCH v3 3/6] hw/ide/sii3112: Use memory_region_new to avoid leaking regions BALATON Zoltan
2026-02-10 20:02 ` [PATCH v3 4/6] hw/pci-host/articia: Map PCI memory windows in realize BALATON Zoltan
2026-02-10 20:02 ` [PATCH v3 5/6] hw/pci-host/articia: Add variable for common type cast BALATON Zoltan
2026-02-10 20:02 ` [PATCH v3 6/6] hw/xtensa/xtfpga: Fix leaking memory region BALATON Zoltan
2026-02-10 20:58 ` [PATCH v3 0/6] Implement memory_region_new_* functions BALATON Zoltan
2026-02-11  7:00 ` Paolo Bonzini
2026-02-11 11:47   ` BALATON Zoltan
2026-02-11 14:35     ` Peter Xu
2026-02-12 17:37       ` BALATON Zoltan
2026-02-14 13:44         ` BALATON Zoltan
2026-02-14 13:55           ` BALATON Zoltan

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.