s390x/cpumodel: "host" and "qemu" as CPU subclasses

This patch introduces two CPU models, "host" and "qemu".
"qemu" is used as default when running under TCG. "host" is used
as default when running under KVM. "host" cannot be used without KVM.
"host" is not migration-safe. They both inherit from the base s390x CPU,
which is turned into an abstract class.

This patch also changes CPU creation to take care of the passed CPU string
and reuses common code parse_features() function for that purpose. Unknown
CPU definitions are now reported. The "-cpu ?" and "query-cpu-definition"
commands are changed to list all CPU subclasses automatically, including
migration-safety and whether static.

Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Message-Id: <20160905085244.99980-3-dahi@linux.vnet.ibm.com>
[CH: fix up self-assignments in s390_cpu_list, as spotted by clang]
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
This commit is contained in:
David Hildenbrand 2016-09-05 10:52:16 +02:00 committed by Cornelia Huck
parent fc4b84b1c6
commit 41868f846d
7 changed files with 229 additions and 28 deletions

View file

@ -101,7 +101,11 @@ void s390_init_cpus(MachineState *machine)
gchar *name;
if (machine->cpu_model == NULL) {
machine->cpu_model = "host";
if (kvm_enabled()) {
machine->cpu_model = "host";
} else {
machine->cpu_model = "qemu";
}
}
cpu_states = g_new0(S390CPU *, max_cpus);

View file

@ -1,5 +1,5 @@
obj-y += translate.o helper.o cpu.o interrupt.o
obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o
obj-y += gdbstub.o
obj-y += gdbstub.o cpu_models.o
obj-$(CONFIG_SOFTMMU) += machine.o ioinst.o arch_dump.o mmu_helper.o
obj-$(CONFIG_KVM) += kvm.o

View file

@ -45,6 +45,10 @@ typedef struct S390CPUClass {
/*< private >*/
CPUClass parent_class;
/*< public >*/
bool kvm_required;
bool is_static;
bool is_migration_safe;
const char *desc;
int64_t next_cpu_id;

View file

@ -44,30 +44,6 @@
#define CR0_RESET 0xE0UL
#define CR14_RESET 0xC2000000UL;
/* generate CPU information for cpu -? */
void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf)
{
#ifdef CONFIG_KVM
(*cpu_fprintf)(f, "s390 %16s\n", "host");
#endif
}
#ifndef CONFIG_USER_ONLY
CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
{
CpuDefinitionInfoList *entry;
CpuDefinitionInfo *info;
info = g_malloc0(sizeof(*info));
info->name = g_strdup("host");
entry = g_malloc0(sizeof(*entry));
entry->value = info;
return entry;
}
#endif
static void s390_cpu_set_pc(CPUState *cs, vaddr value)
{
S390CPU *cpu = S390_CPU(cs);
@ -206,6 +182,12 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp)
CPUS390XState *env = &cpu->env;
Error *err = NULL;
/* the model has to be realized before qemu_init_vcpu() due to kvm */
s390_realize_cpu_model(cs, &err);
if (err) {
goto out;
}
#if !defined(CONFIG_USER_ONLY)
if (cpu->id >= max_cpus) {
error_setg(&err, "Unable to add CPU: %" PRIi64
@ -435,6 +417,7 @@ static void s390_cpu_class_init(ObjectClass *oc, void *data)
scc->cpu_reset = s390_cpu_reset;
scc->initial_cpu_reset = s390_cpu_initial_reset;
cc->reset = s390_cpu_full_reset;
cc->class_by_name = s390_cpu_class_by_name,
cc->has_work = s390_cpu_has_work;
cc->do_interrupt = s390_cpu_do_interrupt;
cc->dump_state = s390_cpu_dump_state;
@ -470,7 +453,7 @@ static const TypeInfo s390_cpu_type_info = {
.instance_size = sizeof(S390CPU),
.instance_init = s390_cpu_initfn,
.instance_finalize = s390_cpu_finalize,
.abstract = false,
.abstract = true,
.class_size = sizeof(S390CPUClass),
.class_init = s390_cpu_class_init,
};

View file

@ -633,6 +633,8 @@ extern void subsystem_reset(void);
void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf);
#define cpu_list s390_cpu_list
void s390_realize_cpu_model(CPUState *cs, Error **errp);
ObjectClass *s390_cpu_class_by_name(const char *name);
#define EXCP_EXT 1 /* external interrupt */
#define EXCP_SVC 2 /* supervisor call (syscall) */

177
target-s390x/cpu_models.c Normal file
View file

@ -0,0 +1,177 @@
/*
* CPU models for s390x
*
* Copyright 2016 IBM Corp.
*
* Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or (at
* your option) any later version. See the COPYING file in the top-level
* directory.
*/
#include "qemu/osdep.h"
#include "cpu.h"
#include "qapi/error.h"
#ifndef CONFIG_USER_ONLY
#include "sysemu/arch_init.h"
#endif
struct S390PrintCpuListInfo {
FILE *f;
fprintf_function print;
};
static void print_cpu_model_list(ObjectClass *klass, void *opaque)
{
struct S390PrintCpuListInfo *info = opaque;
S390CPUClass *scc = S390_CPU_CLASS(klass);
char *name = g_strdup(object_class_get_name(klass));
const char *details = "";
if (scc->is_static) {
details = "(static, migration-safe)";
} else if (scc->is_migration_safe) {
details = "(migration-safe)";
}
/* strip off the -s390-cpu */
g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0;
(*info->print)(info->f, "s390 %-15s %-35s %s\n", name, scc->desc,
details);
g_free(name);
}
void s390_cpu_list(FILE *f, fprintf_function print)
{
struct S390PrintCpuListInfo info = {
.f = f,
.print = print,
};
object_class_foreach(print_cpu_model_list, TYPE_S390_CPU, false, &info);
}
#ifndef CONFIG_USER_ONLY
static void create_cpu_model_list(ObjectClass *klass, void *opaque)
{
CpuDefinitionInfoList **cpu_list = opaque;
CpuDefinitionInfoList *entry;
CpuDefinitionInfo *info;
char *name = g_strdup(object_class_get_name(klass));
S390CPUClass *scc = S390_CPU_CLASS(klass);
/* strip off the -s390-cpu */
g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0;
info = g_malloc0(sizeof(*info));
info->name = name;
info->has_migration_safe = true;
info->migration_safe = scc->is_migration_safe;
info->q_static = scc->is_static;
entry = g_malloc0(sizeof(*entry));
entry->value = info;
entry->next = *cpu_list;
*cpu_list = entry;
}
CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
{
CpuDefinitionInfoList *list = NULL;
object_class_foreach(create_cpu_model_list, TYPE_S390_CPU, false, &list);
return list;
}
#endif
void s390_realize_cpu_model(CPUState *cs, Error **errp)
{
S390CPUClass *xcc = S390_CPU_GET_CLASS(cs);
if (xcc->kvm_required && !kvm_enabled()) {
error_setg(errp, "CPU definition requires KVM");
return;
}
}
#ifdef CONFIG_KVM
static void s390_host_cpu_model_initfn(Object *obj)
{
}
#endif
static void s390_qemu_cpu_model_initfn(Object *obj)
{
}
static void s390_cpu_model_finalize(Object *obj)
{
}
#ifdef CONFIG_KVM
static void s390_host_cpu_model_class_init(ObjectClass *oc, void *data)
{
S390CPUClass *xcc = S390_CPU_CLASS(oc);
xcc->kvm_required = true;
xcc->desc = "KVM only: All recognized features";
}
#endif
static void s390_qemu_cpu_model_class_init(ObjectClass *oc, void *data)
{
S390CPUClass *xcc = S390_CPU_CLASS(oc);
xcc->is_migration_safe = true;
xcc->desc = g_strdup_printf("QEMU Virtual CPU version %s",
qemu_hw_version());
}
#define S390_CPU_TYPE_SUFFIX "-" TYPE_S390_CPU
#define S390_CPU_TYPE_NAME(name) (name S390_CPU_TYPE_SUFFIX)
/* Generate type name for a cpu model. Caller has to free the string. */
static char *s390_cpu_type_name(const char *model_name)
{
return g_strdup_printf(S390_CPU_TYPE_NAME("%s"), model_name);
}
ObjectClass *s390_cpu_class_by_name(const char *name)
{
char *typename = s390_cpu_type_name(name);
ObjectClass *oc;
oc = object_class_by_name(typename);
g_free(typename);
return oc;
}
static const TypeInfo qemu_s390_cpu_type_info = {
.name = S390_CPU_TYPE_NAME("qemu"),
.parent = TYPE_S390_CPU,
.instance_init = s390_qemu_cpu_model_initfn,
.instance_finalize = s390_cpu_model_finalize,
.class_init = s390_qemu_cpu_model_class_init,
};
#ifdef CONFIG_KVM
static const TypeInfo host_s390_cpu_type_info = {
.name = S390_CPU_TYPE_NAME("host"),
.parent = TYPE_S390_CPU,
.instance_init = s390_host_cpu_model_initfn,
.instance_finalize = s390_cpu_model_finalize,
.class_init = s390_host_cpu_model_class_init,
};
#endif
static void register_types(void)
{
type_register_static(&qemu_s390_cpu_type_info);
#ifdef CONFIG_KVM
type_register_static(&host_s390_cpu_type_info);
#endif
}
type_init(register_types)

View file

@ -70,7 +70,38 @@ void s390x_cpu_timer(void *opaque)
S390CPU *cpu_s390x_create(const char *cpu_model, Error **errp)
{
return S390_CPU(object_new(TYPE_S390_CPU));
static bool features_parsed;
char *name, *features;
const char *typename;
ObjectClass *oc;
CPUClass *cc;
name = g_strdup(cpu_model);
features = strchr(name, ',');
if (features) {
features[0] = 0;
features++;
}
oc = cpu_class_by_name(TYPE_S390_CPU, name);
if (!oc) {
error_setg(errp, "Unknown CPU definition \'%s\'", name);
g_free(name);
return NULL;
}
typename = object_class_get_name(oc);
if (!features_parsed) {
features_parsed = true;
cc = CPU_CLASS(oc);
cc->parse_features(typename, features, errp);
}
g_free(name);
if (*errp) {
return NULL;
}
return S390_CPU(CPU(object_new(typename)));
}
S390CPU *s390x_new_cpu(const char *cpu_model, int64_t id, Error **errp)