diff --git a/Makefile.objs b/Makefile.objs index a3eab4b410..12a314e3fb 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -21,6 +21,13 @@ qom-obj-y = qom/ universal-obj-y += $(qom-obj-y) +####################################################################### +# Core hw code (qdev core) +hw-core-obj-y += hw/ +hw-core-obj-y += qemu-option.o + +universal-obj-y += $(hw-core-obj-y) + ####################################################################### # oslib-obj-y is code depending on the OS (win32 vs posix) oslib-obj-y = osdep.o cutils.o qemu-timer-common.o @@ -182,6 +189,7 @@ nested-vars += \ user-obj-y \ common-obj-y \ universal-obj-y \ + hw-core-obj-y \ extra-obj-y \ trace-obj-y dummy := $(call unnest-vars) diff --git a/hw/Makefile.objs b/hw/Makefile.objs index b8bbed39c1..6b8a68c504 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -1,3 +1,9 @@ +# core qdev-related obj files, also used by *-user: +hw-core-obj-y += qdev.o qdev-properties.o +# irq.o needed for qdev GPIO handling: +hw-core-obj-y += irq.o + + common-obj-y = usb/ ide/ pci/ common-obj-y += loader.o common-obj-$(CONFIG_VIRTIO) += virtio-console.o @@ -154,7 +160,6 @@ common-obj-$(CONFIG_SOUND) += $(sound-obj-y) common-obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/ common-obj-y += usb/ -common-obj-y += irq.o common-obj-$(CONFIG_PTIMER) += ptimer.o common-obj-$(CONFIG_MAX7310) += max7310.o common-obj-$(CONFIG_WM8750) += wm8750.o @@ -180,7 +185,7 @@ common-obj-$(CONFIG_SD) += sd.o common-obj-y += bt.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o common-obj-y += bt-hci-csr.o common-obj-y += msmouse.o ps2.o -common-obj-y += qdev.o qdev-properties.o qdev-monitor.o +common-obj-y += qdev-monitor.o common-obj-y += qdev-properties-system.o common-obj-$(CONFIG_BRLAPI) += baum.o diff --git a/hw/qdev.c b/hw/qdev.c index f2c248451c..e2a5c5735b 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -698,16 +698,18 @@ static void device_class_base_init(ObjectClass *class, void *data) klass->props = NULL; } -static void qdev_remove_from_bus(Object *obj) +static void device_unparent(Object *obj) { DeviceState *dev = DEVICE(obj); - bus_remove_child(dev->parent_bus, dev); + if (dev->parent_bus != NULL) { + bus_remove_child(dev->parent_bus, dev); + } } static void device_class_init(ObjectClass *class, void *data) { - class->unparent = qdev_remove_from_bus; + class->unparent = device_unparent; } void device_reset(DeviceState *dev) diff --git a/include/qemu-common.h b/include/qemu-common.h index 2b83de395c..ca464bb367 100644 --- a/include/qemu-common.h +++ b/include/qemu-common.h @@ -288,7 +288,9 @@ struct qemu_work_item { }; #ifdef CONFIG_USER_ONLY -#define qemu_init_vcpu(env) do { } while (0) +static inline void qemu_init_vcpu(void *env) +{ +} #else void qemu_init_vcpu(void *env); #endif diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 3e9fc3aca5..fbacb2756b 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -20,7 +20,7 @@ #ifndef QEMU_CPU_H #define QEMU_CPU_H -#include "qom/object.h" +#include "hw/qdev-core.h" #include "qemu/thread.h" /** @@ -46,7 +46,7 @@ typedef struct CPUState CPUState; */ typedef struct CPUClass { /*< private >*/ - ObjectClass parent_class; + DeviceClass parent_class; /*< public >*/ void (*reset)(CPUState *cpu); @@ -66,7 +66,7 @@ struct kvm_run; */ struct CPUState { /*< private >*/ - Object parent_obj; + DeviceState parent_obj; /*< public >*/ struct QemuThread *thread; diff --git a/qom/cpu.c b/qom/cpu.c index d4d436f80a..49e5134ea1 100644 --- a/qom/cpu.c +++ b/qom/cpu.c @@ -36,14 +36,16 @@ static void cpu_common_reset(CPUState *cpu) static void cpu_class_init(ObjectClass *klass, void *data) { + DeviceClass *dc = DEVICE_CLASS(klass); CPUClass *k = CPU_CLASS(klass); k->reset = cpu_common_reset; + dc->no_user = 1; } -static TypeInfo cpu_type_info = { +static const TypeInfo cpu_type_info = { .name = TYPE_CPU, - .parent = TYPE_OBJECT, + .parent = TYPE_DEVICE, .instance_size = sizeof(CPUState), .abstract = true, .class_size = sizeof(CPUClass), diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs index 035b29a1f3..7672c69a29 100644 --- a/stubs/Makefile.objs +++ b/stubs/Makefile.objs @@ -5,4 +5,7 @@ stub-obj-y += fdset-get-fd.o stub-obj-y += fdset-remove-fd.o stub-obj-y += get-fd.o stub-obj-y += set-fd-handler.o +stub-obj-y += reset.o +stub-obj-y += vmstate.o +stub-obj-y += sysbus.o stub-obj-$(CONFIG_WIN32) += fd-register.o diff --git a/stubs/reset.c b/stubs/reset.c new file mode 100644 index 0000000000..ad287251ed --- /dev/null +++ b/stubs/reset.c @@ -0,0 +1,13 @@ +#include "hw/hw.h" + +/* Stub functions for binaries that never call qemu_devices_reset(), + * and don't need to keep track of the reset handler list. + */ + +void qemu_register_reset(QEMUResetHandler *func, void *opaque) +{ +} + +void qemu_unregister_reset(QEMUResetHandler *func, void *opaque) +{ +} diff --git a/stubs/sysbus.c b/stubs/sysbus.c new file mode 100644 index 0000000000..e13496582b --- /dev/null +++ b/stubs/sysbus.c @@ -0,0 +1,6 @@ +#include "hw/qdev-core.h" + +BusState *sysbus_get_default(void) +{ + return NULL; +} diff --git a/stubs/vmstate.c b/stubs/vmstate.c new file mode 100644 index 0000000000..3682af599e --- /dev/null +++ b/stubs/vmstate.c @@ -0,0 +1,17 @@ +#include "qemu-common.h" +#include "migration/vmstate.h" + +int vmstate_register_with_alias_id(DeviceState *dev, + int instance_id, + const VMStateDescription *vmsd, + void *base, int alias_id, + int required_for_version) +{ + return 0; +} + +void vmstate_unregister(DeviceState *dev, + const VMStateDescription *vmsd, + void *opaque) +{ +} diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index 212a6250ba..40e980933f 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -26,11 +26,9 @@ static void alpha_cpu_realize(Object *obj, Error **errp) { -#ifndef CONFIG_USER_ONLY AlphaCPU *cpu = ALPHA_CPU(obj); qemu_init_vcpu(&cpu->env); -#endif } /* Sort alphabetically by type name. */ diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 82685dc3f5..78bd61e18f 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -124,15 +124,34 @@ static const char *cpuid_7_0_ebx_feature_name[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, }; +const char *get_register_name_32(unsigned int reg) +{ + static const char *reg_names[CPU_NB_REGS32] = { + [R_EAX] = "EAX", + [R_ECX] = "ECX", + [R_EDX] = "EDX", + [R_EBX] = "EBX", + [R_ESP] = "ESP", + [R_EBP] = "EBP", + [R_ESI] = "ESI", + [R_EDI] = "EDI", + }; + + if (reg > CPU_NB_REGS32) { + return NULL; + } + return reg_names[reg]; +} + /* collects per-function cpuid data */ typedef struct model_features_t { uint32_t *guest_feat; uint32_t *host_feat; - uint32_t check_feat; const char **flag_names; uint32_t cpuid; - } model_features_t; + int reg; +} model_features_t; int check_cpuid = 0; int enforce_cpuid = 0; @@ -388,6 +407,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "core2duo", .level = 10, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 15, .stepping = 11, @@ -432,6 +454,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "qemu32", .level = 4, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 3, .stepping = 3, @@ -442,6 +467,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "kvm32", .level = 5, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 15, .model = 6, .stepping = 1, @@ -456,6 +484,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "coreduo", .level = 10, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 14, .stepping = 8, @@ -471,6 +502,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "486", .level = 1, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 4, .model = 0, .stepping = 0, @@ -480,6 +514,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium", .level = 1, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 5, .model = 4, .stepping = 3, @@ -489,6 +526,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium2", .level = 2, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 5, .stepping = 2, @@ -498,6 +538,9 @@ static x86_def_t builtin_x86_defs[] = { { .name = "pentium3", .level = 2, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 7, .stepping = 3, @@ -523,6 +566,9 @@ static x86_def_t builtin_x86_defs[] = { .name = "n270", /* original is on level 10 */ .level = 5, + .vendor1 = CPUID_VENDOR_INTEL_1, + .vendor2 = CPUID_VENDOR_INTEL_2, + .vendor3 = CPUID_VENDOR_INTEL_3, .family = 6, .model = 28, .stepping = 2, @@ -897,13 +943,12 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def) } } - /* - * Every SVM feature requires emulation support in KVM - so we can't just - * read the host features here. KVM might even support SVM features not - * available on the host hardware. Just set all bits and mask out the - * unsupported ones later. - */ - x86_cpu_def->svm_features = -1; + /* Other KVM-specific feature fields: */ + x86_cpu_def->svm_features = + kvm_arch_get_supported_cpuid(s, 0x8000000A, 0, R_EDX); + x86_cpu_def->kvm_features = + kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX); + #endif /* CONFIG_KVM */ } @@ -913,18 +958,20 @@ static int unavailable_host_feature(struct model_features_t *f, uint32_t mask) for (i = 0; i < 32; ++i) if (1 << i & mask) { - fprintf(stderr, "warning: host cpuid %04x_%04x lacks requested" - " flag '%s' [0x%08x]\n", - f->cpuid >> 16, f->cpuid & 0xffff, - f->flag_names[i] ? f->flag_names[i] : "[reserved]", mask); + const char *reg = get_register_name_32(f->reg); + assert(reg); + fprintf(stderr, "warning: host doesn't support requested feature: " + "CPUID.%02XH:%s%s%s [bit %d]\n", + f->cpuid, reg, + f->flag_names[i] ? "." : "", + f->flag_names[i] ? f->flag_names[i] : "", i); break; } return 0; } /* best effort attempt to inform user requested cpu flags aren't making - * their way to the guest. Note: ft[].check_feat ideally should be - * specified via a guest_def field to suppress report of extraneous flags. + * their way to the guest. * * This function may be called only if KVM is enabled. */ @@ -935,20 +982,21 @@ static int kvm_check_features_against_host(x86_def_t *guest_def) int rv, i; struct model_features_t ft[] = { {&guest_def->features, &host_def.features, - ~0, feature_name, 0x00000000}, + feature_name, 0x00000001, R_EDX}, {&guest_def->ext_features, &host_def.ext_features, - ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001}, + ext_feature_name, 0x00000001, R_ECX}, {&guest_def->ext2_features, &host_def.ext2_features, - ~PPRO_FEATURES, ext2_feature_name, 0x80000000}, + ext2_feature_name, 0x80000001, R_EDX}, {&guest_def->ext3_features, &host_def.ext3_features, - ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}}; + ext3_feature_name, 0x80000001, R_ECX} + }; assert(kvm_enabled()); kvm_cpu_fill_host(&host_def); for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i) for (mask = 1; mask; mask <<= 1) - if (ft[i].check_feat & mask && *ft[i].guest_feat & mask && + if (*ft[i].guest_feat & mask && !(*ft[i].host_feat & mask)) { unavailable_host_feature(&ft[i], mask); rv = 1; @@ -1513,15 +1561,10 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) if (cpu_x86_parse_featurestr(def, features) < 0) { goto error; } - if (def->vendor1) { - env->cpuid_vendor1 = def->vendor1; - env->cpuid_vendor2 = def->vendor2; - env->cpuid_vendor3 = def->vendor3; - } else { - env->cpuid_vendor1 = CPUID_VENDOR_INTEL_1; - env->cpuid_vendor2 = CPUID_VENDOR_INTEL_2; - env->cpuid_vendor3 = CPUID_VENDOR_INTEL_3; - } + assert(def->vendor1); + env->cpuid_vendor1 = def->vendor1; + env->cpuid_vendor2 = def->vendor2; + env->cpuid_vendor3 = def->vendor3; env->cpuid_vendor_override = def->vendor_override; object_property_set_int(OBJECT(cpu), def->level, "level", &error); object_property_set_int(OBJECT(cpu), def->family, "family", &error); @@ -1540,31 +1583,6 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model) object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000, "tsc-frequency", &error); - /* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on - * CPUID[1].EDX. - */ - if (env->cpuid_vendor1 == CPUID_VENDOR_AMD_1 && - env->cpuid_vendor2 == CPUID_VENDOR_AMD_2 && - env->cpuid_vendor3 == CPUID_VENDOR_AMD_3) { - env->cpuid_ext2_features &= ~CPUID_EXT2_AMD_ALIASES; - env->cpuid_ext2_features |= (def->features & CPUID_EXT2_AMD_ALIASES); - } - - if (!kvm_enabled()) { - env->cpuid_features &= TCG_FEATURES; - env->cpuid_ext_features &= TCG_EXT_FEATURES; - env->cpuid_ext2_features &= (TCG_EXT2_FEATURES -#ifdef TARGET_X86_64 - | CPUID_EXT2_SYSCALL | CPUID_EXT2_LM -#endif - ); - env->cpuid_ext3_features &= TCG_EXT3_FEATURES; - env->cpuid_svm_features &= TCG_SVM_FEATURES; - } else { -#ifdef CONFIG_KVM - filter_features_for_kvm(cpu); -#endif - } object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error); if (error) { fprintf(stderr, "%s\n", error_get_pretty(error)); @@ -2085,6 +2103,33 @@ void x86_cpu_realize(Object *obj, Error **errp) env->cpuid_level = 7; } + /* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on + * CPUID[1].EDX. + */ + if (env->cpuid_vendor1 == CPUID_VENDOR_AMD_1 && + env->cpuid_vendor2 == CPUID_VENDOR_AMD_2 && + env->cpuid_vendor3 == CPUID_VENDOR_AMD_3) { + env->cpuid_ext2_features &= ~CPUID_EXT2_AMD_ALIASES; + env->cpuid_ext2_features |= (env->cpuid_features + & CPUID_EXT2_AMD_ALIASES); + } + + if (!kvm_enabled()) { + env->cpuid_features &= TCG_FEATURES; + env->cpuid_ext_features &= TCG_EXT_FEATURES; + env->cpuid_ext2_features &= (TCG_EXT2_FEATURES +#ifdef TARGET_X86_64 + | CPUID_EXT2_SYSCALL | CPUID_EXT2_LM +#endif + ); + env->cpuid_ext3_features &= TCG_EXT3_FEATURES; + env->cpuid_svm_features &= TCG_SVM_FEATURES; + } else { +#ifdef CONFIG_KVM + filter_features_for_kvm(cpu); +#endif + } + #ifndef CONFIG_USER_ONLY qemu_register_reset(x86_cpu_machine_reset_cb, cpu); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 1283537108..e56921bbe3 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1220,4 +1220,7 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); void enable_kvm_pv_eoi(void); +/* Return name of 32-bit register, from a R_* constant */ +const char *get_register_name_32(unsigned int reg); + #endif /* CPU_I386_H */