Hi Gustavo,
On 17/12/25 22:20, Gustavo Romero wrote:
> The proposal in v1 was to allocate all CPUAddressSpace structures
> dynamically as the address spaces were added. However, after private
> discussions with Richard, Peter, and Phil, I agreed to take the opposite
> approach: allocating all defined address spaces (CPUAddressSpace struct)
> for a target statically.
>
> This different approach simplifies the current AS API too for the
> definition of new address spaces for a target, while also simplifying
> the changes necessary to achieve it.
>
> CPUAddressSpace is a tiny structure, so allocating it statically has
> negligible impact. Meanwhile, the AddressSpace struct (inside the
> CPUAddressSpace struct), although larger, is already allocated
> dynamically and allocated only when an address space is required.
>
> The AS API simplification proposed here simply requires calling
> cpu_address_space_init() once to set the total number of ASes supported
> by a given target, and then adding the required address spaces using
> cpu_address_space_add(). Consequently, there is no longer a need to
> precompute the total number of ASes beforehand, which becomes clumsy for
> targets that require different combinations of ASes.
>
> Finally, the problem of mapping a sparse sequence of AS indexes to a
> dense sequence of CPU AS indexes (array indexes) disappears, since a
> CPUAddressSpace struct is statically allocated for all defined ASes
> supported by the target.
What I had in mind is set the max per CPUClass, allocating them all
(currently 1, 2 or 4) then only use what is necessary. Smth like
(untested):
-- >8 --
Author: Philippe Mathieu-Daudé <philmd@linaro.org>
Date: Thu Dec 18 09:39:16 2025 +0100
cpus: Define maximum number of address spaces in CPUClass
Since we know upfront the maximum number of address spaces
a CPU can use, defined it as a CPUClass field, then rather
than allocating on-demand in cpu_address_space_init() and
optionally releasing, allocate them once in cpu_exec_initfn(),
always releasing in cpu_common_finalize().
Finally when possible, reduce the number of used AS in the
CPU DeviceRealize handler, after all properties are set.
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index ab7b59aed2b..76e33749264 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -147,2 +147,4 @@ struct SysemuCPUOps;
* related information.
+ * @address_spaces_max: Maximum number of address spaces usable by this
+ * architecture.
*
@@ -197,2 +199,3 @@ struct CPUClass {
bool gdb_stop_before_watchpoint;
+ unsigned address_spaces_max;
};
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index 8c306c89e45..2921d075065 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -311,3 +311,2 @@ static void cpu_common_initfn(Object *obj)
cpu->as = NULL;
- cpu->num_ases = 0;
/* user-mode doesn't have configurable SMP topology */
@@ -361,2 +360,3 @@ static void cpu_common_finalize(Object *obj)
g_free(cpu->thread);
+ g_free(cpu->cpu_ases);
}
diff --git a/hw/core/cpu-system.c b/hw/core/cpu-system.c
index 8b31c72da4b..fa6aa857981 100644
--- a/hw/core/cpu-system.c
+++ b/hw/core/cpu-system.c
@@ -190,8 +190,2 @@ void cpu_exec_class_post_init(CPUClass *cc)
-void cpu_exec_initfn(CPUState *cpu)
-{
- cpu->memory = get_system_memory();
- object_ref(OBJECT(cpu->memory));
-}
-
static int cpu_common_post_load(void *opaque, int version_id)
diff --git a/system/cpus.c b/system/cpus.c
index ef2d2f241fa..4b9c94d402c 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -720,3 +720,3 @@ void qemu_init_vcpu(CPUState *cpu)
*/
- cpu->num_ases = 1;
+ assert(cpu->num_ases == 1);
cpu_address_space_init(cpu, 0, "cpu-memory", cpu->memory);
diff --git a/system/physmem.c b/system/physmem.c
index cc148d3a409..f5d362c6ea4 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -778,2 +778,13 @@ hwaddr memory_region_section_get_iotlb(CPUState *cpu,
+void cpu_exec_initfn(CPUState *cpu)
+{
+ unsigned max_ases = cpu->cc->address_spaces_max ?: 1;
+
+ cpu->cpu_ases = g_new0(CPUAddressSpace, max_ases);
+ cpu->num_ases = max_ases;
+
+ cpu->memory = get_system_memory();
+ object_ref(OBJECT(cpu->memory));
+}
+
void cpu_address_space_init(CPUState *cpu, int asidx,
@@ -798,6 +809,2 @@ void cpu_address_space_init(CPUState *cpu, int asidx,
- if (!cpu->cpu_ases) {
- cpu->cpu_ases = g_new0(CPUAddressSpace, cpu->num_ases);
- }
-
newas = &cpu->cpu_ases[asidx];
@@ -834,4 +841,2 @@ void cpu_destroy_address_spaces(CPUState *cpu)
}
-
- g_clear_pointer(&cpu->cpu_ases, g_free);
}
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index f1e9ea0a0f8..e9467b68846 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -2393,2 +2393,3 @@ static void arm_cpu_class_init(ObjectClass *oc,
const void *data)
#ifndef CONFIG_USER_ONLY
+ cc->address_spaces_max = 4; /* See ARMASIdx */
cc->sysemu_ops = &arm_sysemu_ops;
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 64177757863..4074183ec67 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -46,2 +46,3 @@
#include "hw/i386/sgx-epc.h"
+#include "hw/i386/x86.h"
#endif
@@ -9520,2 +9521,6 @@ static void x86_cpu_realizefn(DeviceState *dev,
Error **errp)
+ if (!x86_machine_is_smm_enabled(X86_MACHINE(ms))) {
+ cs->num_ases = 1;
+ }
+
qemu_register_reset(x86_cpu_machine_reset_cb, cpu);
@@ -10108,2 +10113,3 @@ static void
x86_cpu_common_class_init(ObjectClass *oc, const void *data)
#ifndef CONFIG_USER_ONLY
+ cc->address_spaces_max = 2; /* See X86ASIdx */
cc->sysemu_ops = &i386_sysemu_ops;
diff --git a/target/i386/kvm/kvm-cpu.c b/target/i386/kvm/kvm-cpu.c
index 9c25b558395..855edd164d2 100644
--- a/target/i386/kvm/kvm-cpu.c
+++ b/target/i386/kvm/kvm-cpu.c
@@ -100,3 +100,2 @@ static bool kvm_cpu_realizefn(CPUState *cs, Error
**errp)
*/
- cs->num_ases =
x86_machine_is_smm_enabled(X86_MACHINE(current_machine)) ? 2 : 1;
cpu_address_space_init(cs, X86ASIdx_MEM, "cpu-memory", cs->memory);
---