@@ -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);
@@ -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
@@ -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;
@@ -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,
};
@@ -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) */
new file mode 100644
@@ -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)
@@ -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)