* [PATCH v5 1/7] memory: Export memory_region_set_ops()
2026-05-25 15:47 [PATCH v5 0/7] Implement memory_region_new_* functions BALATON Zoltan
@ 2026-05-25 15:47 ` BALATON Zoltan
2026-05-25 20:01 ` Peter Maydell
2026-05-25 15:47 ` [PATCH v5 2/7] memory: Add memory_region_new* functions BALATON Zoltan
` (6 subsequent siblings)
7 siblings, 1 reply; 13+ messages in thread
From: BALATON Zoltan @ 2026-05-25 15:47 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, Max Filippov,
Peter Maydell, Philippe Mathieu-Daudé
Make memory_region_set_ops() function public. In some cases such as
when devices have configurable endianness or different behaviour based
on settings it is necessary to change the ops callback after the
memory region is created. Export memory_region_set_ops() function for
this.
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---
include/system/memory.h | 13 +++++++++++++
system/memory.c | 7 +++----
2 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/include/system/memory.h b/include/system/memory.h
index 1417132f6d..da07b52885 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -1343,6 +1343,19 @@ void memory_region_ref(MemoryRegion *mr);
*/
void memory_region_unref(MemoryRegion *mr);
+/**
+ * memory_region_set_ops: Set ops of an I/O memory region.
+ *
+ * Accesses into the region will cause the callbacks in @ops to be called.
+ *
+ * @mr: the #MemoryRegion to be changed.
+ * @ops: a structure containing read and write callbacks to be used when
+ * I/O is performed on the region.
+ * @opaque: passed to the read and write callbacks of the @ops structure.
+ */
+void memory_region_set_ops(MemoryRegion *mr, const MemoryRegionOps *ops,
+ void *opaque);
+
/**
* memory_region_init_io: Initialize an I/O memory region.
*
diff --git a/system/memory.c b/system/memory.c
index 739ba11da6..edcdf91d48 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -1560,10 +1560,10 @@ MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
}
}
-static void memory_region_set_ops(MemoryRegion *mr,
- const MemoryRegionOps *ops,
- void *opaque)
+void memory_region_set_ops(MemoryRegion *mr, const MemoryRegionOps *ops,
+ void *opaque)
{
+ g_assert(!ops || !(ops->impl.unaligned && !ops->valid.unaligned));
mr->ops = ops ?: &unassigned_mem_ops;
mr->opaque = opaque;
mr->terminates = true;
@@ -1573,7 +1573,6 @@ void memory_region_init_io(MemoryRegion *mr, Object *owner,
const MemoryRegionOps *ops, void *opaque,
const char *name, uint64_t size)
{
- g_assert(!ops || !(ops->impl.unaligned && !ops->valid.unaligned));
memory_region_init(mr, owner, name, size);
memory_region_set_ops(mr, ops, opaque);
}
--
2.41.3
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH v5 1/7] memory: Export memory_region_set_ops()
2026-05-25 15:47 ` [PATCH v5 1/7] memory: Export memory_region_set_ops() BALATON Zoltan
@ 2026-05-25 20:01 ` Peter Maydell
2026-05-25 20:57 ` BALATON Zoltan
0 siblings, 1 reply; 13+ messages in thread
From: Peter Maydell @ 2026-05-25 20:01 UTC (permalink / raw)
To: BALATON Zoltan
Cc: qemu-devel, Peter Xu, Akihiko Odaki, Paolo Bonzini, Max Filippov,
Philippe Mathieu-Daudé
On Mon, 25 May 2026 at 16:47, BALATON Zoltan <balaton@eik.bme.hu> wrote:
>
> Make memory_region_set_ops() function public. In some cases such as
> when devices have configurable endianness or different behaviour based
> on settings it is necessary to change the ops callback after the
> memory region is created. Export memory_region_set_ops() function for
> this.
If some other CPU is in the middle of using the old MemoryRegionOps
when the device swaps them out under its feet, what happens?
You could also remove the old MR from its container and add a different
one with the different behaviour when the guest changes the config,
or have both of them in the container and toggle which is visible
with memory_region_set_enabled(). That might potentially be more
awkward but it would avoid having to look into the memory region
API internals.
-- PMM
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v5 1/7] memory: Export memory_region_set_ops()
2026-05-25 20:01 ` Peter Maydell
@ 2026-05-25 20:57 ` BALATON Zoltan
2026-05-28 13:39 ` Peter Xu
0 siblings, 1 reply; 13+ messages in thread
From: BALATON Zoltan @ 2026-05-25 20:57 UTC (permalink / raw)
To: Peter Maydell
Cc: qemu-devel, Peter Xu, Akihiko Odaki, Paolo Bonzini, Max Filippov,
Philippe Mathieu-Daudé
On Mon, 25 May 2026, Peter Maydell wrote:
> On Mon, 25 May 2026 at 16:47, BALATON Zoltan <balaton@eik.bme.hu> wrote:
>>
>> Make memory_region_set_ops() function public. In some cases such as
>> when devices have configurable endianness or different behaviour based
>> on settings it is necessary to change the ops callback after the
>> memory region is created. Export memory_region_set_ops() function for
>> this.
>
> If some other CPU is in the middle of using the old MemoryRegionOps
> when the device swaps them out under its feet, what happens?
In my limited test with PPC and ati-vga this seems to work and the switch
would happen in device register write so nothing else is expected to run
accessing the device at the same time at that point. I can't tell for all
possible cases but that would then be a problem in the caller not in this
function. Callers are expected to call it when appropriate which I could
mention in the doc comment if needed.
> You could also remove the old MR from its container and add a different
> one with the different behaviour when the guest changes the config,
> or have both of them in the container and toggle which is visible
> with memory_region_set_enabled(). That might potentially be more
> awkward but it would avoid having to look into the memory region
> API internals.
That could also work if I had a container but it's switching the
endianness of a PCI BAR which is registered with pci_register_bar() so
it's easiest to switch the ops on the region than hacking around it using
two more otherwise unneeded memory regions as I also can't swap PCI BARs
so it would need a container aditionally to two regions using the same
callbacks just with different endianness. Allowing setting the ops of a
single region seems simpler.
Regards,
BALATON Zoltan
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v5 1/7] memory: Export memory_region_set_ops()
2026-05-25 20:57 ` BALATON Zoltan
@ 2026-05-28 13:39 ` Peter Xu
0 siblings, 0 replies; 13+ messages in thread
From: Peter Xu @ 2026-05-28 13:39 UTC (permalink / raw)
To: BALATON Zoltan
Cc: Peter Maydell, qemu-devel, Akihiko Odaki, Paolo Bonzini,
Max Filippov, Philippe Mathieu-Daudé
On Mon, May 25, 2026 at 10:57:39PM +0200, BALATON Zoltan wrote:
> On Mon, 25 May 2026, Peter Maydell wrote:
> > On Mon, 25 May 2026 at 16:47, BALATON Zoltan <balaton@eik.bme.hu> wrote:
> > >
> > > Make memory_region_set_ops() function public. In some cases such as
> > > when devices have configurable endianness or different behaviour based
> > > on settings it is necessary to change the ops callback after the
> > > memory region is created. Export memory_region_set_ops() function for
> > > this.
> >
> > If some other CPU is in the middle of using the old MemoryRegionOps
> > when the device swaps them out under its feet, what happens?
>
> In my limited test with PPC and ati-vga this seems to work and the switch
> would happen in device register write so nothing else is expected to run
> accessing the device at the same time at that point. I can't tell for all
> possible cases but that would then be a problem in the caller not in this
> function. Callers are expected to call it when appropriate which I could
> mention in the doc comment if needed.
>
> > You could also remove the old MR from its container and add a different
> > one with the different behaviour when the guest changes the config,
> > or have both of them in the container and toggle which is visible
> > with memory_region_set_enabled(). That might potentially be more
> > awkward but it would avoid having to look into the memory region
> > API internals.
>
> That could also work if I had a container but it's switching the endianness
> of a PCI BAR which is registered with pci_register_bar() so it's easiest to
> switch the ops on the region than hacking around it using two more otherwise
> unneeded memory regions as I also can't swap PCI BARs so it would need a
> container aditionally to two regions using the same callbacks just with
> different endianness. Allowing setting the ops of a single region seems
> simpler.
I think PeterM's proposal makes more sense.
Having two MRs registered under the same offset of parent and dynamically
enable/disable seems to be a common way to solve similar problems in QEMU.
I don't see why it is hacky if we can allow dynamic flip of mr->ops, which
smells more risky.
Exporting that API may invite more abuse, which I'm not sure it's good.
The other thing I want to mention is having ops flippable relies on "BQL
serializes everything", but it's already not true with exceptions like
HPET, see memory_region_enable_lockless_io(). I think this will introduce
tech debts that we don't necessarily need.
Thanks,
--
Peter Xu
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v5 2/7] memory: Add memory_region_new* functions
2026-05-25 15:47 [PATCH v5 0/7] Implement memory_region_new_* functions BALATON Zoltan
2026-05-25 15:47 ` [PATCH v5 1/7] memory: Export memory_region_set_ops() BALATON Zoltan
@ 2026-05-25 15:47 ` BALATON Zoltan
2026-05-25 15:47 ` [PATCH v5 3/7] memory: Update documentation for memory_region_new*() BALATON Zoltan
` (5 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: BALATON Zoltan @ 2026-05-25 15:47 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, 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 | 179 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 260 insertions(+)
diff --git a/include/system/memory.h b/include/system/memory.h
index da07b52885..31e555c624 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -1314,6 +1314,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
*
@@ -1377,6 +1381,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
@@ -1403,6 +1413,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
@@ -1435,6 +1451,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
/**
@@ -1470,6 +1496,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.
@@ -1498,6 +1533,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
/**
@@ -1521,6 +1565,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.
@@ -1549,6 +1598,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.
@@ -1568,6 +1622,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
@@ -1633,6 +1693,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.
*
@@ -1662,6 +1732,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.
@@ -1697,6 +1772,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 edcdf91d48..19a9d1cd5d 100644
--- a/system/memory.c
+++ b/system/memory.c
@@ -1252,6 +1252,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));
+
+ g_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)
@@ -1577,6 +1586,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 bool memory_region_set_ram_block(MemoryRegion *mr, RAMBlock *rb)
{
mr->terminates = true;
@@ -1602,6 +1621,20 @@ bool memory_region_init_ram_flags_nomigrate(MemoryRegion *mr, Object *owner,
return memory_region_set_ram_block(mr, rb);
}
+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);
+ RAMBlock *rb;
+
+ mr->ram = true;
+ rb = qemu_ram_alloc(size, ram_flags, mr, errp);
+ return memory_region_set_ram_block(mr, rb) ? mr : NULL;
+}
+
bool memory_region_init_resizeable_ram(MemoryRegion *mr,
Object *owner,
const char *name,
@@ -1620,6 +1653,23 @@ bool memory_region_init_resizeable_ram(MemoryRegion *mr,
return memory_region_set_ram_block(mr, rb);
}
+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);
+ RAMBlock *rb;
+
+ mr->ram = true;
+ rb = qemu_ram_alloc_resizeable(size, max_size, resized, mr, errp);
+ return memory_region_set_ram_block(mr, rb) ? 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,
@@ -1637,6 +1687,25 @@ bool memory_region_init_ram_from_file(MemoryRegion *mr, Object *owner,
return memory_region_set_ram_block(mr, rb);
}
+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);
+ RAMBlock *rb;
+
+ mr->ram = true;
+ mr->readonly = !!(ram_flags & RAM_READONLY);
+ mr->align = align;
+ rb = qemu_ram_alloc_from_file(size, mr, ram_flags, path, offset, errp);
+ return memory_region_set_ram_block(mr, rb) ? 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,
@@ -1651,6 +1720,21 @@ bool memory_region_init_ram_from_fd(MemoryRegion *mr, Object *owner,
false, errp);
return memory_region_set_ram_block(mr, rb);
}
+
+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);
+ RAMBlock *rb;
+
+ mr->ram = true;
+ mr->readonly = !!(ram_flags & RAM_READONLY);
+ rb = qemu_ram_alloc_from_fd(size, size, NULL, mr, ram_flags, fd, offset,
+ false, errp);
+ return memory_region_set_ram_block(mr, rb) ? mr : NULL;
+}
#endif
static void memory_region_set_ram_ptr(MemoryRegion *mr, uint64_t size,
@@ -1671,6 +1755,16 @@ void memory_region_init_ram_ptr(MemoryRegion *mr, Object *owner,
memory_region_set_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);
+
+ mr->ram = true;
+ memory_region_set_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)
@@ -1681,6 +1775,18 @@ void memory_region_init_ram_device_ptr(MemoryRegion *mr, Object *owner,
memory_region_set_ram_ptr(mr, size, ptr);
}
+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);
+ mr->ram = true;
+ mr->ram_device = true;
+ memory_region_set_ram_ptr(mr, size, ptr);
+ return mr;
+}
+
void memory_region_init_alias(MemoryRegion *mr, Object *owner,
const char *name, MemoryRegion *orig,
hwaddr offset, uint64_t size)
@@ -1690,6 +1796,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,
@@ -3712,6 +3871,26 @@ bool memory_region_init_rom_device(MemoryRegion *mr, Object *owner,
return false;
}
+MemoryRegion *memory_region_new_rom_device(Object *owner,
+ const MemoryRegionOps *ops,
+ void *opaque,
+ const char *name, uint64_t size,
+ Error **errp)
+{
+ MemoryRegion *mr;
+ RAMBlock *rb;
+
+ assert(ops);
+ mr = memory_region_new_io(owner, ops, opaque, name, size);
+ rb = qemu_ram_alloc(size, 0, mr, errp);
+ if (memory_region_set_ram_block(mr, rb)) {
+ mr->rom_device = true;
+ memory_region_register_ram(mr, owner);
+ return mr;
+ }
+ return NULL;
+}
+
/*
* 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] 13+ messages in thread* [PATCH v5 3/7] memory: Update documentation for memory_region_new*()
2026-05-25 15:47 [PATCH v5 0/7] Implement memory_region_new_* functions BALATON Zoltan
2026-05-25 15:47 ` [PATCH v5 1/7] memory: Export memory_region_set_ops() BALATON Zoltan
2026-05-25 15:47 ` [PATCH v5 2/7] memory: Add memory_region_new* functions BALATON Zoltan
@ 2026-05-25 15:47 ` BALATON Zoltan
2026-05-25 15:47 ` [PATCH v5 4/7] hw/ide/sii3112: Use memory_region_new to avoid leaking regions BALATON Zoltan
` (4 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: BALATON Zoltan @ 2026-05-25 15:47 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, 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 31e555c624..313460da4c 100644
--- a/include/system/memory.h
+++ b/include/system/memory.h
@@ -1314,6 +1314,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);
@@ -1381,6 +1388,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,
@@ -1413,6 +1427,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,
@@ -1452,6 +1475,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,
@@ -1496,6 +1528,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,
@@ -1534,6 +1575,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,
@@ -1565,6 +1615,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,
@@ -1598,6 +1656,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,
@@ -1622,6 +1689,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,
@@ -1693,6 +1768,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,
@@ -1732,6 +1814,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,
@@ -1772,6 +1861,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] 13+ messages in thread* [PATCH v5 4/7] hw/ide/sii3112: Use memory_region_new to avoid leaking regions
2026-05-25 15:47 [PATCH v5 0/7] Implement memory_region_new_* functions BALATON Zoltan
` (2 preceding siblings ...)
2026-05-25 15:47 ` [PATCH v5 3/7] memory: Update documentation for memory_region_new*() BALATON Zoltan
@ 2026-05-25 15:47 ` BALATON Zoltan
2026-05-25 15:47 ` [PATCH v5 5/7] hw/pci-host/articia: Map PCI memory windows in realize BALATON Zoltan
` (3 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: BALATON Zoltan @ 2026-05-25 15:47 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, 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] 13+ messages in thread* [PATCH v5 5/7] hw/pci-host/articia: Map PCI memory windows in realize
2026-05-25 15:47 [PATCH v5 0/7] Implement memory_region_new_* functions BALATON Zoltan
` (3 preceding siblings ...)
2026-05-25 15:47 ` [PATCH v5 4/7] hw/ide/sii3112: Use memory_region_new to avoid leaking regions BALATON Zoltan
@ 2026-05-25 15:47 ` BALATON Zoltan
2026-05-25 15:47 ` [PATCH v5 6/7] hw/pci-host/articia: Add variable for common type cast BALATON Zoltan
` (2 subsequent siblings)
7 siblings, 0 replies; 13+ messages in thread
From: BALATON Zoltan @ 2026-05-25 15:47 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, 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 9fba5ca03a..bfbacdbdb2 100644
--- a/hw/ppc/amigaone.c
+++ b/hw/ppc/amigaone.c
@@ -34,13 +34,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
@@ -266,7 +259,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;
@@ -307,8 +300,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);
@@ -328,8 +321,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);
@@ -342,17 +335,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] 13+ messages in thread* [PATCH v5 6/7] hw/pci-host/articia: Add variable for common type cast
2026-05-25 15:47 [PATCH v5 0/7] Implement memory_region_new_* functions BALATON Zoltan
` (4 preceding siblings ...)
2026-05-25 15:47 ` [PATCH v5 5/7] hw/pci-host/articia: Map PCI memory windows in realize BALATON Zoltan
@ 2026-05-25 15:47 ` BALATON Zoltan
2026-05-25 15:47 ` [PATCH v5 7/7] hw/xtensa/xtfpga: Fix leaking memory region BALATON Zoltan
2026-05-25 16:06 ` [PATCH v5 0/7] Implement memory_region_new_* functions Paolo Bonzini
7 siblings, 0 replies; 13+ messages in thread
From: BALATON Zoltan @ 2026-05-25 15:47 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, 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] 13+ messages in thread* [PATCH v5 7/7] hw/xtensa/xtfpga: Fix leaking memory region
2026-05-25 15:47 [PATCH v5 0/7] Implement memory_region_new_* functions BALATON Zoltan
` (5 preceding siblings ...)
2026-05-25 15:47 ` [PATCH v5 6/7] hw/pci-host/articia: Add variable for common type cast BALATON Zoltan
@ 2026-05-25 15:47 ` BALATON Zoltan
2026-05-25 16:06 ` [PATCH v5 0/7] Implement memory_region_new_* functions Paolo Bonzini
7 siblings, 0 replies; 13+ messages in thread
From: BALATON Zoltan @ 2026-05-25 15:47 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Xu, Akihiko Odaki, Paolo Bonzini, Max Filippov,
Peter Maydell, Philippe Mathieu-Daudé
Use memory_region_new_ram to avoid leaking memory region.
Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu>
---
hw/xtensa/xtfpga.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/hw/xtensa/xtfpga.c b/hw/xtensa/xtfpga.c
index 33a2d9485c..c826f6a308 100644
--- a/hw/xtensa/xtfpga.c
+++ b/hw/xtensa/xtfpga.c
@@ -161,9 +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(ram, OBJECT(s), "open_eth.ram", 16 * KiB,
- &error_fatal);
+ 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] 13+ messages in thread* Re: [PATCH v5 0/7] Implement memory_region_new_* functions
2026-05-25 15:47 [PATCH v5 0/7] Implement memory_region_new_* functions BALATON Zoltan
` (6 preceding siblings ...)
2026-05-25 15:47 ` [PATCH v5 7/7] hw/xtensa/xtfpga: Fix leaking memory region BALATON Zoltan
@ 2026-05-25 16:06 ` Paolo Bonzini
2026-05-25 16:58 ` BALATON Zoltan
7 siblings, 1 reply; 13+ messages in thread
From: Paolo Bonzini @ 2026-05-25 16:06 UTC (permalink / raw)
To: BALATON Zoltan, qemu-devel
Cc: Peter Xu, Akihiko Odaki, Max Filippov, Peter Maydell,
Philippe Mathieu-Daudé
On 5/25/26 17:47, BALATON Zoltan wrote:
> Allow creating memory regions that are managed by QOM and freed with
> their owner as it is already documented and implemented but there was
> no way to use it.
It was already explained that this will not be merged.
Paolo
> v5:
> - rebase on master
> - add patch to export memory_region_set_ops (needed for ati-vga endian
> switch)
>
> v4:
> - rebase on latest version of clean up series:
> Based-on: cover.1772924151.git.balaton@eik.bme.hu
>
> v3:
> - based on split off clean up 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 (7):
> memory: Export memory_region_set_ops()
> 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 | 5 +-
> include/system/memory.h | 192 ++++++++++++++++++++++++++++++++++++++++
> system/memory.c | 186 +++++++++++++++++++++++++++++++++++++-
> 8 files changed, 421 insertions(+), 76 deletions(-)
>
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v5 0/7] Implement memory_region_new_* functions
2026-05-25 16:06 ` [PATCH v5 0/7] Implement memory_region_new_* functions Paolo Bonzini
@ 2026-05-25 16:58 ` BALATON Zoltan
0 siblings, 0 replies; 13+ messages in thread
From: BALATON Zoltan @ 2026-05-25 16:58 UTC (permalink / raw)
To: Paolo Bonzini
Cc: qemu-devel, Peter Xu, Akihiko Odaki, Max Filippov, Peter Maydell,
Philippe Mathieu-Daudé
On Mon, 25 May 2026, Paolo Bonzini wrote:
> On 5/25/26 17:47, BALATON Zoltan wrote:
>> Allow creating memory regions that are managed by QOM and freed with
>> their owner as it is already documented and implemented but there was
>> no way to use it.
>
> It was already explained that this will not be merged.
Please explain again why because I did not get a reason for refusing it.
If this won't be merged how should the issues handled here be fixed and
why is that better than this way? (The patches seem to have been mangled
on sending so I'd resend but I at least need the first patch for further
ati-vga patches.)
Regards,
BALATON Zoltan
> Paolo
>
>> v5:
>> - rebase on master
>> - add patch to export memory_region_set_ops (needed for ati-vga endian
>> switch)
>>
>> v4:
>> - rebase on latest version of clean up series:
>> Based-on: cover.1772924151.git.balaton@eik.bme.hu
>>
>> v3:
>> - based on split off clean up 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 (7):
>> memory: Export memory_region_set_ops()
>> 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 | 5 +-
>> include/system/memory.h | 192 ++++++++++++++++++++++++++++++++++++++++
>> system/memory.c | 186 +++++++++++++++++++++++++++++++++++++-
>> 8 files changed, 421 insertions(+), 76 deletions(-)
>>
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread