From 998b7b1db4f61ee2784d8e9050c3dda15abd4425 Mon Sep 17 00:00:00 2001 From: Victor Kaplansky Date: Sun, 9 Aug 2015 12:39:53 +0300 Subject: make: fix where dependency *.d are stored. In rules like "bar/%.o: %.c" there is a difference between $(*D) and $(@D). $(*D) expands to '.', while $(@D) expands to 'bar'. It is cleaner to generate *.d in the same directory where appropriate *.o resides. This allows precise including of dependency info from .d files. As a hack, we also touch two sources for generated *.hex files. Without this hack, anyone doing "git pull; make" will not get *.hex rebuilt correctly since the dependency file would be missing. Signed-off-by: Victor Kaplansky Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/acpi-dsdt.dsl | 1 - hw/i386/q35-acpi-dsdt.dsl | 1 + rules.mak | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/i386/acpi-dsdt.dsl b/hw/i386/acpi-dsdt.dsl index a2d84ec..8dba096 100644 --- a/hw/i386/acpi-dsdt.dsl +++ b/hw/i386/acpi-dsdt.dsl @@ -43,7 +43,6 @@ DefinitionBlock ( #include "acpi-dsdt-hpet.dsl" - /**************************************************************** * PIIX4 PM ****************************************************************/ diff --git a/hw/i386/q35-acpi-dsdt.dsl b/hw/i386/q35-acpi-dsdt.dsl index 16eaca3..7be7b37 100644 --- a/hw/i386/q35-acpi-dsdt.dsl +++ b/hw/i386/q35-acpi-dsdt.dsl @@ -22,6 +22,7 @@ * Based on acpi-dsdt.dsl, but heavily modified for q35 chipset. */ + ACPI_EXTRACT_ALL_CODE Q35AcpiDsdtAmlCode DefinitionBlock ( diff --git a/rules.mak b/rules.mak index aec27f8..6e35c36 100644 --- a/rules.mak +++ b/rules.mak @@ -17,7 +17,7 @@ MAKEFLAGS += -rR QEMU_CXXFLAGS = -D__STDC_LIMIT_MACROS $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls, $(QEMU_CFLAGS)) # Flags for dependency generation -QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(*D)/$(*F).d +QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(@D)/$(*F).d # Same as -I$(SRC_PATH) -I., but for the nested source/object directories QEMU_INCLUDES += -I$( Date: Sun, 9 Aug 2015 12:39:59 +0300 Subject: make: load only required dependency files. The old rules.mak loads dependency .d files using include directive with file glob pattern "*.d". This breaks the build when build tree has left-over *.d files from another build. This patch fixes this by - loading precise list of .d files made from *.o and *.mo. - specifying explicit list of required dependency info files for *.hex autogenerated sources. Note that Makefile still includes some .d in root directory by including "*.d". Signed-off-by: Victor Kaplansky Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/Makefile.objs | 8 +++++++- rules.mak | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index bd4f147..ecdb400 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -7,8 +7,14 @@ obj-$(CONFIG_XEN) += ../xenpv/ xen/ obj-y += kvmvapic.o obj-y += acpi-build.o + +gen-hex-y += hw/i386/acpi-dsdt.hex +gen-hex-y += hw/i386/q35-acpi-dsdt.hex + hw/i386/acpi-build.o: hw/i386/acpi-build.c \ - hw/i386/acpi-dsdt.hex hw/i386/q35-acpi-dsdt.hex + $(gen-hex-y) + +-include $(gen-hex-y:.hex=.d) iasl-option=$(shell if test -z "`$(1) $(2) 2>&1 > /dev/null`" \ ; then echo "$(2)"; else echo "$(3)"; fi ;) diff --git a/rules.mak b/rules.mak index 6e35c36..4551b9e 100644 --- a/rules.mak +++ b/rules.mak @@ -368,6 +368,6 @@ define unnest-vars $(error $o added in $v but $o-objs is not set))) $(shell mkdir -p ./ $(sort $(dir $($v)))) # Include all the .d files - $(eval -include $(addsuffix *.d, $(sort $(dir $($v))))) + $(eval -include $(patsubst %.o,%.d,$(patsubst %.mo,%.d,$($v)))) $(eval $v := $(filter-out %/,$($v)))) endef -- cgit v1.1 From e33d22fab3ad64bedc1c9addb0a0fa437995c12a Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:15:31 -0300 Subject: piix: Document coreboot-specific RAM size config register The existing i440fx initialization code sets a PCI config register that isn't documented anywhere in the Intel 440FX datasheet. Register 0x57 is DRAMC (DRAM Control) and has nothing to do with the RAM size. This was implemented in commit ec5f92ce6ac8ec09056be77e03c941be188648fa because old coreboot code tried to read registers 0x5a-0x5f,0x56,0x57 to get the RAM size from QEMU, but I couldn't find out why coreboot did that. I assume it was a mistake, and the original code was supposed to be reading the DRB[0-7] registers (offsets 0x60-0x67). Document that coreboot-specific register offset in a macro and a comment, for future reference. Cc: Ed Swierk Cc: Richard Smith Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci-host/piix.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hw/pci-host/piix.c b/hw/pci-host/piix.c index ad55f99..1cb25f3 100644 --- a/hw/pci-host/piix.c +++ b/hw/pci-host/piix.c @@ -117,6 +117,11 @@ struct PCII440FXState { #define I440FX_PAM_SIZE 7 #define I440FX_SMRAM 0x72 +/* Older coreboot versions (4.0 and older) read a config register that doesn't + * exist in real hardware, to get the RAM size from QEMU. + */ +#define I440FX_COREBOOT_RAM_SIZE 0x57 + static void piix3_set_irq(void *opaque, int pirq, int level); static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pci_intx); static void piix3_write_config_xen(PCIDevice *dev, @@ -394,7 +399,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, if (ram_size > 255) { ram_size = 255; } - d->config[0x57] = ram_size; + d->config[I440FX_COREBOOT_RAM_SIZE] = ram_size; i440fx_update_memory_mappings(f); -- cgit v1.1 From 27add3814157f5506672e85ff918d1b379ae8ac0 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:55:42 -0300 Subject: pc: Use PC_COMPAT_* for CPUID feature compatibility Now we can use compat_props to keep CPUID feature compatibility, using the boolean QOM properties for CPUID feature flags. This simplifies the compatibility code, and reduces duplication between pc_piix.c and pc_q35.c. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_piix.c | 22 ---------- hw/i386/pc_q35.c | 22 ---------- include/hw/i386/pc.h | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 112 insertions(+), 46 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index a896624..482555f 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -319,24 +319,6 @@ static void pc_compat_2_2(MachineState *machine) { pc_compat_2_3(machine); rsdp_in_ram = false; - x86_cpu_compat_set_features("kvm64", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("kvm32", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Conroe", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Penryn", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Nehalem", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Westmere", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("SandyBridge", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Haswell", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Broadwell", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G1", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G2", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G3", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G4", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G5", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_F16C); - x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); - x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_F16C); - x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); machine->suppress_vmdesc = true; } @@ -346,8 +328,6 @@ static void pc_compat_2_1(MachineState *machine) pc_compat_2_2(machine); smbios_uuid_encoded = false; - x86_cpu_compat_set_features("coreduo", FEAT_1_ECX, CPUID_EXT_VMX, 0); - x86_cpu_compat_set_features("core2duo", FEAT_1_ECX, CPUID_EXT_VMX, 0); x86_cpu_compat_kvm_no_autodisable(FEAT_8000_0001_ECX, CPUID_EXT3_SVM); pcms->enforce_aligned_dimm = false; } @@ -402,8 +382,6 @@ static void pc_compat_1_5(MachineState *machine) static void pc_compat_1_4(MachineState *machine) { pc_compat_1_5(machine); - x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE); - x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ); } static void pc_compat_1_3(MachineState *machine) diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 974aead..1da9b3a 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -302,24 +302,6 @@ static void pc_compat_2_2(MachineState *machine) { pc_compat_2_3(machine); rsdp_in_ram = false; - x86_cpu_compat_set_features("kvm64", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("kvm32", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Conroe", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Penryn", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Nehalem", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Westmere", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("SandyBridge", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Haswell", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Broadwell", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G1", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G2", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G3", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G4", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Opteron_G5", FEAT_1_EDX, 0, CPUID_VME); - x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_F16C); - x86_cpu_compat_set_features("Haswell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); - x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_F16C); - x86_cpu_compat_set_features("Broadwell", FEAT_1_ECX, 0, CPUID_EXT_RDRAND); machine->suppress_vmdesc = true; } @@ -330,8 +312,6 @@ static void pc_compat_2_1(MachineState *machine) pc_compat_2_2(machine); pcms->enforce_aligned_dimm = false; smbios_uuid_encoded = false; - x86_cpu_compat_set_features("coreduo", FEAT_1_ECX, CPUID_EXT_VMX, 0); - x86_cpu_compat_set_features("core2duo", FEAT_1_ECX, CPUID_EXT_VMX, 0); x86_cpu_compat_kvm_no_autodisable(FEAT_8000_0001_ECX, CPUID_EXT3_SVM); } @@ -367,8 +347,6 @@ static void pc_compat_1_5(MachineState *machine) static void pc_compat_1_4(MachineState *machine) { pc_compat_1_5(machine); - x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE); - x86_cpu_compat_set_features("Westmere", FEAT_1_ECX, 0, CPUID_EXT_PCLMULQDQ); } #define DEFINE_Q35_MACHINE(suffix, name, compatfn, optionfn) \ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 954203d..1dca7e7 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -374,11 +374,111 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); #define PC_COMPAT_2_2 \ PC_COMPAT_2_3 \ - HW_COMPAT_2_2 + HW_COMPAT_2_2 \ + {\ + .driver = "kvm64" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "kvm32" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Conroe" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Penryn" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Nehalem" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Westmere" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "SandyBridge" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Haswell" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Broadwell" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Opteron_G1" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Opteron_G2" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Opteron_G3" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Opteron_G4" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Opteron_G5" "-" TYPE_X86_CPU,\ + .property = "vme",\ + .value = "off",\ + },\ + {\ + .driver = "Haswell" "-" TYPE_X86_CPU,\ + .property = "f16c",\ + .value = "off",\ + },\ + {\ + .driver = "Haswell" "-" TYPE_X86_CPU,\ + .property = "rdrand",\ + .value = "off",\ + },\ + {\ + .driver = "Broadwell" "-" TYPE_X86_CPU,\ + .property = "f16c",\ + .value = "off",\ + },\ + {\ + .driver = "Broadwell" "-" TYPE_X86_CPU,\ + .property = "rdrand",\ + .value = "off",\ + }, #define PC_COMPAT_2_1 \ PC_COMPAT_2_2 \ - HW_COMPAT_2_1 + HW_COMPAT_2_1 \ + {\ + .driver = "coreduo" "-" TYPE_X86_CPU,\ + .property = "vmx",\ + .value = "on",\ + },\ + {\ + .driver = "core2duo" "-" TYPE_X86_CPU,\ + .property = "vmx",\ + .value = "on",\ + }, #define PC_COMPAT_2_0 \ PC_COMPAT_2_1 \ @@ -589,6 +689,16 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); .driver = "486-" TYPE_X86_CPU,\ .property = "model",\ .value = stringify(0),\ + },\ + {\ + .driver = "n270" "-" TYPE_X86_CPU,\ + .property = "movbe",\ + .value = "off",\ + },\ + {\ + .driver = "Westmere" "-" TYPE_X86_CPU,\ + .property = "pclmulqdq",\ + .value = "off",\ }, static inline void pc_common_machine_options(MachineClass *m) -- cgit v1.1 From e8963e5cecd4bb47ec3a7221ae591f278de6b5d0 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:55:43 -0300 Subject: target-i386: Remove x86_cpu_compat_set_features() The function is not used by PC code anymore and can be removed. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- target-i386/cpu.c | 26 -------------------------- target-i386/cpu.h | 3 --- 2 files changed, 29 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 7a779b1..cfb8aa7 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1392,32 +1392,6 @@ static X86CPUDefinition builtin_x86_defs[] = { }, }; -/** - * x86_cpu_compat_set_features: - * @cpu_model: CPU model name to be changed. If NULL, all CPU models are changed - * @w: Identifies the feature word to be changed. - * @feat_add: Feature bits to be added to feature word - * @feat_remove: Feature bits to be removed from feature word - * - * Change CPU model feature bits for compatibility. - * - * This function may be used by machine-type compatibility functions - * to enable or disable feature bits on specific CPU models. - */ -void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w, - uint32_t feat_add, uint32_t feat_remove) -{ - X86CPUDefinition *def; - int i; - for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) { - def = &builtin_x86_defs[i]; - if (!cpu_model || !strcmp(cpu_model, def->name)) { - def->features[w] |= feat_add; - def->features[w] &= ~feat_remove; - } - } -} - static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w, bool migratable_only); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index ead2832..74b674d 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1332,9 +1332,6 @@ void cpu_smm_update(X86CPU *cpu); void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); -void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w, - uint32_t feat_add, uint32_t feat_remove); - void x86_cpu_compat_kvm_no_autoenable(FeatureWord w, uint32_t features); void x86_cpu_compat_kvm_no_autodisable(FeatureWord w, uint32_t features); -- cgit v1.1 From dda65c7c4b9b4925bdd056c66d4e1ef5cf4a8fb8 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:55:44 -0300 Subject: pc: Use error_abort when registering properties No errors should happen when registering the properties, but we shouldn't silently ignore them if they happen. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 7661ea9..7c811cd 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1886,39 +1886,39 @@ static void pc_machine_initfn(Object *obj) object_property_add(obj, PC_MACHINE_MEMHP_REGION_SIZE, "int", pc_machine_get_hotplug_memory_region_size, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, &error_abort); pcms->max_ram_below_4g = 1ULL << 32; /* 4G */ object_property_add(obj, PC_MACHINE_MAX_RAM_BELOW_4G, "size", pc_machine_get_max_ram_below_4g, pc_machine_set_max_ram_below_4g, - NULL, NULL, NULL); + NULL, NULL, &error_abort); object_property_set_description(obj, PC_MACHINE_MAX_RAM_BELOW_4G, "Maximum ram below the 4G boundary (32bit boundary)", - NULL); + &error_abort); pcms->smm = ON_OFF_AUTO_AUTO; object_property_add(obj, PC_MACHINE_SMM, "OnOffAuto", pc_machine_get_smm, pc_machine_set_smm, - NULL, NULL, NULL); + NULL, NULL, &error_abort); object_property_set_description(obj, PC_MACHINE_SMM, "Enable SMM (pc & q35)", - NULL); + &error_abort); pcms->vmport = ON_OFF_AUTO_AUTO; object_property_add(obj, PC_MACHINE_VMPORT, "OnOffAuto", pc_machine_get_vmport, pc_machine_set_vmport, - NULL, NULL, NULL); + NULL, NULL, &error_abort); object_property_set_description(obj, PC_MACHINE_VMPORT, "Enable vmport (pc & q35)", - NULL); + &error_abort); pcms->enforce_aligned_dimm = true; object_property_add_bool(obj, PC_MACHINE_ENFORCE_ALIGNED_DIMM, pc_machine_get_aligned_dimm, - NULL, NULL); + NULL, &error_abort); } static unsigned pc_cpu_index_to_socket_id(unsigned cpu_index) -- cgit v1.1 From ec68007a29bff36dab96ae3ea731c85b4b66fdca Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:55:45 -0300 Subject: pc: Rename pc_machine variables to pcms Make the code use the same variable name everywhere. "pcms" is already being used in existing code and it's shorter. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 4 ++-- hw/i386/pc_piix.c | 20 ++++++++++---------- hw/i386/pc_q35.c | 20 ++++++++++---------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 7c811cd..ad1a861 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -435,7 +435,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, { int val; static pc_cmos_init_late_arg arg; - PCMachineState *pc_machine = PC_MACHINE(machine); + PCMachineState *pcms = PC_MACHINE(machine); Error *local_err = NULL; /* various important CMOS locations needed by PC/Bochs bios */ @@ -478,7 +478,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, object_property_add_link(OBJECT(machine), "rtc_state", TYPE_ISA_DEVICE, - (Object **)&pc_machine->rtc, + (Object **)&pcms->rtc, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); object_property_set_link(OBJECT(machine), OBJECT(s), diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 482555f..c88ed0d 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -78,7 +78,7 @@ static bool kvmclock_enabled = true; /* PC hardware initialisation */ static void pc_init1(MachineState *machine) { - PCMachineState *pc_machine = PC_MACHINE(machine); + PCMachineState *pcms = PC_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *system_io = get_system_io(); int i; @@ -117,13 +117,13 @@ static void pc_init1(MachineState *machine) /* Handle the machine opt max-ram-below-4g. It is basically doing * min(qemu limit, user limit). */ - if (lowmem > pc_machine->max_ram_below_4g) { - lowmem = pc_machine->max_ram_below_4g; + if (lowmem > pcms->max_ram_below_4g) { + lowmem = pcms->max_ram_below_4g; if (machine->ram_size - lowmem > lowmem && lowmem & ((1ULL << 30) - 1)) { error_report("Warning: Large machine and max_ram_below_4g(%"PRIu64 ") not a multiple of 1G; possible bad performance.", - pc_machine->max_ram_below_4g); + pcms->max_ram_below_4g); } } @@ -234,14 +234,14 @@ static void pc_init1(MachineState *machine) pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL); - assert(pc_machine->vmport != ON_OFF_AUTO_MAX); - if (pc_machine->vmport == ON_OFF_AUTO_AUTO) { - pc_machine->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON; + assert(pcms->vmport != ON_OFF_AUTO_MAX); + if (pcms->vmport == ON_OFF_AUTO_AUTO) { + pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON; } /* init basic PC hardware */ pc_basic_device_init(isa_bus, gsi, &rtc_state, true, - (pc_machine->vmport != ON_OFF_AUTO_ON), 0x4); + (pcms->vmport != ON_OFF_AUTO_ON), 0x4); pc_nic_init(isa_bus, pci_bus); @@ -286,13 +286,13 @@ static void pc_init1(MachineState *machine) /* TODO: Populate SPD eeprom data. */ smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, gsi[9], smi_irq, - pc_machine_is_smm_enabled(pc_machine), + pc_machine_is_smm_enabled(pcms), &piix4_pm); smbus_eeprom_init(smbus, 8, NULL, 0); object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, TYPE_HOTPLUG_HANDLER, - (Object **)&pc_machine->acpi_dev, + (Object **)&pcms->acpi_dev, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); object_property_set_link(OBJECT(machine), OBJECT(piix4_pm), diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 1da9b3a..d0e4350 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -65,7 +65,7 @@ static bool has_reserved_memory = true; /* PC hardware initialisation */ static void pc_q35_init(MachineState *machine) { - PCMachineState *pc_machine = PC_MACHINE(machine); + PCMachineState *pcms = PC_MACHINE(machine); ram_addr_t below_4g_mem_size, above_4g_mem_size; Q35PCIHost *q35_host; PCIHostState *phb; @@ -108,13 +108,13 @@ static void pc_q35_init(MachineState *machine) /* Handle the machine opt max-ram-below-4g. It is basically doing * min(qemu limit, user limit). */ - if (lowmem > pc_machine->max_ram_below_4g) { - lowmem = pc_machine->max_ram_below_4g; + if (lowmem > pcms->max_ram_below_4g) { + lowmem = pcms->max_ram_below_4g; if (machine->ram_size - lowmem > lowmem && lowmem & ((1ULL << 30) - 1)) { error_report("Warning: Large machine and max_ram_below_4g(%"PRIu64 ") not a multiple of 1G; possible bad performance.", - pc_machine->max_ram_below_4g); + pcms->max_ram_below_4g); } } @@ -207,7 +207,7 @@ static void pc_q35_init(MachineState *machine) object_property_add_link(OBJECT(machine), PC_MACHINE_ACPI_DEVICE_PROP, TYPE_HOTPLUG_HANDLER, - (Object **)&pc_machine->acpi_dev, + (Object **)&pcms->acpi_dev, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); object_property_set_link(OBJECT(machine), OBJECT(lpc), @@ -242,17 +242,17 @@ static void pc_q35_init(MachineState *machine) pc_register_ferr_irq(gsi[13]); - assert(pc_machine->vmport != ON_OFF_AUTO_MAX); - if (pc_machine->vmport == ON_OFF_AUTO_AUTO) { - pc_machine->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON; + assert(pcms->vmport != ON_OFF_AUTO_MAX); + if (pcms->vmport == ON_OFF_AUTO_AUTO) { + pcms->vmport = xen_enabled() ? ON_OFF_AUTO_OFF : ON_OFF_AUTO_ON; } /* init basic PC hardware */ pc_basic_device_init(isa_bus, gsi, &rtc_state, !mc->no_floppy, - (pc_machine->vmport != ON_OFF_AUTO_ON), 0xff0104); + (pcms->vmport != ON_OFF_AUTO_ON), 0xff0104); /* connect pm stuff to lpc */ - ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pc_machine), !mc->no_tco); + ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms), !mc->no_tco); /* ahci and SATA device, for q35 1 ahci controller is built-in */ ahci = pci_create_simple_multifunction(host_bus, -- cgit v1.1 From 8170dfa077761ed979b45f608cf706253a764f0d Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:55:46 -0300 Subject: pc: Move PCMachineClass, PCMachineState to qemu/typedefs.h They will be used inside hw/xen/xen.h, which doesn't include hw/i386/pc.h. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- include/hw/i386/pc.h | 4 +--- include/qemu/typedefs.h | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 1dca7e7..6746097 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -2,6 +2,7 @@ #define HW_PC_H #include "qemu-common.h" +#include "qemu/typedefs.h" #include "exec/memory.h" #include "hw/boards.h" #include "hw/isa/isa.h" @@ -61,9 +62,6 @@ struct PCMachineClass { DeviceState *dev); }; -typedef struct PCMachineState PCMachineState; -typedef struct PCMachineClass PCMachineClass; - #define TYPE_PC_MACHINE "generic-pc-machine" #define PC_MACHINE(obj) \ OBJECT_CHECK(PCMachineState, (obj), TYPE_PC_MACHINE) diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index 6fdcbcd..f8a9dd6 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -58,6 +58,8 @@ typedef struct PCIESlot PCIESlot; typedef struct PCIExpressDevice PCIExpressDevice; typedef struct PCIExpressHost PCIExpressHost; typedef struct PCIHostState PCIHostState; +typedef struct PCMachineState PCMachineState; +typedef struct PCMachineClass PCMachineClass; typedef struct PCMCIACardState PCMCIACardState; typedef struct PixelFormat PixelFormat; typedef struct PropertyInfo PropertyInfo; -- cgit v1.1 From 41742767bfa8127954b6f57b39b590adcde3ac6c Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:55:47 -0300 Subject: pc: Eliminate pc_common_machine_options() All TYPE_PC_MACHINE subclasses call pc_common_machine_options(). TYPE_PC_MACHINE can simply initialize the common options on class_init directly. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 1 + hw/i386/pc_piix.c | 2 -- include/hw/i386/pc.h | 6 ------ 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index ad1a861..583c47a 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1938,6 +1938,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) pcmc->get_hotplug_handler = mc->get_hotplug_handler; mc->get_hotplug_handler = pc_get_hotpug_handler; mc->cpu_index_to_socket_id = pc_cpu_index_to_socket_id; + mc->default_boot_order = "cad"; hc->plug = pc_machine_device_plug_cb; hc->unplug_request = pc_machine_device_unplug_request_cb; hc->unplug = pc_machine_device_unplug_cb; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index c88ed0d..d722518 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -887,7 +887,6 @@ DEFINE_I440FX_MACHINE(v0_10, "pc-0.10", pc_compat_0_13, static void isapc_machine_options(MachineClass *m) { - pc_common_machine_options(m); m->desc = "ISA-only PC"; m->max_cpus = 1; } @@ -899,7 +898,6 @@ DEFINE_PC_MACHINE(isapc, "isapc", pc_init_isa, #ifdef CONFIG_XEN static void xenfv_machine_options(MachineClass *m) { - pc_common_machine_options(m); m->desc = "Xen Fully-virtualized PC"; m->max_cpus = HVM_MAX_VCPUS; m->default_machine_opts = "accel=xen"; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 6746097..1d21ab2 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -699,14 +699,8 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); .value = "off",\ }, -static inline void pc_common_machine_options(MachineClass *m) -{ - m->default_boot_order = "cad"; -} - static inline void pc_default_machine_options(MachineClass *m) { - pc_common_machine_options(m); m->hot_add_cpu = pc_hot_add_cpu; m->max_cpus = 255; } -- cgit v1.1 From 4458fb3a7993249f466662b18ccae75f1a313200 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:55:48 -0300 Subject: pc: Eliminate pc_default_machine_options() The only PC machines that didn't call pc_default_machine_options() were isaps and xenfv. Both were already overwriting max_cpus, and only isapc was not overwriting hot_add_cpu. After making isapc set hot_add_cpu to NULL, we can move the pc_default_machine_options() code the PC common class_init. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 2 ++ hw/i386/pc_piix.c | 1 - hw/i386/pc_q35.c | 1 - include/hw/i386/pc.h | 6 ------ 4 files changed, 2 insertions(+), 8 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 583c47a..29f2b90 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1939,6 +1939,8 @@ static void pc_machine_class_init(ObjectClass *oc, void *data) mc->get_hotplug_handler = pc_get_hotpug_handler; mc->cpu_index_to_socket_id = pc_cpu_index_to_socket_id; mc->default_boot_order = "cad"; + mc->hot_add_cpu = pc_hot_add_cpu; + mc->max_cpus = 255; hc->plug = pc_machine_device_plug_cb; hc->unplug_request = pc_machine_device_unplug_request_cb; hc->unplug = pc_machine_device_unplug_cb; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index d722518..48d56c0 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -449,7 +449,6 @@ static void pc_xen_hvm_init(MachineState *machine) static void pc_i440fx_machine_options(MachineClass *m) { - pc_default_machine_options(m); m->family = "pc_piix"; m->desc = "Standard PC (i440FX + PIIX, 1996)"; m->hot_add_cpu = pc_hot_add_cpu; diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index d0e4350..0706934 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -363,7 +363,6 @@ static void pc_compat_1_4(MachineState *machine) static void pc_q35_machine_options(MachineClass *m) { - pc_default_machine_options(m); m->family = "pc_q35"; m->desc = "Standard PC (Q35 + ICH9, 2009)"; m->hot_add_cpu = pc_hot_add_cpu; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 1d21ab2..0273bec 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -699,12 +699,6 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *); .value = "off",\ }, -static inline void pc_default_machine_options(MachineClass *m) -{ - m->hot_add_cpu = pc_hot_add_cpu; - m->max_cpus = 255; -} - #define DEFINE_PC_MACHINE(suffix, namestr, initfn, optsfn) \ static void pc_machine_##suffix##_class_init(ObjectClass *oc, void *data) \ { \ -- cgit v1.1 From 23d3040704e8e2a10f3e21e2c6594b3a8c7b20db Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:55:49 -0300 Subject: pc: Use PCMachineState for pc_cmos_init() argument pc_cmos_init() already expects a PCMachineState object, there's no point in upcasting it to MachineState before calling the function. While doing it, reorder the arguments so PCMachineState is the first function argument. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 10 +++++----- hw/i386/pc_piix.c | 5 +++-- hw/i386/pc_q35.c | 5 +++-- include/hw/i386/pc.h | 5 +++-- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 29f2b90..255476b 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -428,14 +428,14 @@ static void pc_cmos_init_late(void *opaque) qemu_unregister_reset(pc_cmos_init_late, opaque); } -void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, - const char *boot_device, MachineState *machine, +void pc_cmos_init(PCMachineState *pcms, + ram_addr_t ram_size, ram_addr_t above_4g_mem_size, + const char *boot_device, BusState *idebus0, BusState *idebus1, ISADevice *s) { int val; static pc_cmos_init_late_arg arg; - PCMachineState *pcms = PC_MACHINE(machine); Error *local_err = NULL; /* various important CMOS locations needed by PC/Bochs bios */ @@ -476,12 +476,12 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, /* set the number of CPU */ rtc_set_memory(s, 0x5f, smp_cpus - 1); - object_property_add_link(OBJECT(machine), "rtc_state", + object_property_add_link(OBJECT(pcms), "rtc_state", TYPE_ISA_DEVICE, (Object **)&pcms->rtc, object_property_allow_set_link, OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); - object_property_set_link(OBJECT(machine), OBJECT(s), + object_property_set_link(OBJECT(pcms), OBJECT(s), "rtc_state", &error_abort); set_boot_dev(s, boot_device, &local_err); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 48d56c0..b975c21 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -271,8 +271,9 @@ static void pc_init1(MachineState *machine) } } - pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order, - machine, idebus[0], idebus[1], rtc_state); + pc_cmos_init(pcms, + below_4g_mem_size, above_4g_mem_size, machine->boot_order, + idebus[0], idebus[1], rtc_state); if (pci_enabled && usb_enabled()) { pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci"); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 0706934..441e9d9 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -276,8 +276,9 @@ static void pc_q35_init(MachineState *machine) 0xb100), 8, NULL, 0); - pc_cmos_init(below_4g_mem_size, above_4g_mem_size, machine->boot_order, - machine, idebus[0], idebus[1], rtc_state); + pc_cmos_init(pcms, + below_4g_mem_size, above_4g_mem_size, machine->boot_order, + idebus[0], idebus[1], rtc_state); /* the rest devices to which pci devfn is automatically assigned */ pc_vga_init(isa_bus, host_bus); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 0273bec..d8184cd 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -200,8 +200,9 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, bool no_vmport, uint32 hpet_irqs); void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd); -void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, - const char *boot_device, MachineState *machine, +void pc_cmos_init(PCMachineState *pcms, + ram_addr_t ram_size, ram_addr_t above_4g_mem_size, + const char *boot_device, BusState *ide0, BusState *ide1, ISADevice *s); void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus); -- cgit v1.1 From 62b160c02ca46f0b5a06cc4416c47708c7ffd76b Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:55:50 -0300 Subject: pc: Use PCMachineState for pc_memory_init() argument pc_memory_init() already expects a PCMachineState object, there's no point in upcasting it to MachineState before calling the function. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 4 ++-- hw/i386/pc_piix.c | 2 +- hw/i386/pc_q35.c | 2 +- include/hw/i386/pc.h | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 255476b..a9a9cf4 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1289,7 +1289,7 @@ FWCfgState *xen_load_linux(const char *kernel_filename, return fw_cfg; } -FWCfgState *pc_memory_init(MachineState *machine, +FWCfgState *pc_memory_init(PCMachineState *pcms, MemoryRegion *system_memory, ram_addr_t below_4g_mem_size, ram_addr_t above_4g_mem_size, @@ -1301,7 +1301,7 @@ FWCfgState *pc_memory_init(MachineState *machine, MemoryRegion *ram, *option_rom_mr; MemoryRegion *ram_below_4g, *ram_above_4g; FWCfgState *fw_cfg; - PCMachineState *pcms = PC_MACHINE(machine); + MachineState *machine = MACHINE(pcms); assert(machine->ram_size == below_4g_mem_size + above_4g_mem_size); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index b975c21..18e9aa5 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -178,7 +178,7 @@ static void pc_init1(MachineState *machine) /* allocate ram and load rom/bios */ if (!xen_enabled()) { - pc_memory_init(machine, system_memory, + pc_memory_init(pcms, system_memory, below_4g_mem_size, above_4g_mem_size, rom_memory, &ram_memory, guest_info); } else if (machine->kernel_filename != NULL) { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 441e9d9..6763f0d 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -170,7 +170,7 @@ static void pc_q35_init(MachineState *machine) /* allocate ram and load rom/bios */ if (!xen_enabled()) { - pc_memory_init(machine, get_system_memory(), + pc_memory_init(pcms, get_system_memory(), below_4g_mem_size, above_4g_mem_size, rom_memory, &ram_memory, guest_info); } diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index d8184cd..4fa2b3f 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -185,7 +185,7 @@ FWCfgState *xen_load_linux(const char *kernel_filename, const char *initrd_filename, ram_addr_t below_4g_mem_size, PcGuestInfo *guest_info); -FWCfgState *pc_memory_init(MachineState *machine, +FWCfgState *pc_memory_init(PCMachineState *pcms, MemoryRegion *system_memory, ram_addr_t below_4g_mem_size, ram_addr_t above_4g_mem_size, -- cgit v1.1 From c0aa4e1ecbcad29bb9f1d654f930300b975c3ba8 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:55:51 -0300 Subject: pc: Move {above,below}_4g_mem_size variables to PCMachineState This will make the info readily available for the other initialization functions, and will allow us to simplify their argument list. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc_piix.c | 26 ++++++++++++++------------ hw/i386/pc_q35.c | 24 +++++++++++++----------- include/hw/i386/pc.h | 1 + 3 files changed, 28 insertions(+), 23 deletions(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 18e9aa5..559f4e5 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -82,7 +82,6 @@ static void pc_init1(MachineState *machine) MemoryRegion *system_memory = get_system_memory(); MemoryRegion *system_io = get_system_io(); int i; - ram_addr_t below_4g_mem_size, above_4g_mem_size; PCIBus *pci_bus; ISABus *isa_bus; PCII440FXState *i440fx_state; @@ -128,14 +127,15 @@ static void pc_init1(MachineState *machine) } if (machine->ram_size >= lowmem) { - above_4g_mem_size = machine->ram_size - lowmem; - below_4g_mem_size = lowmem; + pcms->above_4g_mem_size = machine->ram_size - lowmem; + pcms->below_4g_mem_size = lowmem; } else { - above_4g_mem_size = 0; - below_4g_mem_size = machine->ram_size; + pcms->above_4g_mem_size = 0; + pcms->below_4g_mem_size = machine->ram_size; } - if (xen_enabled() && xen_hvm_init(&below_4g_mem_size, &above_4g_mem_size, + if (xen_enabled() && xen_hvm_init(&pcms->below_4g_mem_size, + &pcms->above_4g_mem_size, &ram_memory) != 0) { fprintf(stderr, "xen hardware virtual machine initialisation failed\n"); exit(1); @@ -160,7 +160,8 @@ static void pc_init1(MachineState *machine) rom_memory = system_memory; } - guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size); + guest_info = pc_guest_info_init(pcms->below_4g_mem_size, + pcms->above_4g_mem_size); guest_info->has_acpi_build = has_acpi_build; guest_info->legacy_acpi_table_size = legacy_acpi_table_size; @@ -179,14 +180,14 @@ static void pc_init1(MachineState *machine) /* allocate ram and load rom/bios */ if (!xen_enabled()) { pc_memory_init(pcms, system_memory, - below_4g_mem_size, above_4g_mem_size, + pcms->below_4g_mem_size, pcms->above_4g_mem_size, rom_memory, &ram_memory, guest_info); } else if (machine->kernel_filename != NULL) { /* For xen HVM direct kernel boot, load linux here */ xen_load_linux(machine->kernel_filename, machine->kernel_cmdline, machine->initrd_filename, - below_4g_mem_size, + pcms->below_4g_mem_size, guest_info); } @@ -202,8 +203,8 @@ static void pc_init1(MachineState *machine) if (pci_enabled) { pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi, system_memory, system_io, machine->ram_size, - below_4g_mem_size, - above_4g_mem_size, + pcms->below_4g_mem_size, + pcms->above_4g_mem_size, pci_memory, ram_memory); } else { pci_bus = NULL; @@ -272,7 +273,8 @@ static void pc_init1(MachineState *machine) } pc_cmos_init(pcms, - below_4g_mem_size, above_4g_mem_size, machine->boot_order, + pcms->below_4g_mem_size, pcms->above_4g_mem_size, + machine->boot_order, idebus[0], idebus[1], rtc_state); if (pci_enabled && usb_enabled()) { diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 6763f0d..489dfcb 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -66,7 +66,6 @@ static bool has_reserved_memory = true; static void pc_q35_init(MachineState *machine) { PCMachineState *pcms = PC_MACHINE(machine); - ram_addr_t below_4g_mem_size, above_4g_mem_size; Q35PCIHost *q35_host; PCIHostState *phb; PCIBus *host_bus; @@ -119,14 +118,15 @@ static void pc_q35_init(MachineState *machine) } if (machine->ram_size >= lowmem) { - above_4g_mem_size = machine->ram_size - lowmem; - below_4g_mem_size = lowmem; + pcms->above_4g_mem_size = machine->ram_size - lowmem; + pcms->below_4g_mem_size = lowmem; } else { - above_4g_mem_size = 0; - below_4g_mem_size = machine->ram_size; + pcms->above_4g_mem_size = 0; + pcms->below_4g_mem_size = machine->ram_size; } - if (xen_enabled() && xen_hvm_init(&below_4g_mem_size, &above_4g_mem_size, + if (xen_enabled() && xen_hvm_init(&pcms->below_4g_mem_size, + &pcms->above_4g_mem_size, &ram_memory) != 0) { fprintf(stderr, "xen hardware virtual machine initialisation failed\n"); exit(1); @@ -151,7 +151,8 @@ static void pc_q35_init(MachineState *machine) rom_memory = get_system_memory(); } - guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size); + guest_info = pc_guest_info_init(pcms->below_4g_mem_size, + pcms->above_4g_mem_size); guest_info->isapc_ram_fw = false; guest_info->has_acpi_build = has_acpi_build; guest_info->has_reserved_memory = has_reserved_memory; @@ -171,7 +172,7 @@ static void pc_q35_init(MachineState *machine) /* allocate ram and load rom/bios */ if (!xen_enabled()) { pc_memory_init(pcms, get_system_memory(), - below_4g_mem_size, above_4g_mem_size, + pcms->below_4g_mem_size, pcms->above_4g_mem_size, rom_memory, &ram_memory, guest_info); } @@ -193,8 +194,8 @@ static void pc_q35_init(MachineState *machine) q35_host->mch.pci_address_space = pci_memory; q35_host->mch.system_memory = get_system_memory(); q35_host->mch.address_space_io = get_system_io(); - q35_host->mch.below_4g_mem_size = below_4g_mem_size; - q35_host->mch.above_4g_mem_size = above_4g_mem_size; + q35_host->mch.below_4g_mem_size = pcms->below_4g_mem_size; + q35_host->mch.above_4g_mem_size = pcms->above_4g_mem_size; q35_host->mch.guest_info = guest_info; /* pci */ qdev_init_nofail(DEVICE(q35_host)); @@ -277,7 +278,8 @@ static void pc_q35_init(MachineState *machine) 8, NULL, 0); pc_cmos_init(pcms, - below_4g_mem_size, above_4g_mem_size, machine->boot_order, + pcms->below_4g_mem_size, pcms->above_4g_mem_size, + machine->boot_order, idebus[0], idebus[1], rtc_state); /* the rest devices to which pci devfn is automatically assigned */ diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 4fa2b3f..e1d20ad 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -40,6 +40,7 @@ struct PCMachineState { OnOffAuto vmport; OnOffAuto smm; bool enforce_aligned_dimm; + ram_addr_t below_4g_mem_size, above_4g_mem_size; }; #define PC_MACHINE_ACPI_DEVICE_PROP "acpi-device" -- cgit v1.1 From b9cfc918ddcbbb5d3b8c1a47675b927cc25eb632 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:55:52 -0300 Subject: pc: Use PCMachineState as pc_guest_info_init() argument Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 7 +++---- hw/i386/pc_piix.c | 3 +-- hw/i386/pc_q35.c | 3 +-- include/hw/i386/pc.h | 3 +-- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index a9a9cf4..081ef83 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1189,15 +1189,14 @@ void pc_guest_info_machine_done(Notifier *notifier, void *data) acpi_setup(&guest_info_state->info); } -PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size, - ram_addr_t above_4g_mem_size) +PcGuestInfo *pc_guest_info_init(PCMachineState *pcms) { PcGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state); PcGuestInfo *guest_info = &guest_info_state->info; int i, j; - guest_info->ram_size_below_4g = below_4g_mem_size; - guest_info->ram_size = below_4g_mem_size + above_4g_mem_size; + guest_info->ram_size_below_4g = pcms->below_4g_mem_size; + guest_info->ram_size = pcms->below_4g_mem_size + pcms->above_4g_mem_size; guest_info->apic_id_limit = pc_apic_id_limit(max_cpus); guest_info->apic_xrupt_override = kvm_allows_irq0_override(); guest_info->numa_nodes = nb_numa_nodes; diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 559f4e5..9364c47 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -160,8 +160,7 @@ static void pc_init1(MachineState *machine) rom_memory = system_memory; } - guest_info = pc_guest_info_init(pcms->below_4g_mem_size, - pcms->above_4g_mem_size); + guest_info = pc_guest_info_init(pcms); guest_info->has_acpi_build = has_acpi_build; guest_info->legacy_acpi_table_size = legacy_acpi_table_size; diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 489dfcb..af5fd9f 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -151,8 +151,7 @@ static void pc_q35_init(MachineState *machine) rom_memory = get_system_memory(); } - guest_info = pc_guest_info_init(pcms->below_4g_mem_size, - pcms->above_4g_mem_size); + guest_info = pc_guest_info_init(pcms); guest_info->isapc_ram_fw = false; guest_info->has_acpi_build = has_acpi_build; guest_info->has_reserved_memory = has_reserved_memory; diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index e1d20ad..94d7afb 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -165,8 +165,7 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge); void pc_hot_add_cpu(const int64_t id, Error **errp); void pc_acpi_init(const char *default_dsdt); -PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size, - ram_addr_t above_4g_mem_size); +PcGuestInfo *pc_guest_info_init(PCMachineState *pcms); void pc_set_legacy_acpi_data_size(void); -- cgit v1.1 From df1f79fdbb98f948f0f9d77a5a48a643026ef31d Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:55:53 -0300 Subject: pc: Remove redundant arguments from *load_linux() Remove arguments that can be found in PCMachineState. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 28 ++++++++++++---------------- hw/i386/pc_piix.c | 6 +----- include/hw/i386/pc.h | 5 +---- 3 files changed, 14 insertions(+), 25 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 081ef83..54b28a3 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -809,11 +809,8 @@ static long get_file_size(FILE *f) return size; } -static void load_linux(FWCfgState *fw_cfg, - const char *kernel_filename, - const char *initrd_filename, - const char *kernel_cmdline, - hwaddr max_ram_size) +static void load_linux(PCMachineState *pcms, + FWCfgState *fw_cfg) { uint16_t protocol; int setup_size, kernel_size, initrd_size = 0, cmdline_size; @@ -822,6 +819,10 @@ static void load_linux(FWCfgState *fw_cfg, hwaddr real_addr, prot_addr, cmdline_addr, initrd_addr = 0; FILE *f; char *vmode; + MachineState *machine = MACHINE(pcms); + const char *kernel_filename = machine->kernel_filename; + const char *initrd_filename = machine->initrd_filename; + const char *kernel_cmdline = machine->kernel_cmdline; /* Align to 16 bytes as a paranoia measure */ cmdline_size = (strlen(kernel_cmdline)+16) & ~15; @@ -886,8 +887,8 @@ static void load_linux(FWCfgState *fw_cfg, initrd_max = 0x37ffffff; } - if (initrd_max >= max_ram_size - acpi_data_size) { - initrd_max = max_ram_size - acpi_data_size - 1; + if (initrd_max >= pcms->below_4g_mem_size - acpi_data_size) { + initrd_max = pcms->below_4g_mem_size - acpi_data_size - 1; } fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_ADDR, cmdline_addr); @@ -1263,22 +1264,18 @@ void pc_acpi_init(const char *default_dsdt) } } -FWCfgState *xen_load_linux(const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - ram_addr_t below_4g_mem_size, +FWCfgState *xen_load_linux(PCMachineState *pcms, PcGuestInfo *guest_info) { int i; FWCfgState *fw_cfg; - assert(kernel_filename != NULL); + assert(MACHINE(pcms)->kernel_filename != NULL); fw_cfg = fw_cfg_init_io(BIOS_CFG_IOPORT); rom_set_fw(fw_cfg); - load_linux(fw_cfg, kernel_filename, initrd_filename, - kernel_cmdline, below_4g_mem_size); + load_linux(pcms, fw_cfg); for (i = 0; i < nb_option_roms; i++) { assert(!strcmp(option_rom[i].name, "linuxboot.bin") || !strcmp(option_rom[i].name, "multiboot.bin")); @@ -1400,8 +1397,7 @@ FWCfgState *pc_memory_init(PCMachineState *pcms, } if (linux_boot) { - load_linux(fw_cfg, machine->kernel_filename, machine->initrd_filename, - machine->kernel_cmdline, below_4g_mem_size); + load_linux(pcms, fw_cfg); } for (i = 0; i < nb_option_roms; i++) { diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 9364c47..f64f029 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -183,11 +183,7 @@ static void pc_init1(MachineState *machine) rom_memory, &ram_memory, guest_info); } else if (machine->kernel_filename != NULL) { /* For xen HVM direct kernel boot, load linux here */ - xen_load_linux(machine->kernel_filename, - machine->kernel_cmdline, - machine->initrd_filename, - pcms->below_4g_mem_size, - guest_info); + xen_load_linux(pcms, guest_info); } gsi_state = g_malloc0(sizeof(*gsi_state)); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 94d7afb..c433602 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -180,10 +180,7 @@ void pc_set_legacy_acpi_data_size(void); void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory, MemoryRegion *pci_address_space); -FWCfgState *xen_load_linux(const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - ram_addr_t below_4g_mem_size, +FWCfgState *xen_load_linux(PCMachineState *pcms, PcGuestInfo *guest_info); FWCfgState *pc_memory_init(PCMachineState *pcms, MemoryRegion *system_memory, -- cgit v1.1 From 880768546eabea369068f30f22e5d26aa4c6970b Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:55:54 -0300 Subject: pc: Remove redundant arguments from pc_cmos_init() Remove arguments that can be found in PCMachineState. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 16 +++++++--------- hw/i386/pc_piix.c | 5 +---- hw/i386/pc_q35.c | 5 +---- include/hw/i386/pc.h | 2 -- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 54b28a3..681ea85 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -429,8 +429,6 @@ static void pc_cmos_init_late(void *opaque) } void pc_cmos_init(PCMachineState *pcms, - ram_addr_t ram_size, ram_addr_t above_4g_mem_size, - const char *boot_device, BusState *idebus0, BusState *idebus1, ISADevice *s) { @@ -442,12 +440,12 @@ void pc_cmos_init(PCMachineState *pcms, /* memory size */ /* base memory (first MiB) */ - val = MIN(ram_size / 1024, 640); + val = MIN(pcms->below_4g_mem_size / 1024, 640); rtc_set_memory(s, 0x15, val); rtc_set_memory(s, 0x16, val >> 8); /* extended memory (next 64MiB) */ - if (ram_size > 1024 * 1024) { - val = (ram_size - 1024 * 1024) / 1024; + if (pcms->below_4g_mem_size > 1024 * 1024) { + val = (pcms->below_4g_mem_size - 1024 * 1024) / 1024; } else { val = 0; } @@ -458,8 +456,8 @@ void pc_cmos_init(PCMachineState *pcms, rtc_set_memory(s, 0x30, val); rtc_set_memory(s, 0x31, val >> 8); /* memory between 16MiB and 4GiB */ - if (ram_size > 16 * 1024 * 1024) { - val = (ram_size - 16 * 1024 * 1024) / 65536; + if (pcms->below_4g_mem_size > 16 * 1024 * 1024) { + val = (pcms->below_4g_mem_size - 16 * 1024 * 1024) / 65536; } else { val = 0; } @@ -468,7 +466,7 @@ void pc_cmos_init(PCMachineState *pcms, rtc_set_memory(s, 0x34, val); rtc_set_memory(s, 0x35, val >> 8); /* memory above 4GiB */ - val = above_4g_mem_size / 65536; + val = pcms->above_4g_mem_size / 65536; rtc_set_memory(s, 0x5b, val); rtc_set_memory(s, 0x5c, val >> 8); rtc_set_memory(s, 0x5d, val >> 16); @@ -484,7 +482,7 @@ void pc_cmos_init(PCMachineState *pcms, object_property_set_link(OBJECT(pcms), OBJECT(s), "rtc_state", &error_abort); - set_boot_dev(s, boot_device, &local_err); + set_boot_dev(s, MACHINE(pcms)->boot_order, &local_err); if (local_err) { error_report_err(local_err); exit(1); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index f64f029..c98635f 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -267,10 +267,7 @@ static void pc_init1(MachineState *machine) } } - pc_cmos_init(pcms, - pcms->below_4g_mem_size, pcms->above_4g_mem_size, - machine->boot_order, - idebus[0], idebus[1], rtc_state); + pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state); if (pci_enabled && usb_enabled()) { pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci"); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index af5fd9f..79e3f9b 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -276,10 +276,7 @@ static void pc_q35_init(MachineState *machine) 0xb100), 8, NULL, 0); - pc_cmos_init(pcms, - pcms->below_4g_mem_size, pcms->above_4g_mem_size, - machine->boot_order, - idebus[0], idebus[1], rtc_state); + pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state); /* the rest devices to which pci devfn is automatically assigned */ pc_vga_init(isa_bus, host_bus); diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index c433602..a56f70c 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -198,8 +198,6 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, uint32 hpet_irqs); void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd); void pc_cmos_init(PCMachineState *pcms, - ram_addr_t ram_size, ram_addr_t above_4g_mem_size, - const char *boot_device, BusState *ide0, BusState *ide1, ISADevice *s); void pc_nic_init(ISABus *isa_bus, PCIBus *pci_bus); -- cgit v1.1 From c8d163bc9e037ec32b2250b2d7950b1d1bc3fd61 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Fri, 7 Aug 2015 16:55:55 -0300 Subject: pc: Remove redundant arguments from pc_memory_init() Remove arguments that can be found in PCMachineState. Signed-off-by: Eduardo Habkost Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 18 +++++++++--------- hw/i386/pc_piix.c | 1 - hw/i386/pc_q35.c | 1 - include/hw/i386/pc.h | 2 -- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 681ea85..0c828e4 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -1285,8 +1285,6 @@ FWCfgState *xen_load_linux(PCMachineState *pcms, FWCfgState *pc_memory_init(PCMachineState *pcms, MemoryRegion *system_memory, - ram_addr_t below_4g_mem_size, - ram_addr_t above_4g_mem_size, MemoryRegion *rom_memory, MemoryRegion **ram_memory, PcGuestInfo *guest_info) @@ -1297,7 +1295,8 @@ FWCfgState *pc_memory_init(PCMachineState *pcms, FWCfgState *fw_cfg; MachineState *machine = MACHINE(pcms); - assert(machine->ram_size == below_4g_mem_size + above_4g_mem_size); + assert(machine->ram_size == pcms->below_4g_mem_size + + pcms->above_4g_mem_size); linux_boot = (machine->kernel_filename != NULL); @@ -1311,16 +1310,17 @@ FWCfgState *pc_memory_init(PCMachineState *pcms, *ram_memory = ram; ram_below_4g = g_malloc(sizeof(*ram_below_4g)); memory_region_init_alias(ram_below_4g, NULL, "ram-below-4g", ram, - 0, below_4g_mem_size); + 0, pcms->below_4g_mem_size); memory_region_add_subregion(system_memory, 0, ram_below_4g); - e820_add_entry(0, below_4g_mem_size, E820_RAM); - if (above_4g_mem_size > 0) { + e820_add_entry(0, pcms->below_4g_mem_size, E820_RAM); + if (pcms->above_4g_mem_size > 0) { ram_above_4g = g_malloc(sizeof(*ram_above_4g)); memory_region_init_alias(ram_above_4g, NULL, "ram-above-4g", ram, - below_4g_mem_size, above_4g_mem_size); + pcms->below_4g_mem_size, + pcms->above_4g_mem_size); memory_region_add_subregion(system_memory, 0x100000000ULL, ram_above_4g); - e820_add_entry(0x100000000ULL, above_4g_mem_size, E820_RAM); + e820_add_entry(0x100000000ULL, pcms->above_4g_mem_size, E820_RAM); } if (!guest_info->has_reserved_memory && @@ -1353,7 +1353,7 @@ FWCfgState *pc_memory_init(PCMachineState *pcms, } pcms->hotplug_memory.base = - ROUND_UP(0x100000000ULL + above_4g_mem_size, 1ULL << 30); + ROUND_UP(0x100000000ULL + pcms->above_4g_mem_size, 1ULL << 30); if (pcms->enforce_aligned_dimm) { /* size hotplug region assuming 1G page max alignment per slot */ diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index c98635f..ce51cd1 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -179,7 +179,6 @@ static void pc_init1(MachineState *machine) /* allocate ram and load rom/bios */ if (!xen_enabled()) { pc_memory_init(pcms, system_memory, - pcms->below_4g_mem_size, pcms->above_4g_mem_size, rom_memory, &ram_memory, guest_info); } else if (machine->kernel_filename != NULL) { /* For xen HVM direct kernel boot, load linux here */ diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 79e3f9b..cd4ecc3 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -171,7 +171,6 @@ static void pc_q35_init(MachineState *machine) /* allocate ram and load rom/bios */ if (!xen_enabled()) { pc_memory_init(pcms, get_system_memory(), - pcms->below_4g_mem_size, pcms->above_4g_mem_size, rom_memory, &ram_memory, guest_info); } diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index a56f70c..d0cad87 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -184,8 +184,6 @@ FWCfgState *xen_load_linux(PCMachineState *pcms, PcGuestInfo *guest_info); FWCfgState *pc_memory_init(PCMachineState *pcms, MemoryRegion *system_memory, - ram_addr_t below_4g_mem_size, - ram_addr_t above_4g_mem_size, MemoryRegion *rom_memory, MemoryRegion **ram_memory, PcGuestInfo *guest_info); -- cgit v1.1 From e402463073ae51d00dc6cf98556e2f5c4b008a31 Mon Sep 17 00:00:00 2001 From: Laurent Vivier Date: Fri, 24 Jul 2015 10:35:13 +0200 Subject: pci: allow 0 address for PCI IO/MEM regions Some kernels program a 0 address for io regions. PCI 3.0 spec section 6.2.5.1 doesn't seem to disallow this. based on patch by Michael Roth Add pci_allow_0_addr in MachineClass to conditionally allow addr 0 for pseries, as this can break other architectures. This patch allows to hotplug PCI card in pseries machine, as the first added card BAR0 is always set to 0 address. This as a temporary hack, waiting to fix PCI memory priorities for more machine types... Signed-off-by: Laurent Vivier Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/pci/pci.c | 12 +++++++++--- hw/ppc/spapr.c | 1 + include/hw/boards.h | 3 ++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/hw/pci/pci.c b/hw/pci/pci.c index a017614..9f57aea 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -38,6 +38,7 @@ #include "hw/pci/msix.h" #include "exec/address-spaces.h" #include "hw/hotplug.h" +#include "hw/boards.h" //#define DEBUG_PCI #ifdef DEBUG_PCI @@ -1065,6 +1066,10 @@ static pcibus_t pci_bar_address(PCIDevice *d, pcibus_t new_addr, last_addr; int bar = pci_bar(d, reg); uint16_t cmd = pci_get_word(d->config + PCI_COMMAND); + Object *machine = qdev_get_machine(); + ObjectClass *oc = object_get_class(machine); + MachineClass *mc = MACHINE_CLASS(oc); + bool allow_0_address = mc->pci_allow_0_address; if (type & PCI_BASE_ADDRESS_SPACE_IO) { if (!(cmd & PCI_COMMAND_IO)) { @@ -1075,7 +1080,8 @@ static pcibus_t pci_bar_address(PCIDevice *d, /* Check if 32 bit BAR wraps around explicitly. * TODO: make priorities correct and remove this work around. */ - if (last_addr <= new_addr || new_addr == 0 || last_addr >= UINT32_MAX) { + if (last_addr <= new_addr || last_addr >= UINT32_MAX || + (!allow_0_address && new_addr == 0)) { return PCI_BAR_UNMAPPED; } return new_addr; @@ -1099,8 +1105,8 @@ static pcibus_t pci_bar_address(PCIDevice *d, /* XXX: as we cannot support really dynamic mappings, we handle specific values as invalid mappings. */ - if (last_addr <= new_addr || new_addr == 0 || - last_addr == PCI_BAR_UNMAPPED) { + if (last_addr <= new_addr || last_addr == PCI_BAR_UNMAPPED || + (!allow_0_address && new_addr == 0)) { return PCI_BAR_UNMAPPED; } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index a6f1947..bf0c64f 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1835,6 +1835,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) mc->default_ram_size = 512 * M_BYTE; mc->kvm_type = spapr_kvm_type; mc->has_dynamic_sysbus = true; + mc->pci_allow_0_address = true; fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi; diff --git a/include/hw/boards.h b/include/hw/boards.h index 2aec9cb..3f84afd 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -100,7 +100,8 @@ struct MachineClass { no_cdrom:1, no_sdcard:1, has_dynamic_sysbus:1, - no_tco:1; + no_tco:1, + pci_allow_0_address:1; int is_default; const char *default_machine_opts; const char *default_boot_order; -- cgit v1.1 From bd89dd98b2b835bbff43f02f2e7c823eb0c61331 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 3 Aug 2015 13:20:38 +0800 Subject: virtio-net: remove useless codes After commit 40bad8f3deba15e2074ff34cfe923c12916b1cc5("virtio-net: fix used len for tx"), async_tx.len was no longer used afterwards. So remove useless codes with it. Signed-off-by: Jason Wang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/net/virtio-net.c | 8 ++------ include/hw/virtio/virtio-net.h | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 1510839..8d28e45 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1124,7 +1124,7 @@ static void virtio_net_tx_complete(NetClientState *nc, ssize_t len) virtqueue_push(q->tx_vq, &q->async_tx.elem, 0); virtio_notify(vdev, q->tx_vq); - q->async_tx.elem.out_num = q->async_tx.len = 0; + q->async_tx.elem.out_num = 0; virtio_queue_set_notification(q->tx_vq, 1); virtio_net_flush_tx(q); @@ -1148,7 +1148,7 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) } while (virtqueue_pop(q->tx_vq, &elem)) { - ssize_t ret, len; + ssize_t ret; unsigned int out_num = elem.out_num; struct iovec *out_sg = &elem.out_sg[0]; struct iovec sg[VIRTQUEUE_MAX_SIZE], sg2[VIRTQUEUE_MAX_SIZE + 1]; @@ -1196,18 +1196,14 @@ static int32_t virtio_net_flush_tx(VirtIONetQueue *q) out_sg = sg; } - len = n->guest_hdr_len; - ret = qemu_sendv_packet_async(qemu_get_subqueue(n->nic, queue_index), out_sg, out_num, virtio_net_tx_complete); if (ret == 0) { virtio_queue_set_notification(q->tx_vq, 0); q->async_tx.elem = elem; - q->async_tx.len = len; return -EBUSY; } - len += ret; drop: virtqueue_push(q->tx_vq, &elem, 0); virtio_notify(vdev, q->tx_vq); diff --git a/include/hw/virtio/virtio-net.h b/include/hw/virtio/virtio-net.h index 60b11d5..f3cc25f 100644 --- a/include/hw/virtio/virtio-net.h +++ b/include/hw/virtio/virtio-net.h @@ -48,7 +48,6 @@ typedef struct VirtIONetQueue { int tx_waiting; struct { VirtQueueElement elem; - ssize_t len; } async_tx; struct VirtIONet *n; } VirtIONetQueue; -- cgit v1.1 From 94aaca6457e52bb9c8a53af3c89bfeec40afadfc Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 31 Jul 2015 11:14:35 +0100 Subject: acpi: avoid potential uninitialized access to cpu_hp_io_base When building QEMU with Mingw64 toolchain I see a warning CC x86_64-softmmu/hw/i386/acpi-build.o hw/i386/acpi-build.c: In function 'acpi_build': hw/i386/acpi-build.c:1138:9: warning: 'pm.cpu_hp_io_base' may be used uninitialized in this function [-Wmaybe-uninitialized] aml_append(crs, ^ hw/i386/acpi-build.c:1666:16: note: 'pm.cpu_hp_io_base' was declared here AcpiPmInfo pm; ^ In acpi_get_pm_info() some of the fields are pre-initialized to 0, but this one was missed. Signed-off-by: Daniel P. Berrange Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Reviewed-by: Igor Mammedov --- hw/i386/acpi-build.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 46eddb8..95e0c65 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -169,6 +169,7 @@ static void acpi_get_pm_info(AcpiPmInfo *pm) Object *obj = NULL; QObject *o; + pm->cpu_hp_io_base = 0; pm->pcihp_io_base = 0; pm->pcihp_io_len = 0; if (piix) { -- cgit v1.1 From 5fd0a9d410dc876ce134359c489d1d639ea32889 Mon Sep 17 00:00:00 2001 From: Wei Huang Date: Tue, 11 Aug 2015 22:08:18 -0400 Subject: smbios: extract x86 smbios building code into a function This patch extracts out the procedure of buidling x86 SMBIOS tables into a dedicated function. Acked-by: Gabriel Somlo Tested-by: Gabriel Somlo Reviewed-by: Laszlo Ersek Tested-by: Leif Lindholm Signed-off-by: Wei Huang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 0c828e4..d75a8b4 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -716,11 +716,30 @@ static unsigned int pc_apic_id_limit(unsigned int max_cpus) return x86_cpu_apic_id_from_index(max_cpus - 1) + 1; } -static FWCfgState *bochs_bios_init(void) +static void pc_build_smbios(FWCfgState *fw_cfg) { - FWCfgState *fw_cfg; uint8_t *smbios_tables, *smbios_anchor; size_t smbios_tables_len, smbios_anchor_len; + + smbios_tables = smbios_get_table_legacy(&smbios_tables_len); + if (smbios_tables) { + fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES, + smbios_tables, smbios_tables_len); + } + + smbios_get_tables(&smbios_tables, &smbios_tables_len, + &smbios_anchor, &smbios_anchor_len); + if (smbios_anchor) { + fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables", + smbios_tables, smbios_tables_len); + fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor", + smbios_anchor, smbios_anchor_len); + } +} + +static FWCfgState *bochs_bios_init(void) +{ + FWCfgState *fw_cfg; uint64_t *numa_fw_cfg; int i, j; unsigned int apic_id_limit = pc_apic_id_limit(max_cpus); @@ -746,20 +765,7 @@ static FWCfgState *bochs_bios_init(void) acpi_tables, acpi_tables_len); fw_cfg_add_i32(fw_cfg, FW_CFG_IRQ0_OVERRIDE, kvm_allows_irq0_override()); - smbios_tables = smbios_get_table_legacy(&smbios_tables_len); - if (smbios_tables) { - fw_cfg_add_bytes(fw_cfg, FW_CFG_SMBIOS_ENTRIES, - smbios_tables, smbios_tables_len); - } - - smbios_get_tables(&smbios_tables, &smbios_tables_len, - &smbios_anchor, &smbios_anchor_len); - if (smbios_anchor) { - fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables", - smbios_tables, smbios_tables_len); - fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-anchor", - smbios_anchor, smbios_anchor_len); - } + pc_build_smbios(fw_cfg); fw_cfg_add_bytes(fw_cfg, FW_CFG_E820_TABLE, &e820_reserve, sizeof(e820_reserve)); -- cgit v1.1 From 89cc4a2760be800b5924dd705b1369bc29783c9f Mon Sep 17 00:00:00 2001 From: Wei Huang Date: Tue, 11 Aug 2015 22:08:19 -0400 Subject: smbios: remove dependency on x86 e820 tables Current smbios builds type 19 table from e820, which is x86 specific. This patch removes smbios' dependency on e820 by passing an array of memory area to smbios_get_tables(). Acked-by: Gabriel Somlo Tested-by: Gabriel Somlo Reviewed-by: Laszlo Ersek Tested-by: Leif Lindholm Signed-off-by: Wei Huang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- hw/i386/pc.c | 18 +++++++++++++++++- hw/i386/smbios.c | 14 +++++++------- include/hw/i386/smbios.h | 10 +++++++++- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/hw/i386/pc.c b/hw/i386/pc.c index d75a8b4..0973596 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -720,6 +720,8 @@ static void pc_build_smbios(FWCfgState *fw_cfg) { uint8_t *smbios_tables, *smbios_anchor; size_t smbios_tables_len, smbios_anchor_len; + struct smbios_phys_mem_area *mem_array; + unsigned i, array_count; smbios_tables = smbios_get_table_legacy(&smbios_tables_len); if (smbios_tables) { @@ -727,8 +729,22 @@ static void pc_build_smbios(FWCfgState *fw_cfg) smbios_tables, smbios_tables_len); } - smbios_get_tables(&smbios_tables, &smbios_tables_len, + /* build the array of physical mem area from e820 table */ + mem_array = g_malloc0(sizeof(*mem_array) * e820_get_num_entries()); + for (i = 0, array_count = 0; i < e820_get_num_entries(); i++) { + uint64_t addr, len; + + if (e820_get_entry(i, E820_RAM, &addr, &len)) { + mem_array[array_count].address = addr; + mem_array[array_count].length = len; + array_count++; + } + } + smbios_get_tables(mem_array, array_count, + &smbios_tables, &smbios_tables_len, &smbios_anchor, &smbios_anchor_len); + g_free(mem_array); + if (smbios_anchor) { fw_cfg_add_file(fw_cfg, "etc/smbios/smbios-tables", smbios_tables, smbios_tables_len); diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c index 1341e02..6f715c6 100644 --- a/hw/i386/smbios.c +++ b/hw/i386/smbios.c @@ -831,10 +831,12 @@ static void smbios_entry_point_setup(void) ep.structure_table_address = cpu_to_le32(0); } -void smbios_get_tables(uint8_t **tables, size_t *tables_len, +void smbios_get_tables(const struct smbios_phys_mem_area *mem_array, + const unsigned int mem_array_size, + uint8_t **tables, size_t *tables_len, uint8_t **anchor, size_t *anchor_len) { - unsigned i, dimm_cnt, instance; + unsigned i, dimm_cnt; if (smbios_legacy) { *tables = *anchor = NULL; @@ -867,11 +869,9 @@ void smbios_get_tables(uint8_t **tables, size_t *tables_len, smbios_build_type_17_table(i, GET_DIMM_SZ); } - for (i = 0, instance = 0; i < e820_get_num_entries(); i++) { - uint64_t address, length; - if (e820_get_entry(i, E820_RAM, &address, &length)) { - smbios_build_type_19_table(instance++, address, length); - } + for (i = 0; i < mem_array_size; i++) { + smbios_build_type_19_table(i, mem_array[i].address, + mem_array[i].length); } smbios_build_type_32_table(); diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h index d2850be..4269aab 100644 --- a/include/hw/i386/smbios.h +++ b/include/hw/i386/smbios.h @@ -17,13 +17,21 @@ #define SMBIOS_MAX_TYPE 127 +/* memory area description, used by type 19 table */ +struct smbios_phys_mem_area { + uint64_t address; + uint64_t length; +}; + void smbios_entry_add(QemuOpts *opts); void smbios_set_cpuid(uint32_t version, uint32_t features); void smbios_set_defaults(const char *manufacturer, const char *product, const char *version, bool legacy_mode, bool uuid_encoded); uint8_t *smbios_get_table_legacy(size_t *length); -void smbios_get_tables(uint8_t **tables, size_t *tables_len, +void smbios_get_tables(const struct smbios_phys_mem_area *mem_array, + const unsigned int mem_array_size, + uint8_t **tables, size_t *tables_len, uint8_t **anchor, size_t *anchor_len); /* -- cgit v1.1 From 60d8f328b878ead45a5e5e347935097e3426bbd9 Mon Sep 17 00:00:00 2001 From: Wei Huang Date: Tue, 11 Aug 2015 22:08:20 -0400 Subject: smbios: move smbios code into a common folder To share smbios among different architectures, this patch moves SMBIOS code (smbios.c and smbios.h) from x86 specific folders into new hw/smbios directories. As a result, CONFIG_SMBIOS=y is defined in x86 default config files. Acked-by: Gabriel Somlo Tested-by: Gabriel Somlo Reviewed-by: Laszlo Ersek Tested-by: Leif Lindholm Signed-off-by: Wei Huang Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- arch_init.c | 2 +- default-configs/i386-softmmu.mak | 1 + default-configs/x86_64-softmmu.mak | 1 + hw/Makefile.objs | 1 + hw/i386/Makefile.objs | 2 +- hw/i386/pc.c | 2 +- hw/i386/pc_piix.c | 2 +- hw/i386/pc_q35.c | 2 +- hw/i386/smbios.c | 1102 ------------------------------------ hw/smbios/Makefile.objs | 1 + hw/smbios/smbios.c | 1101 +++++++++++++++++++++++++++++++++++ include/hw/i386/smbios.h | 235 -------- include/hw/smbios/smbios.h | 235 ++++++++ tests/bios-tables-test.c | 2 +- vl.c | 2 +- 15 files changed, 1347 insertions(+), 1344 deletions(-) delete mode 100644 hw/i386/smbios.c create mode 100644 hw/smbios/Makefile.objs create mode 100644 hw/smbios/smbios.c delete mode 100644 include/hw/i386/smbios.h create mode 100644 include/hw/smbios/smbios.h diff --git a/arch_init.c b/arch_init.c index 725c638..38f5fb9 100644 --- a/arch_init.c +++ b/arch_init.c @@ -26,7 +26,7 @@ #include "sysemu/arch_init.h" #include "hw/pci/pci.h" #include "hw/audio/audio.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "qemu/config-file.h" #include "qemu/error-report.h" #include "qmp-commands.h" diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 48b5762..5eaafa1 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -49,3 +49,4 @@ CONFIG_MEM_HOTPLUG=y CONFIG_XIO3130=y CONFIG_IOH3420=y CONFIG_I82801B11=y +CONFIG_SMBIOS=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index 4962ed7..28e2099 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -50,3 +50,4 @@ CONFIG_MEM_HOTPLUG=y CONFIG_XIO3130=y CONFIG_IOH3420=y CONFIG_I82801B11=y +CONFIG_SMBIOS=y diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 73afa41..7e7c241 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -31,6 +31,7 @@ devices-dirs-$(CONFIG_VIRTIO) += virtio/ devices-dirs-$(CONFIG_SOFTMMU) += watchdog/ devices-dirs-$(CONFIG_SOFTMMU) += xen/ devices-dirs-$(CONFIG_MEM_HOTPLUG) += mem/ +devices-dirs-$(CONFIG_SMBIOS) += smbios/ devices-dirs-y += core/ common-obj-y += $(devices-dirs-y) obj-y += $(devices-dirs-y) diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index ecdb400..ebd1015 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -1,5 +1,5 @@ obj-$(CONFIG_KVM) += kvm/ -obj-y += multiboot.o smbios.o +obj-y += multiboot.o obj-y += pc.o pc_piix.o pc_q35.o obj-y += pc_sysfw.o obj-y += intel_iommu.o diff --git a/hw/i386/pc.c b/hw/i386/pc.c index 0973596..9f2924e 100644 --- a/hw/i386/pc.c +++ b/hw/i386/pc.c @@ -33,7 +33,7 @@ #include "hw/pci/pci_bus.h" #include "hw/nvram/fw_cfg.h" #include "hw/timer/hpet.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "hw/loader.h" #include "elf.h" #include "multiboot.h" diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index ce51cd1..9558467 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -28,7 +28,7 @@ #include "hw/loader.h" #include "hw/i386/pc.h" #include "hw/i386/apic.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "hw/pci/pci.h" #include "hw/pci/pci_ids.h" #include "hw/usb.h" diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index cd4ecc3..c07d65b 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -39,7 +39,7 @@ #include "hw/pci-host/q35.h" #include "exec/address-spaces.h" #include "hw/i386/ich9.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "hw/ide/pci.h" #include "hw/ide/ahci.h" #include "hw/usb.h" diff --git a/hw/i386/smbios.c b/hw/i386/smbios.c deleted file mode 100644 index 6f715c6..0000000 --- a/hw/i386/smbios.c +++ /dev/null @@ -1,1102 +0,0 @@ -/* - * SMBIOS Support - * - * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. - * Copyright (C) 2013 Red Hat, Inc. - * - * Authors: - * Alex Williamson - * Markus Armbruster - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - * Contributions after 2012-01-13 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - */ - -#include "qemu/config-file.h" -#include "qemu/error-report.h" -#include "sysemu/sysemu.h" -#include "sysemu/cpus.h" -#include "hw/i386/pc.h" -#include "hw/i386/smbios.h" -#include "hw/loader.h" - - -/* legacy structures and constants for <= 2.0 machines */ -struct smbios_header { - uint16_t length; - uint8_t type; -} QEMU_PACKED; - -struct smbios_field { - struct smbios_header header; - uint8_t type; - uint16_t offset; - uint8_t data[]; -} QEMU_PACKED; - -struct smbios_table { - struct smbios_header header; - uint8_t data[]; -} QEMU_PACKED; - -#define SMBIOS_FIELD_ENTRY 0 -#define SMBIOS_TABLE_ENTRY 1 - -static uint8_t *smbios_entries; -static size_t smbios_entries_len; -static bool smbios_legacy = true; -static bool smbios_uuid_encoded = true; -/* end: legacy structures & constants for <= 2.0 machines */ - - -static uint8_t *smbios_tables; -static size_t smbios_tables_len; -static unsigned smbios_table_max; -static unsigned smbios_table_cnt; -static struct smbios_entry_point ep; - -static int smbios_type4_count = 0; -static bool smbios_immutable; -static bool smbios_have_defaults; -static uint32_t smbios_cpuid_version, smbios_cpuid_features, smbios_smp_sockets; - -static DECLARE_BITMAP(have_binfile_bitmap, SMBIOS_MAX_TYPE+1); -static DECLARE_BITMAP(have_fields_bitmap, SMBIOS_MAX_TYPE+1); - -static struct { - const char *vendor, *version, *date; - bool have_major_minor, uefi; - uint8_t major, minor; -} type0; - -static struct { - const char *manufacturer, *product, *version, *serial, *sku, *family; - /* uuid is in qemu_uuid[] */ -} type1; - -static struct { - const char *manufacturer, *product, *version, *serial, *asset, *location; -} type2; - -static struct { - const char *manufacturer, *version, *serial, *asset, *sku; -} type3; - -static struct { - const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part; -} type4; - -static struct { - const char *loc_pfx, *bank, *manufacturer, *serial, *asset, *part; - uint16_t speed; -} type17; - -static QemuOptsList qemu_smbios_opts = { - .name = "smbios", - .head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head), - .desc = { - /* - * no elements => accept any params - * validation will happen later - */ - { /* end of list */ } - } -}; - -static const QemuOptDesc qemu_smbios_file_opts[] = { - { - .name = "file", - .type = QEMU_OPT_STRING, - .help = "binary file containing an SMBIOS element", - }, - { /* end of list */ } -}; - -static const QemuOptDesc qemu_smbios_type0_opts[] = { - { - .name = "type", - .type = QEMU_OPT_NUMBER, - .help = "SMBIOS element type", - },{ - .name = "vendor", - .type = QEMU_OPT_STRING, - .help = "vendor name", - },{ - .name = "version", - .type = QEMU_OPT_STRING, - .help = "version number", - },{ - .name = "date", - .type = QEMU_OPT_STRING, - .help = "release date", - },{ - .name = "release", - .type = QEMU_OPT_STRING, - .help = "revision number", - },{ - .name = "uefi", - .type = QEMU_OPT_BOOL, - .help = "uefi support", - }, - { /* end of list */ } -}; - -static const QemuOptDesc qemu_smbios_type1_opts[] = { - { - .name = "type", - .type = QEMU_OPT_NUMBER, - .help = "SMBIOS element type", - },{ - .name = "manufacturer", - .type = QEMU_OPT_STRING, - .help = "manufacturer name", - },{ - .name = "product", - .type = QEMU_OPT_STRING, - .help = "product name", - },{ - .name = "version", - .type = QEMU_OPT_STRING, - .help = "version number", - },{ - .name = "serial", - .type = QEMU_OPT_STRING, - .help = "serial number", - },{ - .name = "uuid", - .type = QEMU_OPT_STRING, - .help = "UUID", - },{ - .name = "sku", - .type = QEMU_OPT_STRING, - .help = "SKU number", - },{ - .name = "family", - .type = QEMU_OPT_STRING, - .help = "family name", - }, - { /* end of list */ } -}; - -static const QemuOptDesc qemu_smbios_type2_opts[] = { - { - .name = "type", - .type = QEMU_OPT_NUMBER, - .help = "SMBIOS element type", - },{ - .name = "manufacturer", - .type = QEMU_OPT_STRING, - .help = "manufacturer name", - },{ - .name = "product", - .type = QEMU_OPT_STRING, - .help = "product name", - },{ - .name = "version", - .type = QEMU_OPT_STRING, - .help = "version number", - },{ - .name = "serial", - .type = QEMU_OPT_STRING, - .help = "serial number", - },{ - .name = "asset", - .type = QEMU_OPT_STRING, - .help = "asset tag number", - },{ - .name = "location", - .type = QEMU_OPT_STRING, - .help = "location in chassis", - }, - { /* end of list */ } -}; - -static const QemuOptDesc qemu_smbios_type3_opts[] = { - { - .name = "type", - .type = QEMU_OPT_NUMBER, - .help = "SMBIOS element type", - },{ - .name = "manufacturer", - .type = QEMU_OPT_STRING, - .help = "manufacturer name", - },{ - .name = "version", - .type = QEMU_OPT_STRING, - .help = "version number", - },{ - .name = "serial", - .type = QEMU_OPT_STRING, - .help = "serial number", - },{ - .name = "asset", - .type = QEMU_OPT_STRING, - .help = "asset tag number", - },{ - .name = "sku", - .type = QEMU_OPT_STRING, - .help = "SKU number", - }, - { /* end of list */ } -}; - -static const QemuOptDesc qemu_smbios_type4_opts[] = { - { - .name = "type", - .type = QEMU_OPT_NUMBER, - .help = "SMBIOS element type", - },{ - .name = "sock_pfx", - .type = QEMU_OPT_STRING, - .help = "socket designation string prefix", - },{ - .name = "manufacturer", - .type = QEMU_OPT_STRING, - .help = "manufacturer name", - },{ - .name = "version", - .type = QEMU_OPT_STRING, - .help = "version number", - },{ - .name = "serial", - .type = QEMU_OPT_STRING, - .help = "serial number", - },{ - .name = "asset", - .type = QEMU_OPT_STRING, - .help = "asset tag number", - },{ - .name = "part", - .type = QEMU_OPT_STRING, - .help = "part number", - }, - { /* end of list */ } -}; - -static const QemuOptDesc qemu_smbios_type17_opts[] = { - { - .name = "type", - .type = QEMU_OPT_NUMBER, - .help = "SMBIOS element type", - },{ - .name = "loc_pfx", - .type = QEMU_OPT_STRING, - .help = "device locator string prefix", - },{ - .name = "bank", - .type = QEMU_OPT_STRING, - .help = "bank locator string", - },{ - .name = "manufacturer", - .type = QEMU_OPT_STRING, - .help = "manufacturer name", - },{ - .name = "serial", - .type = QEMU_OPT_STRING, - .help = "serial number", - },{ - .name = "asset", - .type = QEMU_OPT_STRING, - .help = "asset tag number", - },{ - .name = "part", - .type = QEMU_OPT_STRING, - .help = "part number", - },{ - .name = "speed", - .type = QEMU_OPT_NUMBER, - .help = "maximum capable speed", - }, - { /* end of list */ } -}; - -static void smbios_register_config(void) -{ - qemu_add_opts(&qemu_smbios_opts); -} - -machine_init(smbios_register_config); - -static void smbios_validate_table(void) -{ - uint32_t expect_t4_count = smbios_legacy ? smp_cpus : smbios_smp_sockets; - - if (smbios_type4_count && smbios_type4_count != expect_t4_count) { - error_report("Expected %d SMBIOS Type 4 tables, got %d instead", - expect_t4_count, smbios_type4_count); - exit(1); - } -} - - -/* legacy setup functions for <= 2.0 machines */ -static void smbios_add_field(int type, int offset, const void *data, size_t len) -{ - struct smbios_field *field; - - if (!smbios_entries) { - smbios_entries_len = sizeof(uint16_t); - smbios_entries = g_malloc0(smbios_entries_len); - } - smbios_entries = g_realloc(smbios_entries, smbios_entries_len + - sizeof(*field) + len); - field = (struct smbios_field *)(smbios_entries + smbios_entries_len); - field->header.type = SMBIOS_FIELD_ENTRY; - field->header.length = cpu_to_le16(sizeof(*field) + len); - - field->type = type; - field->offset = cpu_to_le16(offset); - memcpy(field->data, data, len); - - smbios_entries_len += sizeof(*field) + len; - (*(uint16_t *)smbios_entries) = - cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); -} - -static void smbios_maybe_add_str(int type, int offset, const char *data) -{ - if (data) { - smbios_add_field(type, offset, data, strlen(data) + 1); - } -} - -static void smbios_build_type_0_fields(void) -{ - smbios_maybe_add_str(0, offsetof(struct smbios_type_0, vendor_str), - type0.vendor); - smbios_maybe_add_str(0, offsetof(struct smbios_type_0, bios_version_str), - type0.version); - smbios_maybe_add_str(0, offsetof(struct smbios_type_0, - bios_release_date_str), - type0.date); - if (type0.have_major_minor) { - smbios_add_field(0, offsetof(struct smbios_type_0, - system_bios_major_release), - &type0.major, 1); - smbios_add_field(0, offsetof(struct smbios_type_0, - system_bios_minor_release), - &type0.minor, 1); - } -} - -static void smbios_build_type_1_fields(void) -{ - smbios_maybe_add_str(1, offsetof(struct smbios_type_1, manufacturer_str), - type1.manufacturer); - smbios_maybe_add_str(1, offsetof(struct smbios_type_1, product_name_str), - type1.product); - smbios_maybe_add_str(1, offsetof(struct smbios_type_1, version_str), - type1.version); - smbios_maybe_add_str(1, offsetof(struct smbios_type_1, serial_number_str), - type1.serial); - smbios_maybe_add_str(1, offsetof(struct smbios_type_1, sku_number_str), - type1.sku); - smbios_maybe_add_str(1, offsetof(struct smbios_type_1, family_str), - type1.family); - if (qemu_uuid_set) { - /* We don't encode the UUID in the "wire format" here because this - * function is for legacy mode and needs to keep the guest ABI, and - * because we don't know what's the SMBIOS version advertised by the - * BIOS. - */ - smbios_add_field(1, offsetof(struct smbios_type_1, uuid), - qemu_uuid, 16); - } -} - -uint8_t *smbios_get_table_legacy(size_t *length) -{ - if (!smbios_legacy) { - *length = 0; - return NULL; - } - - if (!smbios_immutable) { - smbios_build_type_0_fields(); - smbios_build_type_1_fields(); - smbios_validate_table(); - smbios_immutable = true; - } - *length = smbios_entries_len; - return smbios_entries; -} -/* end: legacy setup functions for <= 2.0 machines */ - - -static bool smbios_skip_table(uint8_t type, bool required_table) -{ - if (test_bit(type, have_binfile_bitmap)) { - return true; /* user provided their own binary blob(s) */ - } - if (test_bit(type, have_fields_bitmap)) { - return false; /* user provided fields via command line */ - } - if (smbios_have_defaults && required_table) { - return false; /* we're building tables, and this one's required */ - } - return true; -} - -#define SMBIOS_BUILD_TABLE_PRE(tbl_type, tbl_handle, tbl_required) \ - struct smbios_type_##tbl_type *t; \ - size_t t_off; /* table offset into smbios_tables */ \ - int str_index = 0; \ - do { \ - /* should we skip building this table ? */ \ - if (smbios_skip_table(tbl_type, tbl_required)) { \ - return; \ - } \ - \ - /* use offset of table t within smbios_tables */ \ - /* (pointer must be updated after each realloc) */ \ - t_off = smbios_tables_len; \ - smbios_tables_len += sizeof(*t); \ - smbios_tables = g_realloc(smbios_tables, smbios_tables_len); \ - t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \ - \ - t->header.type = tbl_type; \ - t->header.length = sizeof(*t); \ - t->header.handle = cpu_to_le16(tbl_handle); \ - } while (0) - -#define SMBIOS_TABLE_SET_STR(tbl_type, field, value) \ - do { \ - int len = (value != NULL) ? strlen(value) + 1 : 0; \ - if (len > 1) { \ - smbios_tables = g_realloc(smbios_tables, \ - smbios_tables_len + len); \ - memcpy(smbios_tables + smbios_tables_len, value, len); \ - smbios_tables_len += len; \ - /* update pointer post-realloc */ \ - t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \ - t->field = ++str_index; \ - } else { \ - t->field = 0; \ - } \ - } while (0) - -#define SMBIOS_BUILD_TABLE_POST \ - do { \ - size_t term_cnt, t_size; \ - \ - /* add '\0' terminator (add two if no strings defined) */ \ - term_cnt = (str_index == 0) ? 2 : 1; \ - smbios_tables = g_realloc(smbios_tables, \ - smbios_tables_len + term_cnt); \ - memset(smbios_tables + smbios_tables_len, 0, term_cnt); \ - smbios_tables_len += term_cnt; \ - \ - /* update smbios max. element size */ \ - t_size = smbios_tables_len - t_off; \ - if (t_size > smbios_table_max) { \ - smbios_table_max = t_size; \ - } \ - \ - /* update smbios element count */ \ - smbios_table_cnt++; \ - } while (0) - -static void smbios_build_type_0_table(void) -{ - SMBIOS_BUILD_TABLE_PRE(0, 0x000, false); /* optional, leave up to BIOS */ - - SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor); - SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version); - - t->bios_starting_address_segment = cpu_to_le16(0xE800); /* from SeaBIOS */ - - SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date); - - t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */ - - t->bios_characteristics = cpu_to_le64(0x08); /* Not supported */ - t->bios_characteristics_extension_bytes[0] = 0; - t->bios_characteristics_extension_bytes[1] = 0x14; /* TCD/SVVP | VM */ - if (type0.uefi) { - t->bios_characteristics_extension_bytes[1] |= 0x08; /* |= UEFI */ - } - - if (type0.have_major_minor) { - t->system_bios_major_release = type0.major; - t->system_bios_minor_release = type0.minor; - } else { - t->system_bios_major_release = 0; - t->system_bios_minor_release = 0; - } - - /* hardcoded in SeaBIOS */ - t->embedded_controller_major_release = 0xFF; - t->embedded_controller_minor_release = 0xFF; - - SMBIOS_BUILD_TABLE_POST; -} - -/* Encode UUID from the big endian encoding described on RFC4122 to the wire - * format specified by SMBIOS version 2.6. - */ -static void smbios_encode_uuid(struct smbios_uuid *uuid, const uint8_t *buf) -{ - memcpy(uuid, buf, 16); - if (smbios_uuid_encoded) { - uuid->time_low = bswap32(uuid->time_low); - uuid->time_mid = bswap16(uuid->time_mid); - uuid->time_hi_and_version = bswap16(uuid->time_hi_and_version); - } -} - -static void smbios_build_type_1_table(void) -{ - SMBIOS_BUILD_TABLE_PRE(1, 0x100, true); /* required */ - - SMBIOS_TABLE_SET_STR(1, manufacturer_str, type1.manufacturer); - SMBIOS_TABLE_SET_STR(1, product_name_str, type1.product); - SMBIOS_TABLE_SET_STR(1, version_str, type1.version); - SMBIOS_TABLE_SET_STR(1, serial_number_str, type1.serial); - if (qemu_uuid_set) { - smbios_encode_uuid(&t->uuid, qemu_uuid); - } else { - memset(&t->uuid, 0, 16); - } - t->wake_up_type = 0x06; /* power switch */ - SMBIOS_TABLE_SET_STR(1, sku_number_str, type1.sku); - SMBIOS_TABLE_SET_STR(1, family_str, type1.family); - - SMBIOS_BUILD_TABLE_POST; -} - -static void smbios_build_type_2_table(void) -{ - SMBIOS_BUILD_TABLE_PRE(2, 0x200, false); /* optional */ - - SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer); - SMBIOS_TABLE_SET_STR(2, product_str, type2.product); - SMBIOS_TABLE_SET_STR(2, version_str, type2.version); - SMBIOS_TABLE_SET_STR(2, serial_number_str, type2.serial); - SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset); - t->feature_flags = 0x01; /* Motherboard */ - SMBIOS_TABLE_SET_STR(2, location_str, type2.location); - t->chassis_handle = cpu_to_le16(0x300); /* Type 3 (System enclosure) */ - t->board_type = 0x0A; /* Motherboard */ - t->contained_element_count = 0; - - SMBIOS_BUILD_TABLE_POST; -} - -static void smbios_build_type_3_table(void) -{ - SMBIOS_BUILD_TABLE_PRE(3, 0x300, true); /* required */ - - SMBIOS_TABLE_SET_STR(3, manufacturer_str, type3.manufacturer); - t->type = 0x01; /* Other */ - SMBIOS_TABLE_SET_STR(3, version_str, type3.version); - SMBIOS_TABLE_SET_STR(3, serial_number_str, type3.serial); - SMBIOS_TABLE_SET_STR(3, asset_tag_number_str, type3.asset); - t->boot_up_state = 0x03; /* Safe */ - t->power_supply_state = 0x03; /* Safe */ - t->thermal_state = 0x03; /* Safe */ - t->security_status = 0x02; /* Unknown */ - t->oem_defined = cpu_to_le32(0); - t->height = 0; - t->number_of_power_cords = 0; - t->contained_element_count = 0; - SMBIOS_TABLE_SET_STR(3, sku_number_str, type3.sku); - - SMBIOS_BUILD_TABLE_POST; -} - -static void smbios_build_type_4_table(unsigned instance) -{ - char sock_str[128]; - - SMBIOS_BUILD_TABLE_PRE(4, 0x400 + instance, true); /* required */ - - snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance); - SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str); - t->processor_type = 0x03; /* CPU */ - t->processor_family = 0x01; /* Other */ - SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer); - t->processor_id[0] = cpu_to_le32(smbios_cpuid_version); - t->processor_id[1] = cpu_to_le32(smbios_cpuid_features); - SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version); - t->voltage = 0; - t->external_clock = cpu_to_le16(0); /* Unknown */ - /* SVVP requires max_speed and current_speed to not be unknown. */ - t->max_speed = cpu_to_le16(2000); /* 2000 MHz */ - t->current_speed = cpu_to_le16(2000); /* 2000 MHz */ - t->status = 0x41; /* Socket populated, CPU enabled */ - t->processor_upgrade = 0x01; /* Other */ - t->l1_cache_handle = cpu_to_le16(0xFFFF); /* N/A */ - t->l2_cache_handle = cpu_to_le16(0xFFFF); /* N/A */ - t->l3_cache_handle = cpu_to_le16(0xFFFF); /* N/A */ - SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial); - SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset); - SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part); - t->core_count = t->core_enabled = smp_cores; - t->thread_count = smp_threads; - t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */ - t->processor_family2 = cpu_to_le16(0x01); /* Other */ - - SMBIOS_BUILD_TABLE_POST; - smbios_type4_count++; -} - -#define ONE_KB ((ram_addr_t)1 << 10) -#define ONE_MB ((ram_addr_t)1 << 20) -#define ONE_GB ((ram_addr_t)1 << 30) - -#define MAX_T16_STD_SZ 0x80000000 /* 2T in Kilobytes */ - -static void smbios_build_type_16_table(unsigned dimm_cnt) -{ - uint64_t size_kb; - - SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */ - - t->location = 0x01; /* Other */ - t->use = 0x03; /* System memory */ - t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */ - size_kb = QEMU_ALIGN_UP(ram_size, ONE_KB) / ONE_KB; - if (size_kb < MAX_T16_STD_SZ) { - t->maximum_capacity = cpu_to_le32(size_kb); - t->extended_maximum_capacity = cpu_to_le64(0); - } else { - t->maximum_capacity = cpu_to_le32(MAX_T16_STD_SZ); - t->extended_maximum_capacity = cpu_to_le64(ram_size); - } - t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */ - t->number_of_memory_devices = cpu_to_le16(dimm_cnt); - - SMBIOS_BUILD_TABLE_POST; -} - -#define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */ -#define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */ - -static void smbios_build_type_17_table(unsigned instance, uint64_t size) -{ - char loc_str[128]; - uint64_t size_mb; - - SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */ - - t->physical_memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */ - t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */ - t->total_width = cpu_to_le16(0xFFFF); /* Unknown */ - t->data_width = cpu_to_le16(0xFFFF); /* Unknown */ - size_mb = QEMU_ALIGN_UP(size, ONE_MB) / ONE_MB; - if (size_mb < MAX_T17_STD_SZ) { - t->size = cpu_to_le16(size_mb); - t->extended_size = cpu_to_le32(0); - } else { - assert(size_mb < MAX_T17_EXT_SZ); - t->size = cpu_to_le16(MAX_T17_STD_SZ); - t->extended_size = cpu_to_le32(size_mb); - } - t->form_factor = 0x09; /* DIMM */ - t->device_set = 0; /* Not in a set */ - snprintf(loc_str, sizeof(loc_str), "%s %d", type17.loc_pfx, instance); - SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str); - SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank); - t->memory_type = 0x07; /* RAM */ - t->type_detail = cpu_to_le16(0x02); /* Other */ - t->speed = cpu_to_le16(type17.speed); - SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer); - SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial); - SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset); - SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part); - t->attributes = 0; /* Unknown */ - t->configured_clock_speed = t->speed; /* reuse value for max speed */ - t->minimum_voltage = cpu_to_le16(0); /* Unknown */ - t->maximum_voltage = cpu_to_le16(0); /* Unknown */ - t->configured_voltage = cpu_to_le16(0); /* Unknown */ - - SMBIOS_BUILD_TABLE_POST; -} - -static void smbios_build_type_19_table(unsigned instance, - uint64_t start, uint64_t size) -{ - uint64_t end, start_kb, end_kb; - - SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */ - - end = start + size - 1; - assert(end > start); - start_kb = start / ONE_KB; - end_kb = end / ONE_KB; - if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) { - t->starting_address = cpu_to_le32(start_kb); - t->ending_address = cpu_to_le32(end_kb); - t->extended_starting_address = - t->extended_ending_address = cpu_to_le64(0); - } else { - t->starting_address = t->ending_address = cpu_to_le32(UINT32_MAX); - t->extended_starting_address = cpu_to_le64(start); - t->extended_ending_address = cpu_to_le64(end); - } - t->memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */ - t->partition_width = 1; /* One device per row */ - - SMBIOS_BUILD_TABLE_POST; -} - -static void smbios_build_type_32_table(void) -{ - SMBIOS_BUILD_TABLE_PRE(32, 0x2000, true); /* required */ - - memset(t->reserved, 0, 6); - t->boot_status = 0; /* No errors detected */ - - SMBIOS_BUILD_TABLE_POST; -} - -static void smbios_build_type_127_table(void) -{ - SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */ - SMBIOS_BUILD_TABLE_POST; -} - -void smbios_set_cpuid(uint32_t version, uint32_t features) -{ - smbios_cpuid_version = version; - smbios_cpuid_features = features; -} - -#define SMBIOS_SET_DEFAULT(field, value) \ - if (!field) { \ - field = value; \ - } - -void smbios_set_defaults(const char *manufacturer, const char *product, - const char *version, bool legacy_mode, - bool uuid_encoded) -{ - smbios_have_defaults = true; - smbios_legacy = legacy_mode; - smbios_uuid_encoded = uuid_encoded; - - /* drop unwanted version of command-line file blob(s) */ - if (smbios_legacy) { - g_free(smbios_tables); - /* in legacy mode, also complain if fields were given for types > 1 */ - if (find_next_bit(have_fields_bitmap, - SMBIOS_MAX_TYPE+1, 2) < SMBIOS_MAX_TYPE+1) { - error_report("can't process fields for smbios " - "types > 1 on machine versions < 2.1!"); - exit(1); - } - } else { - g_free(smbios_entries); - } - - SMBIOS_SET_DEFAULT(type1.manufacturer, manufacturer); - SMBIOS_SET_DEFAULT(type1.product, product); - SMBIOS_SET_DEFAULT(type1.version, version); - SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer); - SMBIOS_SET_DEFAULT(type2.product, product); - SMBIOS_SET_DEFAULT(type2.version, version); - SMBIOS_SET_DEFAULT(type3.manufacturer, manufacturer); - SMBIOS_SET_DEFAULT(type3.version, version); - SMBIOS_SET_DEFAULT(type4.sock_pfx, "CPU"); - SMBIOS_SET_DEFAULT(type4.manufacturer, manufacturer); - SMBIOS_SET_DEFAULT(type4.version, version); - SMBIOS_SET_DEFAULT(type17.loc_pfx, "DIMM"); - SMBIOS_SET_DEFAULT(type17.manufacturer, manufacturer); -} - -static void smbios_entry_point_setup(void) -{ - memcpy(ep.anchor_string, "_SM_", 4); - memcpy(ep.intermediate_anchor_string, "_DMI_", 5); - ep.length = sizeof(struct smbios_entry_point); - ep.entry_point_revision = 0; /* formatted_area reserved, per spec v2.1+ */ - memset(ep.formatted_area, 0, 5); - - /* compliant with smbios spec v2.8 */ - ep.smbios_major_version = 2; - ep.smbios_minor_version = 8; - ep.smbios_bcd_revision = 0x28; - - /* set during table construction, but BIOS may override: */ - ep.structure_table_length = cpu_to_le16(smbios_tables_len); - ep.max_structure_size = cpu_to_le16(smbios_table_max); - ep.number_of_structures = cpu_to_le16(smbios_table_cnt); - - /* BIOS must recalculate: */ - ep.checksum = 0; - ep.intermediate_checksum = 0; - ep.structure_table_address = cpu_to_le32(0); -} - -void smbios_get_tables(const struct smbios_phys_mem_area *mem_array, - const unsigned int mem_array_size, - uint8_t **tables, size_t *tables_len, - uint8_t **anchor, size_t *anchor_len) -{ - unsigned i, dimm_cnt; - - if (smbios_legacy) { - *tables = *anchor = NULL; - *tables_len = *anchor_len = 0; - return; - } - - if (!smbios_immutable) { - smbios_build_type_0_table(); - smbios_build_type_1_table(); - smbios_build_type_2_table(); - smbios_build_type_3_table(); - - smbios_smp_sockets = DIV_ROUND_UP(smp_cpus, smp_cores * smp_threads); - assert(smbios_smp_sockets >= 1); - - for (i = 0; i < smbios_smp_sockets; i++) { - smbios_build_type_4_table(i); - } - -#define MAX_DIMM_SZ (16ll * ONE_GB) -#define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ \ - : ((ram_size - 1) % MAX_DIMM_SZ) + 1) - - dimm_cnt = QEMU_ALIGN_UP(ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ; - - smbios_build_type_16_table(dimm_cnt); - - for (i = 0; i < dimm_cnt; i++) { - smbios_build_type_17_table(i, GET_DIMM_SZ); - } - - for (i = 0; i < mem_array_size; i++) { - smbios_build_type_19_table(i, mem_array[i].address, - mem_array[i].length); - } - - smbios_build_type_32_table(); - smbios_build_type_127_table(); - - smbios_validate_table(); - smbios_entry_point_setup(); - smbios_immutable = true; - } - - /* return tables blob and entry point (anchor), and their sizes */ - *tables = smbios_tables; - *tables_len = smbios_tables_len; - *anchor = (uint8_t *)&ep; - *anchor_len = sizeof(struct smbios_entry_point); -} - -static void save_opt(const char **dest, QemuOpts *opts, const char *name) -{ - const char *val = qemu_opt_get(opts, name); - - if (val) { - *dest = val; - } -} - -void smbios_entry_add(QemuOpts *opts) -{ - Error *local_err = NULL; - const char *val; - - assert(!smbios_immutable); - - val = qemu_opt_get(opts, "file"); - if (val) { - struct smbios_structure_header *header; - int size; - struct smbios_table *table; /* legacy mode only */ - - qemu_opts_validate(opts, qemu_smbios_file_opts, &local_err); - if (local_err) { - error_report_err(local_err); - exit(1); - } - - size = get_image_size(val); - if (size == -1 || size < sizeof(struct smbios_structure_header)) { - error_report("Cannot read SMBIOS file %s", val); - exit(1); - } - - /* - * NOTE: standard double '\0' terminator expected, per smbios spec. - * (except in legacy mode, where the second '\0' is implicit and - * will be inserted by the BIOS). - */ - smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size); - header = (struct smbios_structure_header *)(smbios_tables + - smbios_tables_len); - - if (load_image(val, (uint8_t *)header) != size) { - error_report("Failed to load SMBIOS file %s", val); - exit(1); - } - - if (test_bit(header->type, have_fields_bitmap)) { - error_report("can't load type %d struct, fields already specified!", - header->type); - exit(1); - } - set_bit(header->type, have_binfile_bitmap); - - if (header->type == 4) { - smbios_type4_count++; - } - - smbios_tables_len += size; - if (size > smbios_table_max) { - smbios_table_max = size; - } - smbios_table_cnt++; - - /* add a copy of the newly loaded blob to legacy smbios_entries */ - /* NOTE: This code runs before smbios_set_defaults(), so we don't - * yet know which mode (legacy vs. aggregate-table) will be - * required. We therefore add the binary blob to both legacy - * (smbios_entries) and aggregate (smbios_tables) tables, and - * delete the one we don't need from smbios_set_defaults(), - * once we know which machine version has been requested. - */ - if (!smbios_entries) { - smbios_entries_len = sizeof(uint16_t); - smbios_entries = g_malloc0(smbios_entries_len); - } - smbios_entries = g_realloc(smbios_entries, smbios_entries_len + - size + sizeof(*table)); - table = (struct smbios_table *)(smbios_entries + smbios_entries_len); - table->header.type = SMBIOS_TABLE_ENTRY; - table->header.length = cpu_to_le16(sizeof(*table) + size); - memcpy(table->data, header, size); - smbios_entries_len += sizeof(*table) + size; - (*(uint16_t *)smbios_entries) = - cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); - /* end: add a copy of the newly loaded blob to legacy smbios_entries */ - - return; - } - - val = qemu_opt_get(opts, "type"); - if (val) { - unsigned long type = strtoul(val, NULL, 0); - - if (type > SMBIOS_MAX_TYPE) { - error_report("out of range!"); - exit(1); - } - - if (test_bit(type, have_binfile_bitmap)) { - error_report("can't add fields, binary file already loaded!"); - exit(1); - } - set_bit(type, have_fields_bitmap); - - switch (type) { - case 0: - qemu_opts_validate(opts, qemu_smbios_type0_opts, &local_err); - if (local_err) { - error_report_err(local_err); - exit(1); - } - save_opt(&type0.vendor, opts, "vendor"); - save_opt(&type0.version, opts, "version"); - save_opt(&type0.date, opts, "date"); - type0.uefi = qemu_opt_get_bool(opts, "uefi", false); - - val = qemu_opt_get(opts, "release"); - if (val) { - if (sscanf(val, "%hhu.%hhu", &type0.major, &type0.minor) != 2) { - error_report("Invalid release"); - exit(1); - } - type0.have_major_minor = true; - } - return; - case 1: - qemu_opts_validate(opts, qemu_smbios_type1_opts, &local_err); - if (local_err) { - error_report_err(local_err); - exit(1); - } - save_opt(&type1.manufacturer, opts, "manufacturer"); - save_opt(&type1.product, opts, "product"); - save_opt(&type1.version, opts, "version"); - save_opt(&type1.serial, opts, "serial"); - save_opt(&type1.sku, opts, "sku"); - save_opt(&type1.family, opts, "family"); - - val = qemu_opt_get(opts, "uuid"); - if (val) { - if (qemu_uuid_parse(val, qemu_uuid) != 0) { - error_report("Invalid UUID"); - exit(1); - } - qemu_uuid_set = true; - } - return; - case 2: - qemu_opts_validate(opts, qemu_smbios_type2_opts, &local_err); - if (local_err) { - error_report_err(local_err); - exit(1); - } - save_opt(&type2.manufacturer, opts, "manufacturer"); - save_opt(&type2.product, opts, "product"); - save_opt(&type2.version, opts, "version"); - save_opt(&type2.serial, opts, "serial"); - save_opt(&type2.asset, opts, "asset"); - save_opt(&type2.location, opts, "location"); - return; - case 3: - qemu_opts_validate(opts, qemu_smbios_type3_opts, &local_err); - if (local_err) { - error_report_err(local_err); - exit(1); - } - save_opt(&type3.manufacturer, opts, "manufacturer"); - save_opt(&type3.version, opts, "version"); - save_opt(&type3.serial, opts, "serial"); - save_opt(&type3.asset, opts, "asset"); - save_opt(&type3.sku, opts, "sku"); - return; - case 4: - qemu_opts_validate(opts, qemu_smbios_type4_opts, &local_err); - if (local_err) { - error_report_err(local_err); - exit(1); - } - save_opt(&type4.sock_pfx, opts, "sock_pfx"); - save_opt(&type4.manufacturer, opts, "manufacturer"); - save_opt(&type4.version, opts, "version"); - save_opt(&type4.serial, opts, "serial"); - save_opt(&type4.asset, opts, "asset"); - save_opt(&type4.part, opts, "part"); - return; - case 17: - qemu_opts_validate(opts, qemu_smbios_type17_opts, &local_err); - if (local_err) { - error_report_err(local_err); - exit(1); - } - save_opt(&type17.loc_pfx, opts, "loc_pfx"); - save_opt(&type17.bank, opts, "bank"); - save_opt(&type17.manufacturer, opts, "manufacturer"); - save_opt(&type17.serial, opts, "serial"); - save_opt(&type17.asset, opts, "asset"); - save_opt(&type17.part, opts, "part"); - type17.speed = qemu_opt_get_number(opts, "speed", 0); - return; - default: - error_report("Don't know how to build fields for SMBIOS type %ld", - type); - exit(1); - } - } - - error_report("Must specify type= or file="); - exit(1); -} diff --git a/hw/smbios/Makefile.objs b/hw/smbios/Makefile.objs new file mode 100644 index 0000000..f69a92f --- /dev/null +++ b/hw/smbios/Makefile.objs @@ -0,0 +1 @@ +common-obj-$(CONFIG_SMBIOS) += smbios.o diff --git a/hw/smbios/smbios.c b/hw/smbios/smbios.c new file mode 100644 index 0000000..efdbb5d --- /dev/null +++ b/hw/smbios/smbios.c @@ -0,0 +1,1101 @@ +/* + * SMBIOS Support + * + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. + * Copyright (C) 2013 Red Hat, Inc. + * + * Authors: + * Alex Williamson + * Markus Armbruster + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Contributions after 2012-01-13 are licensed under the terms of the + * GNU GPL, version 2 or (at your option) any later version. + */ + +#include "qemu/config-file.h" +#include "qemu/error-report.h" +#include "sysemu/sysemu.h" +#include "sysemu/cpus.h" +#include "hw/smbios/smbios.h" +#include "hw/loader.h" +#include "exec/cpu-common.h" + +/* legacy structures and constants for <= 2.0 machines */ +struct smbios_header { + uint16_t length; + uint8_t type; +} QEMU_PACKED; + +struct smbios_field { + struct smbios_header header; + uint8_t type; + uint16_t offset; + uint8_t data[]; +} QEMU_PACKED; + +struct smbios_table { + struct smbios_header header; + uint8_t data[]; +} QEMU_PACKED; + +#define SMBIOS_FIELD_ENTRY 0 +#define SMBIOS_TABLE_ENTRY 1 + +static uint8_t *smbios_entries; +static size_t smbios_entries_len; +static bool smbios_legacy = true; +static bool smbios_uuid_encoded = true; +/* end: legacy structures & constants for <= 2.0 machines */ + + +static uint8_t *smbios_tables; +static size_t smbios_tables_len; +static unsigned smbios_table_max; +static unsigned smbios_table_cnt; +static struct smbios_entry_point ep; + +static int smbios_type4_count = 0; +static bool smbios_immutable; +static bool smbios_have_defaults; +static uint32_t smbios_cpuid_version, smbios_cpuid_features, smbios_smp_sockets; + +static DECLARE_BITMAP(have_binfile_bitmap, SMBIOS_MAX_TYPE+1); +static DECLARE_BITMAP(have_fields_bitmap, SMBIOS_MAX_TYPE+1); + +static struct { + const char *vendor, *version, *date; + bool have_major_minor, uefi; + uint8_t major, minor; +} type0; + +static struct { + const char *manufacturer, *product, *version, *serial, *sku, *family; + /* uuid is in qemu_uuid[] */ +} type1; + +static struct { + const char *manufacturer, *product, *version, *serial, *asset, *location; +} type2; + +static struct { + const char *manufacturer, *version, *serial, *asset, *sku; +} type3; + +static struct { + const char *sock_pfx, *manufacturer, *version, *serial, *asset, *part; +} type4; + +static struct { + const char *loc_pfx, *bank, *manufacturer, *serial, *asset, *part; + uint16_t speed; +} type17; + +static QemuOptsList qemu_smbios_opts = { + .name = "smbios", + .head = QTAILQ_HEAD_INITIALIZER(qemu_smbios_opts.head), + .desc = { + /* + * no elements => accept any params + * validation will happen later + */ + { /* end of list */ } + } +}; + +static const QemuOptDesc qemu_smbios_file_opts[] = { + { + .name = "file", + .type = QEMU_OPT_STRING, + .help = "binary file containing an SMBIOS element", + }, + { /* end of list */ } +}; + +static const QemuOptDesc qemu_smbios_type0_opts[] = { + { + .name = "type", + .type = QEMU_OPT_NUMBER, + .help = "SMBIOS element type", + },{ + .name = "vendor", + .type = QEMU_OPT_STRING, + .help = "vendor name", + },{ + .name = "version", + .type = QEMU_OPT_STRING, + .help = "version number", + },{ + .name = "date", + .type = QEMU_OPT_STRING, + .help = "release date", + },{ + .name = "release", + .type = QEMU_OPT_STRING, + .help = "revision number", + },{ + .name = "uefi", + .type = QEMU_OPT_BOOL, + .help = "uefi support", + }, + { /* end of list */ } +}; + +static const QemuOptDesc qemu_smbios_type1_opts[] = { + { + .name = "type", + .type = QEMU_OPT_NUMBER, + .help = "SMBIOS element type", + },{ + .name = "manufacturer", + .type = QEMU_OPT_STRING, + .help = "manufacturer name", + },{ + .name = "product", + .type = QEMU_OPT_STRING, + .help = "product name", + },{ + .name = "version", + .type = QEMU_OPT_STRING, + .help = "version number", + },{ + .name = "serial", + .type = QEMU_OPT_STRING, + .help = "serial number", + },{ + .name = "uuid", + .type = QEMU_OPT_STRING, + .help = "UUID", + },{ + .name = "sku", + .type = QEMU_OPT_STRING, + .help = "SKU number", + },{ + .name = "family", + .type = QEMU_OPT_STRING, + .help = "family name", + }, + { /* end of list */ } +}; + +static const QemuOptDesc qemu_smbios_type2_opts[] = { + { + .name = "type", + .type = QEMU_OPT_NUMBER, + .help = "SMBIOS element type", + },{ + .name = "manufacturer", + .type = QEMU_OPT_STRING, + .help = "manufacturer name", + },{ + .name = "product", + .type = QEMU_OPT_STRING, + .help = "product name", + },{ + .name = "version", + .type = QEMU_OPT_STRING, + .help = "version number", + },{ + .name = "serial", + .type = QEMU_OPT_STRING, + .help = "serial number", + },{ + .name = "asset", + .type = QEMU_OPT_STRING, + .help = "asset tag number", + },{ + .name = "location", + .type = QEMU_OPT_STRING, + .help = "location in chassis", + }, + { /* end of list */ } +}; + +static const QemuOptDesc qemu_smbios_type3_opts[] = { + { + .name = "type", + .type = QEMU_OPT_NUMBER, + .help = "SMBIOS element type", + },{ + .name = "manufacturer", + .type = QEMU_OPT_STRING, + .help = "manufacturer name", + },{ + .name = "version", + .type = QEMU_OPT_STRING, + .help = "version number", + },{ + .name = "serial", + .type = QEMU_OPT_STRING, + .help = "serial number", + },{ + .name = "asset", + .type = QEMU_OPT_STRING, + .help = "asset tag number", + },{ + .name = "sku", + .type = QEMU_OPT_STRING, + .help = "SKU number", + }, + { /* end of list */ } +}; + +static const QemuOptDesc qemu_smbios_type4_opts[] = { + { + .name = "type", + .type = QEMU_OPT_NUMBER, + .help = "SMBIOS element type", + },{ + .name = "sock_pfx", + .type = QEMU_OPT_STRING, + .help = "socket designation string prefix", + },{ + .name = "manufacturer", + .type = QEMU_OPT_STRING, + .help = "manufacturer name", + },{ + .name = "version", + .type = QEMU_OPT_STRING, + .help = "version number", + },{ + .name = "serial", + .type = QEMU_OPT_STRING, + .help = "serial number", + },{ + .name = "asset", + .type = QEMU_OPT_STRING, + .help = "asset tag number", + },{ + .name = "part", + .type = QEMU_OPT_STRING, + .help = "part number", + }, + { /* end of list */ } +}; + +static const QemuOptDesc qemu_smbios_type17_opts[] = { + { + .name = "type", + .type = QEMU_OPT_NUMBER, + .help = "SMBIOS element type", + },{ + .name = "loc_pfx", + .type = QEMU_OPT_STRING, + .help = "device locator string prefix", + },{ + .name = "bank", + .type = QEMU_OPT_STRING, + .help = "bank locator string", + },{ + .name = "manufacturer", + .type = QEMU_OPT_STRING, + .help = "manufacturer name", + },{ + .name = "serial", + .type = QEMU_OPT_STRING, + .help = "serial number", + },{ + .name = "asset", + .type = QEMU_OPT_STRING, + .help = "asset tag number", + },{ + .name = "part", + .type = QEMU_OPT_STRING, + .help = "part number", + },{ + .name = "speed", + .type = QEMU_OPT_NUMBER, + .help = "maximum capable speed", + }, + { /* end of list */ } +}; + +static void smbios_register_config(void) +{ + qemu_add_opts(&qemu_smbios_opts); +} + +machine_init(smbios_register_config); + +static void smbios_validate_table(void) +{ + uint32_t expect_t4_count = smbios_legacy ? smp_cpus : smbios_smp_sockets; + + if (smbios_type4_count && smbios_type4_count != expect_t4_count) { + error_report("Expected %d SMBIOS Type 4 tables, got %d instead", + expect_t4_count, smbios_type4_count); + exit(1); + } +} + + +/* legacy setup functions for <= 2.0 machines */ +static void smbios_add_field(int type, int offset, const void *data, size_t len) +{ + struct smbios_field *field; + + if (!smbios_entries) { + smbios_entries_len = sizeof(uint16_t); + smbios_entries = g_malloc0(smbios_entries_len); + } + smbios_entries = g_realloc(smbios_entries, smbios_entries_len + + sizeof(*field) + len); + field = (struct smbios_field *)(smbios_entries + smbios_entries_len); + field->header.type = SMBIOS_FIELD_ENTRY; + field->header.length = cpu_to_le16(sizeof(*field) + len); + + field->type = type; + field->offset = cpu_to_le16(offset); + memcpy(field->data, data, len); + + smbios_entries_len += sizeof(*field) + len; + (*(uint16_t *)smbios_entries) = + cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); +} + +static void smbios_maybe_add_str(int type, int offset, const char *data) +{ + if (data) { + smbios_add_field(type, offset, data, strlen(data) + 1); + } +} + +static void smbios_build_type_0_fields(void) +{ + smbios_maybe_add_str(0, offsetof(struct smbios_type_0, vendor_str), + type0.vendor); + smbios_maybe_add_str(0, offsetof(struct smbios_type_0, bios_version_str), + type0.version); + smbios_maybe_add_str(0, offsetof(struct smbios_type_0, + bios_release_date_str), + type0.date); + if (type0.have_major_minor) { + smbios_add_field(0, offsetof(struct smbios_type_0, + system_bios_major_release), + &type0.major, 1); + smbios_add_field(0, offsetof(struct smbios_type_0, + system_bios_minor_release), + &type0.minor, 1); + } +} + +static void smbios_build_type_1_fields(void) +{ + smbios_maybe_add_str(1, offsetof(struct smbios_type_1, manufacturer_str), + type1.manufacturer); + smbios_maybe_add_str(1, offsetof(struct smbios_type_1, product_name_str), + type1.product); + smbios_maybe_add_str(1, offsetof(struct smbios_type_1, version_str), + type1.version); + smbios_maybe_add_str(1, offsetof(struct smbios_type_1, serial_number_str), + type1.serial); + smbios_maybe_add_str(1, offsetof(struct smbios_type_1, sku_number_str), + type1.sku); + smbios_maybe_add_str(1, offsetof(struct smbios_type_1, family_str), + type1.family); + if (qemu_uuid_set) { + /* We don't encode the UUID in the "wire format" here because this + * function is for legacy mode and needs to keep the guest ABI, and + * because we don't know what's the SMBIOS version advertised by the + * BIOS. + */ + smbios_add_field(1, offsetof(struct smbios_type_1, uuid), + qemu_uuid, 16); + } +} + +uint8_t *smbios_get_table_legacy(size_t *length) +{ + if (!smbios_legacy) { + *length = 0; + return NULL; + } + + if (!smbios_immutable) { + smbios_build_type_0_fields(); + smbios_build_type_1_fields(); + smbios_validate_table(); + smbios_immutable = true; + } + *length = smbios_entries_len; + return smbios_entries; +} +/* end: legacy setup functions for <= 2.0 machines */ + + +static bool smbios_skip_table(uint8_t type, bool required_table) +{ + if (test_bit(type, have_binfile_bitmap)) { + return true; /* user provided their own binary blob(s) */ + } + if (test_bit(type, have_fields_bitmap)) { + return false; /* user provided fields via command line */ + } + if (smbios_have_defaults && required_table) { + return false; /* we're building tables, and this one's required */ + } + return true; +} + +#define SMBIOS_BUILD_TABLE_PRE(tbl_type, tbl_handle, tbl_required) \ + struct smbios_type_##tbl_type *t; \ + size_t t_off; /* table offset into smbios_tables */ \ + int str_index = 0; \ + do { \ + /* should we skip building this table ? */ \ + if (smbios_skip_table(tbl_type, tbl_required)) { \ + return; \ + } \ + \ + /* use offset of table t within smbios_tables */ \ + /* (pointer must be updated after each realloc) */ \ + t_off = smbios_tables_len; \ + smbios_tables_len += sizeof(*t); \ + smbios_tables = g_realloc(smbios_tables, smbios_tables_len); \ + t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \ + \ + t->header.type = tbl_type; \ + t->header.length = sizeof(*t); \ + t->header.handle = cpu_to_le16(tbl_handle); \ + } while (0) + +#define SMBIOS_TABLE_SET_STR(tbl_type, field, value) \ + do { \ + int len = (value != NULL) ? strlen(value) + 1 : 0; \ + if (len > 1) { \ + smbios_tables = g_realloc(smbios_tables, \ + smbios_tables_len + len); \ + memcpy(smbios_tables + smbios_tables_len, value, len); \ + smbios_tables_len += len; \ + /* update pointer post-realloc */ \ + t = (struct smbios_type_##tbl_type *)(smbios_tables + t_off); \ + t->field = ++str_index; \ + } else { \ + t->field = 0; \ + } \ + } while (0) + +#define SMBIOS_BUILD_TABLE_POST \ + do { \ + size_t term_cnt, t_size; \ + \ + /* add '\0' terminator (add two if no strings defined) */ \ + term_cnt = (str_index == 0) ? 2 : 1; \ + smbios_tables = g_realloc(smbios_tables, \ + smbios_tables_len + term_cnt); \ + memset(smbios_tables + smbios_tables_len, 0, term_cnt); \ + smbios_tables_len += term_cnt; \ + \ + /* update smbios max. element size */ \ + t_size = smbios_tables_len - t_off; \ + if (t_size > smbios_table_max) { \ + smbios_table_max = t_size; \ + } \ + \ + /* update smbios element count */ \ + smbios_table_cnt++; \ + } while (0) + +static void smbios_build_type_0_table(void) +{ + SMBIOS_BUILD_TABLE_PRE(0, 0x000, false); /* optional, leave up to BIOS */ + + SMBIOS_TABLE_SET_STR(0, vendor_str, type0.vendor); + SMBIOS_TABLE_SET_STR(0, bios_version_str, type0.version); + + t->bios_starting_address_segment = cpu_to_le16(0xE800); /* from SeaBIOS */ + + SMBIOS_TABLE_SET_STR(0, bios_release_date_str, type0.date); + + t->bios_rom_size = 0; /* hardcoded in SeaBIOS with FIXME comment */ + + t->bios_characteristics = cpu_to_le64(0x08); /* Not supported */ + t->bios_characteristics_extension_bytes[0] = 0; + t->bios_characteristics_extension_bytes[1] = 0x14; /* TCD/SVVP | VM */ + if (type0.uefi) { + t->bios_characteristics_extension_bytes[1] |= 0x08; /* |= UEFI */ + } + + if (type0.have_major_minor) { + t->system_bios_major_release = type0.major; + t->system_bios_minor_release = type0.minor; + } else { + t->system_bios_major_release = 0; + t->system_bios_minor_release = 0; + } + + /* hardcoded in SeaBIOS */ + t->embedded_controller_major_release = 0xFF; + t->embedded_controller_minor_release = 0xFF; + + SMBIOS_BUILD_TABLE_POST; +} + +/* Encode UUID from the big endian encoding described on RFC4122 to the wire + * format specified by SMBIOS version 2.6. + */ +static void smbios_encode_uuid(struct smbios_uuid *uuid, const uint8_t *buf) +{ + memcpy(uuid, buf, 16); + if (smbios_uuid_encoded) { + uuid->time_low = bswap32(uuid->time_low); + uuid->time_mid = bswap16(uuid->time_mid); + uuid->time_hi_and_version = bswap16(uuid->time_hi_and_version); + } +} + +static void smbios_build_type_1_table(void) +{ + SMBIOS_BUILD_TABLE_PRE(1, 0x100, true); /* required */ + + SMBIOS_TABLE_SET_STR(1, manufacturer_str, type1.manufacturer); + SMBIOS_TABLE_SET_STR(1, product_name_str, type1.product); + SMBIOS_TABLE_SET_STR(1, version_str, type1.version); + SMBIOS_TABLE_SET_STR(1, serial_number_str, type1.serial); + if (qemu_uuid_set) { + smbios_encode_uuid(&t->uuid, qemu_uuid); + } else { + memset(&t->uuid, 0, 16); + } + t->wake_up_type = 0x06; /* power switch */ + SMBIOS_TABLE_SET_STR(1, sku_number_str, type1.sku); + SMBIOS_TABLE_SET_STR(1, family_str, type1.family); + + SMBIOS_BUILD_TABLE_POST; +} + +static void smbios_build_type_2_table(void) +{ + SMBIOS_BUILD_TABLE_PRE(2, 0x200, false); /* optional */ + + SMBIOS_TABLE_SET_STR(2, manufacturer_str, type2.manufacturer); + SMBIOS_TABLE_SET_STR(2, product_str, type2.product); + SMBIOS_TABLE_SET_STR(2, version_str, type2.version); + SMBIOS_TABLE_SET_STR(2, serial_number_str, type2.serial); + SMBIOS_TABLE_SET_STR(2, asset_tag_number_str, type2.asset); + t->feature_flags = 0x01; /* Motherboard */ + SMBIOS_TABLE_SET_STR(2, location_str, type2.location); + t->chassis_handle = cpu_to_le16(0x300); /* Type 3 (System enclosure) */ + t->board_type = 0x0A; /* Motherboard */ + t->contained_element_count = 0; + + SMBIOS_BUILD_TABLE_POST; +} + +static void smbios_build_type_3_table(void) +{ + SMBIOS_BUILD_TABLE_PRE(3, 0x300, true); /* required */ + + SMBIOS_TABLE_SET_STR(3, manufacturer_str, type3.manufacturer); + t->type = 0x01; /* Other */ + SMBIOS_TABLE_SET_STR(3, version_str, type3.version); + SMBIOS_TABLE_SET_STR(3, serial_number_str, type3.serial); + SMBIOS_TABLE_SET_STR(3, asset_tag_number_str, type3.asset); + t->boot_up_state = 0x03; /* Safe */ + t->power_supply_state = 0x03; /* Safe */ + t->thermal_state = 0x03; /* Safe */ + t->security_status = 0x02; /* Unknown */ + t->oem_defined = cpu_to_le32(0); + t->height = 0; + t->number_of_power_cords = 0; + t->contained_element_count = 0; + SMBIOS_TABLE_SET_STR(3, sku_number_str, type3.sku); + + SMBIOS_BUILD_TABLE_POST; +} + +static void smbios_build_type_4_table(unsigned instance) +{ + char sock_str[128]; + + SMBIOS_BUILD_TABLE_PRE(4, 0x400 + instance, true); /* required */ + + snprintf(sock_str, sizeof(sock_str), "%s%2x", type4.sock_pfx, instance); + SMBIOS_TABLE_SET_STR(4, socket_designation_str, sock_str); + t->processor_type = 0x03; /* CPU */ + t->processor_family = 0x01; /* Other */ + SMBIOS_TABLE_SET_STR(4, processor_manufacturer_str, type4.manufacturer); + t->processor_id[0] = cpu_to_le32(smbios_cpuid_version); + t->processor_id[1] = cpu_to_le32(smbios_cpuid_features); + SMBIOS_TABLE_SET_STR(4, processor_version_str, type4.version); + t->voltage = 0; + t->external_clock = cpu_to_le16(0); /* Unknown */ + /* SVVP requires max_speed and current_speed to not be unknown. */ + t->max_speed = cpu_to_le16(2000); /* 2000 MHz */ + t->current_speed = cpu_to_le16(2000); /* 2000 MHz */ + t->status = 0x41; /* Socket populated, CPU enabled */ + t->processor_upgrade = 0x01; /* Other */ + t->l1_cache_handle = cpu_to_le16(0xFFFF); /* N/A */ + t->l2_cache_handle = cpu_to_le16(0xFFFF); /* N/A */ + t->l3_cache_handle = cpu_to_le16(0xFFFF); /* N/A */ + SMBIOS_TABLE_SET_STR(4, serial_number_str, type4.serial); + SMBIOS_TABLE_SET_STR(4, asset_tag_number_str, type4.asset); + SMBIOS_TABLE_SET_STR(4, part_number_str, type4.part); + t->core_count = t->core_enabled = smp_cores; + t->thread_count = smp_threads; + t->processor_characteristics = cpu_to_le16(0x02); /* Unknown */ + t->processor_family2 = cpu_to_le16(0x01); /* Other */ + + SMBIOS_BUILD_TABLE_POST; + smbios_type4_count++; +} + +#define ONE_KB ((ram_addr_t)1 << 10) +#define ONE_MB ((ram_addr_t)1 << 20) +#define ONE_GB ((ram_addr_t)1 << 30) + +#define MAX_T16_STD_SZ 0x80000000 /* 2T in Kilobytes */ + +static void smbios_build_type_16_table(unsigned dimm_cnt) +{ + uint64_t size_kb; + + SMBIOS_BUILD_TABLE_PRE(16, 0x1000, true); /* required */ + + t->location = 0x01; /* Other */ + t->use = 0x03; /* System memory */ + t->error_correction = 0x06; /* Multi-bit ECC (for Microsoft, per SeaBIOS) */ + size_kb = QEMU_ALIGN_UP(ram_size, ONE_KB) / ONE_KB; + if (size_kb < MAX_T16_STD_SZ) { + t->maximum_capacity = cpu_to_le32(size_kb); + t->extended_maximum_capacity = cpu_to_le64(0); + } else { + t->maximum_capacity = cpu_to_le32(MAX_T16_STD_SZ); + t->extended_maximum_capacity = cpu_to_le64(ram_size); + } + t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */ + t->number_of_memory_devices = cpu_to_le16(dimm_cnt); + + SMBIOS_BUILD_TABLE_POST; +} + +#define MAX_T17_STD_SZ 0x7FFF /* (32G - 1M), in Megabytes */ +#define MAX_T17_EXT_SZ 0x80000000 /* 2P, in Megabytes */ + +static void smbios_build_type_17_table(unsigned instance, uint64_t size) +{ + char loc_str[128]; + uint64_t size_mb; + + SMBIOS_BUILD_TABLE_PRE(17, 0x1100 + instance, true); /* required */ + + t->physical_memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */ + t->memory_error_information_handle = cpu_to_le16(0xFFFE); /* Not provided */ + t->total_width = cpu_to_le16(0xFFFF); /* Unknown */ + t->data_width = cpu_to_le16(0xFFFF); /* Unknown */ + size_mb = QEMU_ALIGN_UP(size, ONE_MB) / ONE_MB; + if (size_mb < MAX_T17_STD_SZ) { + t->size = cpu_to_le16(size_mb); + t->extended_size = cpu_to_le32(0); + } else { + assert(size_mb < MAX_T17_EXT_SZ); + t->size = cpu_to_le16(MAX_T17_STD_SZ); + t->extended_size = cpu_to_le32(size_mb); + } + t->form_factor = 0x09; /* DIMM */ + t->device_set = 0; /* Not in a set */ + snprintf(loc_str, sizeof(loc_str), "%s %d", type17.loc_pfx, instance); + SMBIOS_TABLE_SET_STR(17, device_locator_str, loc_str); + SMBIOS_TABLE_SET_STR(17, bank_locator_str, type17.bank); + t->memory_type = 0x07; /* RAM */ + t->type_detail = cpu_to_le16(0x02); /* Other */ + t->speed = cpu_to_le16(type17.speed); + SMBIOS_TABLE_SET_STR(17, manufacturer_str, type17.manufacturer); + SMBIOS_TABLE_SET_STR(17, serial_number_str, type17.serial); + SMBIOS_TABLE_SET_STR(17, asset_tag_number_str, type17.asset); + SMBIOS_TABLE_SET_STR(17, part_number_str, type17.part); + t->attributes = 0; /* Unknown */ + t->configured_clock_speed = t->speed; /* reuse value for max speed */ + t->minimum_voltage = cpu_to_le16(0); /* Unknown */ + t->maximum_voltage = cpu_to_le16(0); /* Unknown */ + t->configured_voltage = cpu_to_le16(0); /* Unknown */ + + SMBIOS_BUILD_TABLE_POST; +} + +static void smbios_build_type_19_table(unsigned instance, + uint64_t start, uint64_t size) +{ + uint64_t end, start_kb, end_kb; + + SMBIOS_BUILD_TABLE_PRE(19, 0x1300 + instance, true); /* required */ + + end = start + size - 1; + assert(end > start); + start_kb = start / ONE_KB; + end_kb = end / ONE_KB; + if (start_kb < UINT32_MAX && end_kb < UINT32_MAX) { + t->starting_address = cpu_to_le32(start_kb); + t->ending_address = cpu_to_le32(end_kb); + t->extended_starting_address = + t->extended_ending_address = cpu_to_le64(0); + } else { + t->starting_address = t->ending_address = cpu_to_le32(UINT32_MAX); + t->extended_starting_address = cpu_to_le64(start); + t->extended_ending_address = cpu_to_le64(end); + } + t->memory_array_handle = cpu_to_le16(0x1000); /* Type 16 above */ + t->partition_width = 1; /* One device per row */ + + SMBIOS_BUILD_TABLE_POST; +} + +static void smbios_build_type_32_table(void) +{ + SMBIOS_BUILD_TABLE_PRE(32, 0x2000, true); /* required */ + + memset(t->reserved, 0, 6); + t->boot_status = 0; /* No errors detected */ + + SMBIOS_BUILD_TABLE_POST; +} + +static void smbios_build_type_127_table(void) +{ + SMBIOS_BUILD_TABLE_PRE(127, 0x7F00, true); /* required */ + SMBIOS_BUILD_TABLE_POST; +} + +void smbios_set_cpuid(uint32_t version, uint32_t features) +{ + smbios_cpuid_version = version; + smbios_cpuid_features = features; +} + +#define SMBIOS_SET_DEFAULT(field, value) \ + if (!field) { \ + field = value; \ + } + +void smbios_set_defaults(const char *manufacturer, const char *product, + const char *version, bool legacy_mode, + bool uuid_encoded) +{ + smbios_have_defaults = true; + smbios_legacy = legacy_mode; + smbios_uuid_encoded = uuid_encoded; + + /* drop unwanted version of command-line file blob(s) */ + if (smbios_legacy) { + g_free(smbios_tables); + /* in legacy mode, also complain if fields were given for types > 1 */ + if (find_next_bit(have_fields_bitmap, + SMBIOS_MAX_TYPE+1, 2) < SMBIOS_MAX_TYPE+1) { + error_report("can't process fields for smbios " + "types > 1 on machine versions < 2.1!"); + exit(1); + } + } else { + g_free(smbios_entries); + } + + SMBIOS_SET_DEFAULT(type1.manufacturer, manufacturer); + SMBIOS_SET_DEFAULT(type1.product, product); + SMBIOS_SET_DEFAULT(type1.version, version); + SMBIOS_SET_DEFAULT(type2.manufacturer, manufacturer); + SMBIOS_SET_DEFAULT(type2.product, product); + SMBIOS_SET_DEFAULT(type2.version, version); + SMBIOS_SET_DEFAULT(type3.manufacturer, manufacturer); + SMBIOS_SET_DEFAULT(type3.version, version); + SMBIOS_SET_DEFAULT(type4.sock_pfx, "CPU"); + SMBIOS_SET_DEFAULT(type4.manufacturer, manufacturer); + SMBIOS_SET_DEFAULT(type4.version, version); + SMBIOS_SET_DEFAULT(type17.loc_pfx, "DIMM"); + SMBIOS_SET_DEFAULT(type17.manufacturer, manufacturer); +} + +static void smbios_entry_point_setup(void) +{ + memcpy(ep.anchor_string, "_SM_", 4); + memcpy(ep.intermediate_anchor_string, "_DMI_", 5); + ep.length = sizeof(struct smbios_entry_point); + ep.entry_point_revision = 0; /* formatted_area reserved, per spec v2.1+ */ + memset(ep.formatted_area, 0, 5); + + /* compliant with smbios spec v2.8 */ + ep.smbios_major_version = 2; + ep.smbios_minor_version = 8; + ep.smbios_bcd_revision = 0x28; + + /* set during table construction, but BIOS may override: */ + ep.structure_table_length = cpu_to_le16(smbios_tables_len); + ep.max_structure_size = cpu_to_le16(smbios_table_max); + ep.number_of_structures = cpu_to_le16(smbios_table_cnt); + + /* BIOS must recalculate: */ + ep.checksum = 0; + ep.intermediate_checksum = 0; + ep.structure_table_address = cpu_to_le32(0); +} + +void smbios_get_tables(const struct smbios_phys_mem_area *mem_array, + const unsigned int mem_array_size, + uint8_t **tables, size_t *tables_len, + uint8_t **anchor, size_t *anchor_len) +{ + unsigned i, dimm_cnt; + + if (smbios_legacy) { + *tables = *anchor = NULL; + *tables_len = *anchor_len = 0; + return; + } + + if (!smbios_immutable) { + smbios_build_type_0_table(); + smbios_build_type_1_table(); + smbios_build_type_2_table(); + smbios_build_type_3_table(); + + smbios_smp_sockets = DIV_ROUND_UP(smp_cpus, smp_cores * smp_threads); + assert(smbios_smp_sockets >= 1); + + for (i = 0; i < smbios_smp_sockets; i++) { + smbios_build_type_4_table(i); + } + +#define MAX_DIMM_SZ (16ll * ONE_GB) +#define GET_DIMM_SZ ((i < dimm_cnt - 1) ? MAX_DIMM_SZ \ + : ((ram_size - 1) % MAX_DIMM_SZ) + 1) + + dimm_cnt = QEMU_ALIGN_UP(ram_size, MAX_DIMM_SZ) / MAX_DIMM_SZ; + + smbios_build_type_16_table(dimm_cnt); + + for (i = 0; i < dimm_cnt; i++) { + smbios_build_type_17_table(i, GET_DIMM_SZ); + } + + for (i = 0; i < mem_array_size; i++) { + smbios_build_type_19_table(i, mem_array[i].address, + mem_array[i].length); + } + + smbios_build_type_32_table(); + smbios_build_type_127_table(); + + smbios_validate_table(); + smbios_entry_point_setup(); + smbios_immutable = true; + } + + /* return tables blob and entry point (anchor), and their sizes */ + *tables = smbios_tables; + *tables_len = smbios_tables_len; + *anchor = (uint8_t *)&ep; + *anchor_len = sizeof(struct smbios_entry_point); +} + +static void save_opt(const char **dest, QemuOpts *opts, const char *name) +{ + const char *val = qemu_opt_get(opts, name); + + if (val) { + *dest = val; + } +} + +void smbios_entry_add(QemuOpts *opts) +{ + Error *local_err = NULL; + const char *val; + + assert(!smbios_immutable); + + val = qemu_opt_get(opts, "file"); + if (val) { + struct smbios_structure_header *header; + int size; + struct smbios_table *table; /* legacy mode only */ + + qemu_opts_validate(opts, qemu_smbios_file_opts, &local_err); + if (local_err) { + error_report_err(local_err); + exit(1); + } + + size = get_image_size(val); + if (size == -1 || size < sizeof(struct smbios_structure_header)) { + error_report("Cannot read SMBIOS file %s", val); + exit(1); + } + + /* + * NOTE: standard double '\0' terminator expected, per smbios spec. + * (except in legacy mode, where the second '\0' is implicit and + * will be inserted by the BIOS). + */ + smbios_tables = g_realloc(smbios_tables, smbios_tables_len + size); + header = (struct smbios_structure_header *)(smbios_tables + + smbios_tables_len); + + if (load_image(val, (uint8_t *)header) != size) { + error_report("Failed to load SMBIOS file %s", val); + exit(1); + } + + if (test_bit(header->type, have_fields_bitmap)) { + error_report("can't load type %d struct, fields already specified!", + header->type); + exit(1); + } + set_bit(header->type, have_binfile_bitmap); + + if (header->type == 4) { + smbios_type4_count++; + } + + smbios_tables_len += size; + if (size > smbios_table_max) { + smbios_table_max = size; + } + smbios_table_cnt++; + + /* add a copy of the newly loaded blob to legacy smbios_entries */ + /* NOTE: This code runs before smbios_set_defaults(), so we don't + * yet know which mode (legacy vs. aggregate-table) will be + * required. We therefore add the binary blob to both legacy + * (smbios_entries) and aggregate (smbios_tables) tables, and + * delete the one we don't need from smbios_set_defaults(), + * once we know which machine version has been requested. + */ + if (!smbios_entries) { + smbios_entries_len = sizeof(uint16_t); + smbios_entries = g_malloc0(smbios_entries_len); + } + smbios_entries = g_realloc(smbios_entries, smbios_entries_len + + size + sizeof(*table)); + table = (struct smbios_table *)(smbios_entries + smbios_entries_len); + table->header.type = SMBIOS_TABLE_ENTRY; + table->header.length = cpu_to_le16(sizeof(*table) + size); + memcpy(table->data, header, size); + smbios_entries_len += sizeof(*table) + size; + (*(uint16_t *)smbios_entries) = + cpu_to_le16(le16_to_cpu(*(uint16_t *)smbios_entries) + 1); + /* end: add a copy of the newly loaded blob to legacy smbios_entries */ + + return; + } + + val = qemu_opt_get(opts, "type"); + if (val) { + unsigned long type = strtoul(val, NULL, 0); + + if (type > SMBIOS_MAX_TYPE) { + error_report("out of range!"); + exit(1); + } + + if (test_bit(type, have_binfile_bitmap)) { + error_report("can't add fields, binary file already loaded!"); + exit(1); + } + set_bit(type, have_fields_bitmap); + + switch (type) { + case 0: + qemu_opts_validate(opts, qemu_smbios_type0_opts, &local_err); + if (local_err) { + error_report_err(local_err); + exit(1); + } + save_opt(&type0.vendor, opts, "vendor"); + save_opt(&type0.version, opts, "version"); + save_opt(&type0.date, opts, "date"); + type0.uefi = qemu_opt_get_bool(opts, "uefi", false); + + val = qemu_opt_get(opts, "release"); + if (val) { + if (sscanf(val, "%hhu.%hhu", &type0.major, &type0.minor) != 2) { + error_report("Invalid release"); + exit(1); + } + type0.have_major_minor = true; + } + return; + case 1: + qemu_opts_validate(opts, qemu_smbios_type1_opts, &local_err); + if (local_err) { + error_report_err(local_err); + exit(1); + } + save_opt(&type1.manufacturer, opts, "manufacturer"); + save_opt(&type1.product, opts, "product"); + save_opt(&type1.version, opts, "version"); + save_opt(&type1.serial, opts, "serial"); + save_opt(&type1.sku, opts, "sku"); + save_opt(&type1.family, opts, "family"); + + val = qemu_opt_get(opts, "uuid"); + if (val) { + if (qemu_uuid_parse(val, qemu_uuid) != 0) { + error_report("Invalid UUID"); + exit(1); + } + qemu_uuid_set = true; + } + return; + case 2: + qemu_opts_validate(opts, qemu_smbios_type2_opts, &local_err); + if (local_err) { + error_report_err(local_err); + exit(1); + } + save_opt(&type2.manufacturer, opts, "manufacturer"); + save_opt(&type2.product, opts, "product"); + save_opt(&type2.version, opts, "version"); + save_opt(&type2.serial, opts, "serial"); + save_opt(&type2.asset, opts, "asset"); + save_opt(&type2.location, opts, "location"); + return; + case 3: + qemu_opts_validate(opts, qemu_smbios_type3_opts, &local_err); + if (local_err) { + error_report_err(local_err); + exit(1); + } + save_opt(&type3.manufacturer, opts, "manufacturer"); + save_opt(&type3.version, opts, "version"); + save_opt(&type3.serial, opts, "serial"); + save_opt(&type3.asset, opts, "asset"); + save_opt(&type3.sku, opts, "sku"); + return; + case 4: + qemu_opts_validate(opts, qemu_smbios_type4_opts, &local_err); + if (local_err) { + error_report_err(local_err); + exit(1); + } + save_opt(&type4.sock_pfx, opts, "sock_pfx"); + save_opt(&type4.manufacturer, opts, "manufacturer"); + save_opt(&type4.version, opts, "version"); + save_opt(&type4.serial, opts, "serial"); + save_opt(&type4.asset, opts, "asset"); + save_opt(&type4.part, opts, "part"); + return; + case 17: + qemu_opts_validate(opts, qemu_smbios_type17_opts, &local_err); + if (local_err) { + error_report_err(local_err); + exit(1); + } + save_opt(&type17.loc_pfx, opts, "loc_pfx"); + save_opt(&type17.bank, opts, "bank"); + save_opt(&type17.manufacturer, opts, "manufacturer"); + save_opt(&type17.serial, opts, "serial"); + save_opt(&type17.asset, opts, "asset"); + save_opt(&type17.part, opts, "part"); + type17.speed = qemu_opt_get_number(opts, "speed", 0); + return; + default: + error_report("Don't know how to build fields for SMBIOS type %ld", + type); + exit(1); + } + } + + error_report("Must specify type= or file="); + exit(1); +} diff --git a/include/hw/i386/smbios.h b/include/hw/i386/smbios.h deleted file mode 100644 index 4269aab..0000000 --- a/include/hw/i386/smbios.h +++ /dev/null @@ -1,235 +0,0 @@ -#ifndef QEMU_SMBIOS_H -#define QEMU_SMBIOS_H -/* - * SMBIOS Support - * - * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. - * - * Authors: - * Alex Williamson - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -#include "qemu/option.h" - -#define SMBIOS_MAX_TYPE 127 - -/* memory area description, used by type 19 table */ -struct smbios_phys_mem_area { - uint64_t address; - uint64_t length; -}; - -void smbios_entry_add(QemuOpts *opts); -void smbios_set_cpuid(uint32_t version, uint32_t features); -void smbios_set_defaults(const char *manufacturer, const char *product, - const char *version, bool legacy_mode, - bool uuid_encoded); -uint8_t *smbios_get_table_legacy(size_t *length); -void smbios_get_tables(const struct smbios_phys_mem_area *mem_array, - const unsigned int mem_array_size, - uint8_t **tables, size_t *tables_len, - uint8_t **anchor, size_t *anchor_len); - -/* - * SMBIOS spec defined tables - */ - -/* SMBIOS entry point (anchor). - * BIOS must place this at a 16-bit-aligned address between 0xf0000 and 0xfffff. - */ -struct smbios_entry_point { - uint8_t anchor_string[4]; - uint8_t checksum; - uint8_t length; - uint8_t smbios_major_version; - uint8_t smbios_minor_version; - uint16_t max_structure_size; - uint8_t entry_point_revision; - uint8_t formatted_area[5]; - uint8_t intermediate_anchor_string[5]; - uint8_t intermediate_checksum; - uint16_t structure_table_length; - uint32_t structure_table_address; - uint16_t number_of_structures; - uint8_t smbios_bcd_revision; -} QEMU_PACKED; - -/* This goes at the beginning of every SMBIOS structure. */ -struct smbios_structure_header { - uint8_t type; - uint8_t length; - uint16_t handle; -} QEMU_PACKED; - -/* SMBIOS type 0 - BIOS Information */ -struct smbios_type_0 { - struct smbios_structure_header header; - uint8_t vendor_str; - uint8_t bios_version_str; - uint16_t bios_starting_address_segment; - uint8_t bios_release_date_str; - uint8_t bios_rom_size; - uint64_t bios_characteristics; - uint8_t bios_characteristics_extension_bytes[2]; - uint8_t system_bios_major_release; - uint8_t system_bios_minor_release; - uint8_t embedded_controller_major_release; - uint8_t embedded_controller_minor_release; -} QEMU_PACKED; - -/* UUID encoding. The time_* fields are little-endian, as specified by SMBIOS - * version 2.6. - */ -struct smbios_uuid { - uint32_t time_low; - uint16_t time_mid; - uint16_t time_hi_and_version; - uint8_t clock_seq_hi_and_reserved; - uint8_t clock_seq_low; - uint8_t node[6]; -} QEMU_PACKED; - -/* SMBIOS type 1 - System Information */ -struct smbios_type_1 { - struct smbios_structure_header header; - uint8_t manufacturer_str; - uint8_t product_name_str; - uint8_t version_str; - uint8_t serial_number_str; - struct smbios_uuid uuid; - uint8_t wake_up_type; - uint8_t sku_number_str; - uint8_t family_str; -} QEMU_PACKED; - -/* SMBIOS type 2 - Base Board */ -struct smbios_type_2 { - struct smbios_structure_header header; - uint8_t manufacturer_str; - uint8_t product_str; - uint8_t version_str; - uint8_t serial_number_str; - uint8_t asset_tag_number_str; - uint8_t feature_flags; - uint8_t location_str; - uint16_t chassis_handle; - uint8_t board_type; - uint8_t contained_element_count; - /* contained elements follow */ -} QEMU_PACKED; - -/* SMBIOS type 3 - System Enclosure (v2.7) */ -struct smbios_type_3 { - struct smbios_structure_header header; - uint8_t manufacturer_str; - uint8_t type; - uint8_t version_str; - uint8_t serial_number_str; - uint8_t asset_tag_number_str; - uint8_t boot_up_state; - uint8_t power_supply_state; - uint8_t thermal_state; - uint8_t security_status; - uint32_t oem_defined; - uint8_t height; - uint8_t number_of_power_cords; - uint8_t contained_element_count; - uint8_t sku_number_str; - /* contained elements follow */ -} QEMU_PACKED; - -/* SMBIOS type 4 - Processor Information (v2.6) */ -struct smbios_type_4 { - struct smbios_structure_header header; - uint8_t socket_designation_str; - uint8_t processor_type; - uint8_t processor_family; - uint8_t processor_manufacturer_str; - uint32_t processor_id[2]; - uint8_t processor_version_str; - uint8_t voltage; - uint16_t external_clock; - uint16_t max_speed; - uint16_t current_speed; - uint8_t status; - uint8_t processor_upgrade; - uint16_t l1_cache_handle; - uint16_t l2_cache_handle; - uint16_t l3_cache_handle; - uint8_t serial_number_str; - uint8_t asset_tag_number_str; - uint8_t part_number_str; - uint8_t core_count; - uint8_t core_enabled; - uint8_t thread_count; - uint16_t processor_characteristics; - uint16_t processor_family2; -} QEMU_PACKED; - -/* SMBIOS type 16 - Physical Memory Array (v2.7) */ -struct smbios_type_16 { - struct smbios_structure_header header; - uint8_t location; - uint8_t use; - uint8_t error_correction; - uint32_t maximum_capacity; - uint16_t memory_error_information_handle; - uint16_t number_of_memory_devices; - uint64_t extended_maximum_capacity; -} QEMU_PACKED; - -/* SMBIOS type 17 - Memory Device (v2.8) */ -struct smbios_type_17 { - struct smbios_structure_header header; - uint16_t physical_memory_array_handle; - uint16_t memory_error_information_handle; - uint16_t total_width; - uint16_t data_width; - uint16_t size; - uint8_t form_factor; - uint8_t device_set; - uint8_t device_locator_str; - uint8_t bank_locator_str; - uint8_t memory_type; - uint16_t type_detail; - uint16_t speed; - uint8_t manufacturer_str; - uint8_t serial_number_str; - uint8_t asset_tag_number_str; - uint8_t part_number_str; - uint8_t attributes; - uint32_t extended_size; - uint16_t configured_clock_speed; - uint16_t minimum_voltage; - uint16_t maximum_voltage; - uint16_t configured_voltage; -} QEMU_PACKED; - -/* SMBIOS type 19 - Memory Array Mapped Address (v2.7) */ -struct smbios_type_19 { - struct smbios_structure_header header; - uint32_t starting_address; - uint32_t ending_address; - uint16_t memory_array_handle; - uint8_t partition_width; - uint64_t extended_starting_address; - uint64_t extended_ending_address; -} QEMU_PACKED; - -/* SMBIOS type 32 - System Boot Information */ -struct smbios_type_32 { - struct smbios_structure_header header; - uint8_t reserved[6]; - uint8_t boot_status; -} QEMU_PACKED; - -/* SMBIOS type 127 -- End-of-table */ -struct smbios_type_127 { - struct smbios_structure_header header; -} QEMU_PACKED; - -#endif /*QEMU_SMBIOS_H */ diff --git a/include/hw/smbios/smbios.h b/include/hw/smbios/smbios.h new file mode 100644 index 0000000..4269aab --- /dev/null +++ b/include/hw/smbios/smbios.h @@ -0,0 +1,235 @@ +#ifndef QEMU_SMBIOS_H +#define QEMU_SMBIOS_H +/* + * SMBIOS Support + * + * Copyright (C) 2009 Hewlett-Packard Development Company, L.P. + * + * Authors: + * Alex Williamson + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "qemu/option.h" + +#define SMBIOS_MAX_TYPE 127 + +/* memory area description, used by type 19 table */ +struct smbios_phys_mem_area { + uint64_t address; + uint64_t length; +}; + +void smbios_entry_add(QemuOpts *opts); +void smbios_set_cpuid(uint32_t version, uint32_t features); +void smbios_set_defaults(const char *manufacturer, const char *product, + const char *version, bool legacy_mode, + bool uuid_encoded); +uint8_t *smbios_get_table_legacy(size_t *length); +void smbios_get_tables(const struct smbios_phys_mem_area *mem_array, + const unsigned int mem_array_size, + uint8_t **tables, size_t *tables_len, + uint8_t **anchor, size_t *anchor_len); + +/* + * SMBIOS spec defined tables + */ + +/* SMBIOS entry point (anchor). + * BIOS must place this at a 16-bit-aligned address between 0xf0000 and 0xfffff. + */ +struct smbios_entry_point { + uint8_t anchor_string[4]; + uint8_t checksum; + uint8_t length; + uint8_t smbios_major_version; + uint8_t smbios_minor_version; + uint16_t max_structure_size; + uint8_t entry_point_revision; + uint8_t formatted_area[5]; + uint8_t intermediate_anchor_string[5]; + uint8_t intermediate_checksum; + uint16_t structure_table_length; + uint32_t structure_table_address; + uint16_t number_of_structures; + uint8_t smbios_bcd_revision; +} QEMU_PACKED; + +/* This goes at the beginning of every SMBIOS structure. */ +struct smbios_structure_header { + uint8_t type; + uint8_t length; + uint16_t handle; +} QEMU_PACKED; + +/* SMBIOS type 0 - BIOS Information */ +struct smbios_type_0 { + struct smbios_structure_header header; + uint8_t vendor_str; + uint8_t bios_version_str; + uint16_t bios_starting_address_segment; + uint8_t bios_release_date_str; + uint8_t bios_rom_size; + uint64_t bios_characteristics; + uint8_t bios_characteristics_extension_bytes[2]; + uint8_t system_bios_major_release; + uint8_t system_bios_minor_release; + uint8_t embedded_controller_major_release; + uint8_t embedded_controller_minor_release; +} QEMU_PACKED; + +/* UUID encoding. The time_* fields are little-endian, as specified by SMBIOS + * version 2.6. + */ +struct smbios_uuid { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_hi_and_reserved; + uint8_t clock_seq_low; + uint8_t node[6]; +} QEMU_PACKED; + +/* SMBIOS type 1 - System Information */ +struct smbios_type_1 { + struct smbios_structure_header header; + uint8_t manufacturer_str; + uint8_t product_name_str; + uint8_t version_str; + uint8_t serial_number_str; + struct smbios_uuid uuid; + uint8_t wake_up_type; + uint8_t sku_number_str; + uint8_t family_str; +} QEMU_PACKED; + +/* SMBIOS type 2 - Base Board */ +struct smbios_type_2 { + struct smbios_structure_header header; + uint8_t manufacturer_str; + uint8_t product_str; + uint8_t version_str; + uint8_t serial_number_str; + uint8_t asset_tag_number_str; + uint8_t feature_flags; + uint8_t location_str; + uint16_t chassis_handle; + uint8_t board_type; + uint8_t contained_element_count; + /* contained elements follow */ +} QEMU_PACKED; + +/* SMBIOS type 3 - System Enclosure (v2.7) */ +struct smbios_type_3 { + struct smbios_structure_header header; + uint8_t manufacturer_str; + uint8_t type; + uint8_t version_str; + uint8_t serial_number_str; + uint8_t asset_tag_number_str; + uint8_t boot_up_state; + uint8_t power_supply_state; + uint8_t thermal_state; + uint8_t security_status; + uint32_t oem_defined; + uint8_t height; + uint8_t number_of_power_cords; + uint8_t contained_element_count; + uint8_t sku_number_str; + /* contained elements follow */ +} QEMU_PACKED; + +/* SMBIOS type 4 - Processor Information (v2.6) */ +struct smbios_type_4 { + struct smbios_structure_header header; + uint8_t socket_designation_str; + uint8_t processor_type; + uint8_t processor_family; + uint8_t processor_manufacturer_str; + uint32_t processor_id[2]; + uint8_t processor_version_str; + uint8_t voltage; + uint16_t external_clock; + uint16_t max_speed; + uint16_t current_speed; + uint8_t status; + uint8_t processor_upgrade; + uint16_t l1_cache_handle; + uint16_t l2_cache_handle; + uint16_t l3_cache_handle; + uint8_t serial_number_str; + uint8_t asset_tag_number_str; + uint8_t part_number_str; + uint8_t core_count; + uint8_t core_enabled; + uint8_t thread_count; + uint16_t processor_characteristics; + uint16_t processor_family2; +} QEMU_PACKED; + +/* SMBIOS type 16 - Physical Memory Array (v2.7) */ +struct smbios_type_16 { + struct smbios_structure_header header; + uint8_t location; + uint8_t use; + uint8_t error_correction; + uint32_t maximum_capacity; + uint16_t memory_error_information_handle; + uint16_t number_of_memory_devices; + uint64_t extended_maximum_capacity; +} QEMU_PACKED; + +/* SMBIOS type 17 - Memory Device (v2.8) */ +struct smbios_type_17 { + struct smbios_structure_header header; + uint16_t physical_memory_array_handle; + uint16_t memory_error_information_handle; + uint16_t total_width; + uint16_t data_width; + uint16_t size; + uint8_t form_factor; + uint8_t device_set; + uint8_t device_locator_str; + uint8_t bank_locator_str; + uint8_t memory_type; + uint16_t type_detail; + uint16_t speed; + uint8_t manufacturer_str; + uint8_t serial_number_str; + uint8_t asset_tag_number_str; + uint8_t part_number_str; + uint8_t attributes; + uint32_t extended_size; + uint16_t configured_clock_speed; + uint16_t minimum_voltage; + uint16_t maximum_voltage; + uint16_t configured_voltage; +} QEMU_PACKED; + +/* SMBIOS type 19 - Memory Array Mapped Address (v2.7) */ +struct smbios_type_19 { + struct smbios_structure_header header; + uint32_t starting_address; + uint32_t ending_address; + uint16_t memory_array_handle; + uint8_t partition_width; + uint64_t extended_starting_address; + uint64_t extended_ending_address; +} QEMU_PACKED; + +/* SMBIOS type 32 - System Boot Information */ +struct smbios_type_32 { + struct smbios_structure_header header; + uint8_t reserved[6]; + uint8_t boot_status; +} QEMU_PACKED; + +/* SMBIOS type 127 -- End-of-table */ +struct smbios_type_127 { + struct smbios_structure_header header; +} QEMU_PACKED; + +#endif /*QEMU_SMBIOS_H */ diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c index 0de1742..613867a 100644 --- a/tests/bios-tables-test.c +++ b/tests/bios-tables-test.c @@ -18,7 +18,7 @@ #include "libqtest.h" #include "qemu/compiler.h" #include "hw/acpi/acpi-defs.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "qemu/bitmap.h" #define MACHINE_PC "pc" diff --git a/vl.c b/vl.c index 0adbbd6..584ca88 100644 --- a/vl.c +++ b/vl.c @@ -68,7 +68,7 @@ int main(int argc, char **argv) #include "hw/isa/isa.h" #include "hw/bt.h" #include "sysemu/watchdog.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "hw/xen/xen.h" #include "hw/qdev.h" #include "hw/loader.h" -- cgit v1.1 From d31e5ae7f2c16de2caf752b7f7f903569fea894d Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 12 Aug 2015 12:17:36 +0300 Subject: MAINTAINERS: list smbios maintainers Now that smbios has its own directory, list its maintainers. Same people as ACPI so just reuse that entry. Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 978b717..a059d5d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -645,13 +645,15 @@ S: Supported F: include/hw/pci/* F: hw/pci/* -ACPI +ACPI/SMBIOS M: Michael S. Tsirkin M: Igor Mammedov S: Supported F: include/hw/acpi/* +F: include/hw/smbios/* F: hw/mem/* F: hw/acpi/* +F: hw/smbios/* F: hw/i386/acpi-build.[hc] F: hw/i386/*dsl F: hw/arm/virt-acpi-build.c -- cgit v1.1