diff --git a/include/uc_priv.h b/include/uc_priv.h index 056d345a..d235e3e9 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -226,6 +226,8 @@ struct uc_struct { QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners; QTAILQ_HEAD(, AddressSpace) address_spaces; MachineState *machine_state; + // qom/cpu.c + bool cpu_globals_initialized; // qom/object.c GHashTable *type_table; Type type_interface; diff --git a/qemu/hw/arm/virt.c b/qemu/hw/arm/virt.c index f4087142..35cbf26f 100644 --- a/qemu/hw/arm/virt.c +++ b/qemu/hw/arm/virt.c @@ -61,6 +61,7 @@ typedef struct { static int machvirt_init(struct uc_struct *uc, MachineState *machine) { const char *cpu_model = machine->cpu_model; + char **cpustr; int n; if (!cpu_model) { @@ -69,20 +70,31 @@ static int machvirt_init(struct uc_struct *uc, MachineState *machine) cpu_model = "max"; } + /* Separate the actual CPU model name from any appended features */ + cpustr = g_strsplit(cpu_model, ",", 2); + for (n = 0; n < smp_cpus; n++) { + ObjectClass *oc = cpu_class_by_name(uc, TYPE_ARM_CPU, cpustr[0]); + char *cpuopts = g_strdup(cpustr[1]); + CPUClass *cc = CPU_CLASS(uc, oc); Object *cpuobj; - ObjectClass *oc = cpu_class_by_name(uc, TYPE_ARM_CPU, cpu_model); + Error *err = NULL; + const char *typename = object_class_get_name(oc); if (!oc) { fprintf(stderr, "Unable to find CPU definition\n"); return -1; } - cpuobj = object_new(uc, object_class_get_name(oc)); + /* convert -smp CPU options specified by the user into global props */ + cc->parse_features(uc, typename, cpuopts, &err); + cpuobj = object_new(uc, typename); uc->cpu = CPU(cpuobj); object_property_set_bool(uc, cpuobj, true, "realized", NULL); - } + g_free(cpuopts); + } + g_strfreev(cpustr); return 0; } diff --git a/qemu/include/qom/cpu.h b/qemu/include/qom/cpu.h index 5766d31b..461832bf 100644 --- a/qemu/include/qom/cpu.h +++ b/qemu/include/qom/cpu.h @@ -124,7 +124,7 @@ typedef struct CPUClass { /*< public >*/ ObjectClass *(*class_by_name)(struct uc_struct *uc, const char *cpu_model); - void (*parse_features)(CPUState *cpu, char *str, Error **errp); + void (*parse_features)(struct uc_struct *uc, const char *typename, char *str, Error **errp); void (*reset)(CPUState *cpu); int reset_dump_flags; diff --git a/qemu/qom/cpu.c b/qemu/qom/cpu.c index f44a09af..b9f4b395 100644 --- a/qemu/qom/cpu.c +++ b/qemu/qom/cpu.c @@ -44,7 +44,7 @@ bool cpu_exists(struct uc_struct *uc, int64_t id) CPUState *cpu_generic_init(struct uc_struct *uc, const char *typename, const char *cpu_model) { char *str, *name, *featurestr; - CPUState *cpu; + CPUState *cpu = NULL; ObjectClass *oc; CPUClass *cc; Error *err = NULL; @@ -58,16 +58,18 @@ CPUState *cpu_generic_init(struct uc_struct *uc, const char *typename, const cha return NULL; } - cpu = CPU(object_new(uc, object_class_get_name(oc))); - cc = CPU_GET_CLASS(uc, cpu); - + cc = CPU_CLASS(uc, oc); featurestr = strtok(NULL, ","); - cc->parse_features(cpu, featurestr, &err); + /* TODO: all callers of cpu_generic_init() need to be converted to + * call parse_features() only once, before calling cpu_generic_init(). + */ + cc->parse_features(uc, object_class_get_name(oc), featurestr, &err); g_free(str); if (err != NULL) { goto out; } + cpu = CPU(object_new(uc, object_class_get_name(oc))); object_property_set_bool(uc, OBJECT(cpu), true, "realized", &err); out: @@ -218,25 +220,45 @@ static ObjectClass *cpu_common_class_by_name(struct uc_struct *uc, const char *c return NULL; } -static void cpu_common_parse_features(CPUState *cpu, char *features, +static void cpu_common_parse_features(struct uc_struct *uc, const char *typename, char *features, Error **errp) { char *featurestr; /* Single "key=value" string being parsed */ char *val; - Error *err = NULL; + + /* TODO: all callers of ->parse_features() need to be changed to + * call it only once, so we can remove this check (or change it + * to assert(!cpu_globals_initialized). + * Current callers of ->parse_features() are: + * - machvirt_init() + * - cpu_generic_init() + * - cpu_x86_create() + */ + if (uc->cpu_globals_initialized) { + return; + } + uc->cpu_globals_initialized = true; featurestr = features ? strtok(features, ",") : NULL; while (featurestr) { val = strchr(featurestr, '='); if (val) { + // Unicorn: if'd out +#if 0 + GlobalProperty *prop = g_new0(GlobalProperty, 1); +#endif *val = 0; val++; - object_property_parse(cpu->uc, OBJECT(cpu), val, featurestr, &err); - if (err) { - error_propagate(errp, err); - return; - } + + // Unicorn: If'd out +#if 0 + prop->driver = typename; + prop->property = g_strdup(featurestr); + prop->value = g_strdup(val); + prop->errp = &error_fatal; + qdev_prop_register_global(prop); +#endif } else { error_setg(errp, "Expected key=value format, found %s.", featurestr); diff --git a/qemu/target/i386/cpu.c b/qemu/target/i386/cpu.c index 43444e9d..d56f20d8 100644 --- a/qemu/target/i386/cpu.c +++ b/qemu/target/i386/cpu.c @@ -3018,16 +3018,17 @@ static inline void feat2prop(char *s) /* Parse "+feature,-feature,feature=foo" CPU feature string */ -static void x86_cpu_parse_featurestr(CPUState *cs, char *features, +static void x86_cpu_parse_featurestr(struct uc_struct *uc, const char *typename, char *features, Error **errp) { - X86CPU *cpu = X86_CPU(cs->uc, cs); + X86CPU *cpu = X86_CPU(uc, uc->cpu); char *featurestr; /* Single 'key=value" string being parsed */ Error *local_err = NULL; - // Unicorn: added for consistent zeroing out - memset(cpu->plus_features, 0, sizeof(cpu->plus_features)); - memset(cpu->minus_features, 0, sizeof(cpu->minus_features)); + if (cpu->cpu_globals_initialized) { + return; + } + cpu->cpu_globals_initialized = true; if (!features) { return; @@ -3040,6 +3041,10 @@ static void x86_cpu_parse_featurestr(CPUState *cs, char *features, const char *val = NULL; char *eq = NULL; char num[32]; + // Unicorn: If'd out +#if 0 + GlobalProperty *prop; +#endif /* Compatibility syntax: */ if (featurestr[0] == '+') { @@ -3076,7 +3081,15 @@ static void x86_cpu_parse_featurestr(CPUState *cs, char *features, name = "tsc-frequency"; } - object_property_parse(cs->uc, OBJECT(cpu), val, name, &local_err); + // Unicorn: if'd out +#if 0 + prop = g_new0(GlobalProperty, 1); + prop->driver = typename; + prop->property = g_strdup(name); + prop->value = g_strdup(val); + prop->errp = &error_fatal; + qdev_prop_register_global(prop); +#endif } if (local_err) { @@ -3164,9 +3177,11 @@ X86CPU *cpu_x86_create(struct uc_struct *uc, const char *cpu_model, Error **errp { X86CPU *cpu = NULL; ObjectClass *oc; + CPUClass *cc; gchar **model_pieces; char *name, *features; Error *error = NULL; + const char *typename; model_pieces = g_strsplit(cpu_model, ",", 2); if (!model_pieces[0]) { @@ -3181,10 +3196,11 @@ X86CPU *cpu_x86_create(struct uc_struct *uc, const char *cpu_model, Error **errp error_setg(&error, "Unable to find CPU definition: %s", name); goto out; } + cc = CPU_CLASS(uc, oc); + typename = object_class_get_name(oc); - cpu = X86_CPU(uc, object_new(uc, object_class_get_name(oc))); - - x86_cpu_parse_featurestr(CPU(cpu), features, &error); + cc->parse_features(uc, typename, features, &error); + cpu = X86_CPU(uc, object_new(uc, typename)); if (error) { goto out; } diff --git a/qemu/target/i386/cpu.h b/qemu/target/i386/cpu.h index 6c49ba84..bfdcfb83 100644 --- a/qemu/target/i386/cpu.h +++ b/qemu/target/i386/cpu.h @@ -1211,6 +1211,7 @@ typedef struct CPUX86State { // Unicorn engine struct uc_struct *uc; + bool cpu_globals_initialized; } CPUX86State; /**