[PATCH v2 0/6] system/physmem: Enhance the Address Space API

Gustavo Romero posted 6 patches 1 month, 3 weeks ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20251217212018.93320-1-gustavo.romero@linaro.org
Maintainers: Richard Henderson <richard.henderson@linaro.org>, Paolo Bonzini <pbonzini@redhat.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Peter Xu <peterx@redhat.com>, David Hildenbrand <david@kernel.org>, Peter Maydell <peter.maydell@linaro.org>, Zhao Liu <zhao1.liu@intel.com>, Marcelo Tosatti <mtosatti@redhat.com>, Eduardo Habkost <eduardo@habkost.net>
There is a newer version of this series
include/exec/cpu-common.h          | 23 ++++++++++++++++++-----
stubs/cpu-destroy-address-spaces.c |  2 +-
system/cpus.c                      |  4 ++--
system/physmem.c                   | 12 ++++++++++--
target/arm/cpu.c                   | 28 ++++++++++------------------
target/arm/cpu.h                   |  3 ++-
target/i386/cpu.h                  |  1 +
target/i386/kvm/kvm-cpu.c          |  5 +++--
target/i386/kvm/kvm.c              |  4 ++--
target/i386/tcg/system/tcg-cpu.c   |  6 +++---
10 files changed, 52 insertions(+), 36 deletions(-)
[PATCH v2 0/6] system/physmem: Enhance the Address Space API
Posted by Gustavo Romero 1 month, 3 weeks ago
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.

CI results:
https://gitlab.com/gusbromero/qemu/-/pipelines/2220115152

v1:
https://mail.gnu.org/archive/html/qemu-devel/2025-11/msg04406.html


Cheers,
Gustavo

Gustavo Romero (6):
  target/arm: Initialize AS 0 first
  target/arm: Add a _MAX sentinel to ARMASIdx enum
  target/i386: Add a _MAX sentinel to X86ASIdx enum
  system/physmem: Rename cpu_address_space_init
  system/physmem: Add cpu_address_space_init
  system/physmem: Use cpu_address_space_init to set cpu->num_ases

 include/exec/cpu-common.h          | 23 ++++++++++++++++++-----
 stubs/cpu-destroy-address-spaces.c |  2 +-
 system/cpus.c                      |  4 ++--
 system/physmem.c                   | 12 ++++++++++--
 target/arm/cpu.c                   | 28 ++++++++++------------------
 target/arm/cpu.h                   |  3 ++-
 target/i386/cpu.h                  |  1 +
 target/i386/kvm/kvm-cpu.c          |  5 +++--
 target/i386/kvm/kvm.c              |  4 ++--
 target/i386/tcg/system/tcg-cpu.c   |  6 +++---
 10 files changed, 52 insertions(+), 36 deletions(-)

-- 
2.34.1
Re: [PATCH v2 0/6] system/physmem: Enhance the Address Space API
Posted by Philippe Mathieu-Daudé 1 month, 3 weeks ago
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);

---