cpu: Use CPUClass->parse_features() as convertor to global properties

Currently CPUClass->parse_features() is used to parse -cpu
features string and set properties on created CPU instances.

But considering that features specified by -cpu apply to every
created CPU instance, it doesn't make sense to parse the same
features string for every CPU created. It also makes every target
that cares about parsing features string explicitly call
CPUClass->parse_features() parser, which gets in a way if we
consider using generic device_add for CPU hotplug as device_add
has not a clue about CPU specific hooks.

Turns out we can use global properties mechanism to set
properties on every created CPU instance for a given type. That
way it's possible to convert CPU features into a set of global
properties for CPU type specified by -cpu cpu_model and common
Device.device_post_init() will apply them to CPU of given type
automatically regardless whether it's manually created CPU or CPU
created with help of device_add.

Backports commits 62a48a2a5798425997152dea3fc48708f9116c04 and
f313369fdb78f849ecbbd8e5d88f01ddf38786c8 from qemu
This commit is contained in:
Igor Mammedov 2018-03-20 11:48:55 -04:00 committed by Lioncash
parent f86355f82c
commit 87db6e033b
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
6 changed files with 78 additions and 25 deletions

View file

@ -226,6 +226,8 @@ struct uc_struct {
QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners; QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners;
QTAILQ_HEAD(, AddressSpace) address_spaces; QTAILQ_HEAD(, AddressSpace) address_spaces;
MachineState *machine_state; MachineState *machine_state;
// qom/cpu.c
bool cpu_globals_initialized;
// qom/object.c // qom/object.c
GHashTable *type_table; GHashTable *type_table;
Type type_interface; Type type_interface;

View file

@ -61,6 +61,7 @@ typedef struct {
static int machvirt_init(struct uc_struct *uc, MachineState *machine) static int machvirt_init(struct uc_struct *uc, MachineState *machine)
{ {
const char *cpu_model = machine->cpu_model; const char *cpu_model = machine->cpu_model;
char **cpustr;
int n; int n;
if (!cpu_model) { if (!cpu_model) {
@ -69,20 +70,31 @@ static int machvirt_init(struct uc_struct *uc, MachineState *machine)
cpu_model = "max"; 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++) { 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; 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) { if (!oc) {
fprintf(stderr, "Unable to find CPU definition\n"); fprintf(stderr, "Unable to find CPU definition\n");
return -1; 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); uc->cpu = CPU(cpuobj);
object_property_set_bool(uc, cpuobj, true, "realized", NULL); object_property_set_bool(uc, cpuobj, true, "realized", NULL);
}
g_free(cpuopts);
}
g_strfreev(cpustr);
return 0; return 0;
} }

View file

@ -124,7 +124,7 @@ typedef struct CPUClass {
/*< public >*/ /*< public >*/
ObjectClass *(*class_by_name)(struct uc_struct *uc, const char *cpu_model); 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); void (*reset)(CPUState *cpu);
int reset_dump_flags; int reset_dump_flags;

View file

@ -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) CPUState *cpu_generic_init(struct uc_struct *uc, const char *typename, const char *cpu_model)
{ {
char *str, *name, *featurestr; char *str, *name, *featurestr;
CPUState *cpu; CPUState *cpu = NULL;
ObjectClass *oc; ObjectClass *oc;
CPUClass *cc; CPUClass *cc;
Error *err = NULL; Error *err = NULL;
@ -58,16 +58,18 @@ CPUState *cpu_generic_init(struct uc_struct *uc, const char *typename, const cha
return NULL; return NULL;
} }
cpu = CPU(object_new(uc, object_class_get_name(oc))); cc = CPU_CLASS(uc, oc);
cc = CPU_GET_CLASS(uc, cpu);
featurestr = strtok(NULL, ","); 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); g_free(str);
if (err != NULL) { if (err != NULL) {
goto out; goto out;
} }
cpu = CPU(object_new(uc, object_class_get_name(oc)));
object_property_set_bool(uc, OBJECT(cpu), true, "realized", &err); object_property_set_bool(uc, OBJECT(cpu), true, "realized", &err);
out: out:
@ -218,25 +220,45 @@ static ObjectClass *cpu_common_class_by_name(struct uc_struct *uc, const char *c
return NULL; 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) Error **errp)
{ {
char *featurestr; /* Single "key=value" string being parsed */ char *featurestr; /* Single "key=value" string being parsed */
char *val; 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; featurestr = features ? strtok(features, ",") : NULL;
while (featurestr) { while (featurestr) {
val = strchr(featurestr, '='); val = strchr(featurestr, '=');
if (val) { if (val) {
// Unicorn: if'd out
#if 0
GlobalProperty *prop = g_new0(GlobalProperty, 1);
#endif
*val = 0; *val = 0;
val++; val++;
object_property_parse(cpu->uc, OBJECT(cpu), val, featurestr, &err);
if (err) { // Unicorn: If'd out
error_propagate(errp, err); #if 0
return; prop->driver = typename;
} prop->property = g_strdup(featurestr);
prop->value = g_strdup(val);
prop->errp = &error_fatal;
qdev_prop_register_global(prop);
#endif
} else { } else {
error_setg(errp, "Expected key=value format, found %s.", error_setg(errp, "Expected key=value format, found %s.",
featurestr); featurestr);

View file

@ -3018,16 +3018,17 @@ static inline void feat2prop(char *s)
/* Parse "+feature,-feature,feature=foo" CPU feature string /* 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) Error **errp)
{ {
X86CPU *cpu = X86_CPU(cs->uc, cs); X86CPU *cpu = X86_CPU(uc, uc->cpu);
char *featurestr; /* Single 'key=value" string being parsed */ char *featurestr; /* Single 'key=value" string being parsed */
Error *local_err = NULL; Error *local_err = NULL;
// Unicorn: added for consistent zeroing out if (cpu->cpu_globals_initialized) {
memset(cpu->plus_features, 0, sizeof(cpu->plus_features)); return;
memset(cpu->minus_features, 0, sizeof(cpu->minus_features)); }
cpu->cpu_globals_initialized = true;
if (!features) { if (!features) {
return; return;
@ -3040,6 +3041,10 @@ static void x86_cpu_parse_featurestr(CPUState *cs, char *features,
const char *val = NULL; const char *val = NULL;
char *eq = NULL; char *eq = NULL;
char num[32]; char num[32];
// Unicorn: If'd out
#if 0
GlobalProperty *prop;
#endif
/* Compatibility syntax: */ /* Compatibility syntax: */
if (featurestr[0] == '+') { if (featurestr[0] == '+') {
@ -3076,7 +3081,15 @@ static void x86_cpu_parse_featurestr(CPUState *cs, char *features,
name = "tsc-frequency"; 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) { if (local_err) {
@ -3164,9 +3177,11 @@ X86CPU *cpu_x86_create(struct uc_struct *uc, const char *cpu_model, Error **errp
{ {
X86CPU *cpu = NULL; X86CPU *cpu = NULL;
ObjectClass *oc; ObjectClass *oc;
CPUClass *cc;
gchar **model_pieces; gchar **model_pieces;
char *name, *features; char *name, *features;
Error *error = NULL; Error *error = NULL;
const char *typename;
model_pieces = g_strsplit(cpu_model, ",", 2); model_pieces = g_strsplit(cpu_model, ",", 2);
if (!model_pieces[0]) { 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); error_setg(&error, "Unable to find CPU definition: %s", name);
goto out; 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))); cc->parse_features(uc, typename, features, &error);
cpu = X86_CPU(uc, object_new(uc, typename));
x86_cpu_parse_featurestr(CPU(cpu), features, &error);
if (error) { if (error) {
goto out; goto out;
} }

View file

@ -1211,6 +1211,7 @@ typedef struct CPUX86State {
// Unicorn engine // Unicorn engine
struct uc_struct *uc; struct uc_struct *uc;
bool cpu_globals_initialized;
} CPUX86State; } CPUX86State;
/** /**