@@ -24,6 +24,10 @@
* This is an abstract class, subclasses are supposed to be created on
* per-architecture basis to handle the specifics of the cpu architecture.
* Subclasses are meant to be user-creatable (for cold-plug).
+ *
+ * Optionnaly a group of cpus may correspond to a cpu cluster and be
+ * exposed as a gdbstub's inferior. In that case cpus must have the
+ * same memory view.
*/
#define TYPE_CPUS "cpus"
@@ -37,10 +41,18 @@ OBJECT_DECLARE_TYPE(CpusState, CpusClass, CPUS)
* order to eventually update this smoothly with a full
* CpuTopology structure in the future.
* @cpus: Array of pointer to cpu objects.
+ * @cluster_node: node in the global cluster list.
+ * @is_cluster: true if the object corresponds to a cpu cluster. It can be
+ * written before realize in order to enable/disable clustering.
+ * @cluster_index: The cluster ID. This value is for internal use only and
+ * should not be exposed directly to the user or to the guest.
*/
struct CpusState {
/*< private >*/
DeviceState parent_obj;
+ bool is_cluster;
+ int32_t cluster_index;
+ QLIST_ENTRY(CpusState) cluster_node;
/*< public >*/
char *cpu_type;
@@ -68,4 +80,11 @@ struct CpusClass {
bool skip_cpus_creation;
};
+/**
+ * cpus_disable_clustering:
+ * Disable clustering for this object.
+ * Has to be called before realize step.
+ */
+void cpus_disable_clustering(CpusState *s);
+
#endif /* HW_CPU_CPUS_H */
@@ -16,9 +16,17 @@
#include "hw/resettable.h"
#include "sysemu/reset.h"
+static QLIST_HEAD(, CpusState) clusters =
+ QLIST_HEAD_INITIALIZER(clusters);
+
static Property cpus_properties[] = {
DEFINE_PROP_STRING("cpu-type", CpusState, cpu_type),
DEFINE_PROP_UINT16("num-cpus", CpusState, topology.cpus, 0),
+ /*
+ * Default behavior is to automatically compute a valid index.
+ * FIXME: remove this property to keep it internal ?
+ */
+ DEFINE_PROP_INT32("cluster-id", CpusState, cluster_index, -1),
DEFINE_PROP_END_OF_LIST()
};
@@ -30,6 +38,20 @@ static void cpus_reset(Object *obj)
}
}
+static void cpus_init(Object *obj)
+{
+ CpusState *s = CPUS(obj);
+
+ /* may be overriden by subclasses or code to disable clustering */
+ s->is_cluster = true;
+}
+
+void cpus_disable_clustering(CpusState *s)
+{
+ assert(!DEVICE(s)->realized);
+ s->is_cluster = false;
+}
+
static void cpus_create_cpus(CpusState *s, Error **errp)
{
Error *err = NULL;
@@ -44,6 +66,11 @@ static void cpus_create_cpus(CpusState *s, Error **errp)
object_property_add_child(OBJECT(s), "cpu[*]", OBJECT(cpu));
object_unref(OBJECT(cpu));
+ /* set index in case of cluster */
+ if (s->is_cluster) {
+ cpu->cluster_index = s->cluster_index;
+ }
+
/* let subclass configure the cpu */
if (cgc->configure_cpu) {
cgc->configure_cpu(s, cpu, i);
@@ -60,7 +87,7 @@ static void cpus_create_cpus(CpusState *s, Error **errp)
static void cpus_realize(DeviceState *dev, Error **errp)
{
- CpusState *s = CPUS(dev);
+ CpusState *item, *s = CPUS(dev);
CpusClass *cgc = CPUS_GET_CLASS(s);
/* if subclass defined a base type, let's check it */
@@ -77,6 +104,38 @@ static void cpus_realize(DeviceState *dev, Error **errp)
return;
}
+ if (s->is_cluster) {
+ if (s->cluster_index < 0) {
+ int32_t max = -1;
+ QLIST_FOREACH(item, &clusters, cluster_node) {
+ if (max < item->cluster_index) {
+ max = item->cluster_index;
+ }
+ }
+ s->cluster_index = max + 1;
+ } else {
+ /*
+ * Check the index is not already taken.
+ */
+ QLIST_FOREACH(item, &clusters, cluster_node) {
+ if (s->cluster_index == item->cluster_index) {
+ error_setg(errp, "cluster index %d already exists",
+ s->cluster_index);
+ return;
+ }
+ }
+ }
+
+ if (s->cluster_index >= MAX_CLUSTERS) {
+ error_setg(errp, "cluster index must be less than %d",
+ MAX_CLUSTERS);
+ return;
+ }
+
+ /* Put the cpus in the inferior list */
+ QLIST_INSERT_HEAD(&clusters, s, cluster_node);
+ }
+
/* create the cpus if needed */
if (!cgc->skip_cpus_creation) {
cpus_create_cpus(s, errp);
@@ -89,6 +148,9 @@ static void cpus_finalize(Object *obj)
CpusState *s = CPUS(obj);
g_free(s->cpus);
+
+ /* it may not be in the list */
+ QLIST_SAFE_REMOVE(s, cluster_node);
}
static void cpus_class_init(ObjectClass *klass, void *data)
@@ -114,6 +176,7 @@ static const TypeInfo cpus_type_info = {
.parent = TYPE_DEVICE,
.abstract = true,
.instance_size = sizeof(CpusState),
+ .instance_init = cpus_init,
.instance_finalize = cpus_finalize,
.class_size = sizeof(CpusClass),
.class_init = cpus_class_init,
Some group of cpus need to form a cpu cluster to be exposed in gdb as inferiors. Note: 'is_cluster' field is required at least to transition the riscv_hart_array (see following commits about that) Signed-off-by: Damien Hedde <damien.hedde@greensocs.com> --- include/hw/cpu/cpus.h | 19 +++++++++++++ hw/cpu/cpus.c | 65 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 1 deletion(-)