diff --git a/exec.c b/exec.c index ce5fadd88a..d817e5f025 100644 --- a/exec.c +++ b/exec.c @@ -526,12 +526,57 @@ void tcg_cpu_address_space_init(CPUState *cpu, AddressSpace *as) } #endif +#ifndef CONFIG_USER_ONLY +static DECLARE_BITMAP(cpu_index_map, MAX_CPUMASK_BITS); + +static int cpu_get_free_index(Error **errp) +{ + int cpu = find_first_zero_bit(cpu_index_map, MAX_CPUMASK_BITS); + + if (cpu >= MAX_CPUMASK_BITS) { + error_setg(errp, "Trying to use more CPUs than max of %d", + MAX_CPUMASK_BITS); + return -1; + } + + bitmap_set(cpu_index_map, cpu, 1); + return cpu; +} + +void cpu_exec_exit(CPUState *cpu) +{ + if (cpu->cpu_index == -1) { + /* cpu_index was never allocated by this @cpu or was already freed. */ + return; + } + + bitmap_clear(cpu_index_map, cpu->cpu_index, 1); + cpu->cpu_index = -1; +} +#else + +static int cpu_get_free_index(Error **errp) +{ + CPUState *some_cpu; + int cpu_index = 0; + + CPU_FOREACH(some_cpu) { + cpu_index++; + } + return cpu_index; +} + +void cpu_exec_exit(CPUState *cpu) +{ +} +#endif + void cpu_exec_init(CPUArchState *env, Error **errp) { CPUState *cpu = ENV_GET_CPU(env); CPUClass *cc = CPU_GET_CLASS(cpu); - CPUState *some_cpu; int cpu_index; + Error *local_err = NULL; #ifndef CONFIG_USER_ONLY cpu->as = &address_space_memory; @@ -542,11 +587,14 @@ void cpu_exec_init(CPUArchState *env, Error **errp) #if defined(CONFIG_USER_ONLY) cpu_list_lock(); #endif - cpu_index = 0; - CPU_FOREACH(some_cpu) { - cpu_index++; + cpu_index = cpu->cpu_index = cpu_get_free_index(&local_err); + if (local_err) { + error_propagate(errp, local_err); +#if defined(CONFIG_USER_ONLY) + cpu_list_unlock(); +#endif + return; } - cpu->cpu_index = cpu_index; QTAILQ_INSERT_TAIL(&cpus, cpu, node); #if defined(CONFIG_USER_ONLY) cpu_list_unlock(); diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 42f42f5a2d..3993042667 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -674,6 +674,7 @@ void cpu_watchpoint_remove_all(CPUState *cpu, int mask); void QEMU_NORETURN cpu_abort(CPUState *cpu, const char *fmt, ...) GCC_FMT_ATTR(2, 3); +void cpu_exec_exit(CPUState *cpu); #ifdef CONFIG_SOFTMMU extern const struct VMStateDescription vmstate_cpu_common; diff --git a/qom/cpu.c b/qom/cpu.c index 56c53a809f..eb9cfeca18 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -312,11 +312,17 @@ static void cpu_common_initfn(Object *obj) CPUState *cpu = CPU(obj); CPUClass *cc = CPU_GET_CLASS(obj); + cpu->cpu_index = -1; cpu->gdb_num_regs = cpu->gdb_num_g_regs = cc->gdb_num_core_regs; QTAILQ_INIT(&cpu->breakpoints); QTAILQ_INIT(&cpu->watchpoints); } +static void cpu_common_finalize(Object *obj) +{ + cpu_exec_exit(CPU(obj)); +} + static int64_t cpu_common_get_arch_id(CPUState *cpu) { return cpu->cpu_index; @@ -358,6 +364,7 @@ static const TypeInfo cpu_type_info = { .parent = TYPE_DEVICE, .instance_size = sizeof(CPUState), .instance_init = cpu_common_initfn, + .instance_finalize = cpu_common_finalize, .abstract = true, .class_size = sizeof(CPUClass), .class_init = cpu_class_init,