On 28/01/15 09:17, Jan Beulich wrote: > While presumably of primary use to ARM64 (once the code gets > generalized), we should still support this more modern variant, > allowing for the actual DMI data to reside in memory above 4Gb. > > While based on draft version 3.0.0d, it is assumed that the final > version of the specification will not render this implementation > invalid (not the least because Linux 3.19 already makes the same > assumption). > > Signed-off-by: Jan Beulich <jbeul...@suse.com>
Acked-by: Andrew Cooper <andrew.coop...@citrix.com> I presume, this being a draft, there is still not any hardware about using SMBIOSv3 yet? ~Andrew > > --- a/xen/arch/x86/dmi_scan.c > +++ b/xen/arch/x86/dmi_scan.c > @@ -38,6 +38,18 @@ struct __packed smbios_eps { > struct dmi_eps dmi; > }; > > +struct __packed smbios3_eps { > + char anchor[5]; /* "_SM3_" */ > + u8 checksum; > + u8 length; > + u8 major, minor; > + u8 docrev; > + u8 revision; > + u8 _rsrvd_; > + u32 max_size; > + u64 address; > +}; > + > struct dmi_header > { > u8 type; > @@ -45,6 +57,53 @@ struct dmi_header > u16 handle; > }; > > +enum dmi_entry_type { > + DMI_ENTRY_BIOS = 0, > + DMI_ENTRY_SYSTEM, > + DMI_ENTRY_BASEBOARD, > + DMI_ENTRY_CHASSIS, > + DMI_ENTRY_PROCESSOR, > + DMI_ENTRY_MEM_CONTROLLER, > + DMI_ENTRY_MEM_MODULE, > + DMI_ENTRY_CACHE, > + DMI_ENTRY_PORT_CONNECTOR, > + DMI_ENTRY_SYSTEM_SLOT, > + DMI_ENTRY_ONBOARD_DEVICE, > + DMI_ENTRY_OEMSTRINGS, > + DMI_ENTRY_SYSCONF, > + DMI_ENTRY_BIOS_LANG, > + DMI_ENTRY_GROUP_ASSOC, > + DMI_ENTRY_SYSTEM_EVENT_LOG, > + DMI_ENTRY_PHYS_MEM_ARRAY, > + DMI_ENTRY_MEM_DEVICE, > + DMI_ENTRY_32_MEM_ERROR, > + DMI_ENTRY_MEM_ARRAY_MAPPED_ADDR, > + DMI_ENTRY_MEM_DEV_MAPPED_ADDR, > + DMI_ENTRY_BUILTIN_POINTING_DEV, > + DMI_ENTRY_PORTABLE_BATTERY, > + DMI_ENTRY_SYSTEM_RESET, > + DMI_ENTRY_HW_SECURITY, > + DMI_ENTRY_SYSTEM_POWER_CONTROLS, > + DMI_ENTRY_VOLTAGE_PROBE, > + DMI_ENTRY_COOLING_DEV, > + DMI_ENTRY_TEMP_PROBE, > + DMI_ENTRY_ELECTRICAL_CURRENT_PROBE, > + DMI_ENTRY_OOB_REMOTE_ACCESS, > + DMI_ENTRY_BIS_ENTRY, > + DMI_ENTRY_SYSTEM_BOOT, > + DMI_ENTRY_MGMT_DEV, > + DMI_ENTRY_MGMT_DEV_COMPONENT, > + DMI_ENTRY_MGMT_DEV_THRES, > + DMI_ENTRY_MEM_CHANNEL, > + DMI_ENTRY_IPMI_DEV, > + DMI_ENTRY_SYS_POWER_SUPPLY, > + DMI_ENTRY_ADDITIONAL, > + DMI_ENTRY_ONBOARD_DEV_EXT, > + DMI_ENTRY_MGMT_CONTROLLER_HOST, > + DMI_ENTRY_INACTIVE = 126, > + DMI_ENTRY_END_OF_TABLE = 127, > +}; > + > #undef DMI_DEBUG > > #ifdef DMI_DEBUG > @@ -74,7 +133,8 @@ static char * __init dmi_string(struct d > * pointing to completely the wrong place for example > */ > > -static int __init dmi_table(u32 base, int len, int num, void > (*decode)(struct dmi_header *)) > +static int __init dmi_table(paddr_t base, u32 len, int num, > + void (*decode)(struct dmi_header *)) > { > u8 *buf; > struct dmi_header *dm; > @@ -92,7 +152,7 @@ static int __init dmi_table(u32 base, in > * OR we run off the end of the table (also happens) > */ > > - while(i<num && data-buf+sizeof(struct dmi_header)<=len) > + while((num < 0 || i < num) && data-buf+sizeof(struct dmi_header)<=len) > { > dm=(struct dmi_header *)data; > /* > @@ -105,6 +165,8 @@ static int __init dmi_table(u32 base, in > data++; > if(data-buf<len-1) > decode(dm); > + if (dm->type == DMI_ENTRY_END_OF_TABLE) > + break; > data+=2; > i++; > } > @@ -127,16 +189,28 @@ static inline bool_t __init dmi_checksum > > static u32 __initdata efi_dmi_address; > static u32 __initdata efi_dmi_size; > +static u64 __initdata efi_smbios3_address; > +static u32 __initdata efi_smbios3_size; > > /* > * Important: This function gets called while still in EFI > * (pseudo-)physical mode. > */ > -void __init dmi_efi_get_table(void *smbios) > +void __init dmi_efi_get_table(const void *smbios, const void *smbios3) > { > - struct smbios_eps *eps = smbios; > + const struct smbios_eps *eps = smbios; > + const struct smbios3_eps *eps3 = smbios3; > + > + if (eps3 && memcmp(eps3->anchor, "_SM3_", 5) && > + eps3->length >= sizeof(*eps3) && > + dmi_checksum(eps3, eps3->length)) { > + efi_smbios3_address = eps3->address; > + efi_smbios3_size = eps3->max_size; > + return; > + } > > - if (memcmp(eps->anchor, "_SM_", 4) && > + if (eps && memcmp(eps->anchor, "_SM_", 4) && > + eps->length >= sizeof(*eps) && > dmi_checksum(eps, eps->length) && > memcmp(eps->dmi.anchor, "_DMI_", 5) == 0 && > dmi_checksum(&eps->dmi, sizeof(eps->dmi))) { > @@ -145,99 +219,190 @@ void __init dmi_efi_get_table(void *smbi > } > } > > -int __init dmi_get_table(u32 *base, u32 *len) > +const char *__init dmi_get_table(paddr_t *base, u32 *len) > { > - struct dmi_eps eps; > - char __iomem *p, *q; > + static unsigned int __initdata instance; > > if (efi_enabled) { > - if (!efi_dmi_size) > - return -1; > - *base = efi_dmi_address; > - *len = efi_dmi_size; > - return 0; > - } > - > - p = maddr_to_virt(0xF0000); > - for (q = p; q < p + 0x10000; q += 16) { > - memcpy_fromio(&eps, q, 15); > - if (memcmp(eps.anchor, "_DMI_", 5) == 0 && > - dmi_checksum(&eps, sizeof(eps))) { > - *base = eps.address; > - *len = eps.size; > - return 0; > + if (efi_smbios3_size && !(instance & 1)) { > + *base = efi_smbios3_address; > + *len = efi_smbios3_size; > + instance |= 1; > + return "SMBIOSv3"; > + } > + if (efi_dmi_size && !(instance & 2)) { > + *base = efi_dmi_address; > + *len = efi_dmi_size; > + instance |= 2; > + return "DMI"; > + } > + } else { > + char __iomem *p = maddr_to_virt(0xF0000), *q; > + union { > + struct dmi_eps dmi; > + struct smbios3_eps smbios3; > + } eps; > + > + for (q = p; q <= p + 0x10000 - sizeof(eps.dmi); q += 16) { > + memcpy_fromio(&eps, q, sizeof(eps.dmi)); > + if (!(instance & 1) && > + memcmp(eps.dmi.anchor, "_DMI_", 5) == 0 && > + dmi_checksum(&eps.dmi, sizeof(eps.dmi))) { > + *base = eps.dmi.address; > + *len = eps.dmi.size; > + instance |= 1; > + return "DMI"; > + } > + > + BUILD_BUG_ON(sizeof(eps.smbios3) <= sizeof(eps.dmi)); > + if ((instance & 2) || > + q > p + 0x10000 - sizeof(eps.smbios3)) > + continue; > + memcpy_fromio(&eps.dmi + 1, q + sizeof(eps.dmi), > + sizeof(eps.smbios3) - sizeof(eps.dmi)); > + if (!memcmp(eps.smbios3.anchor, "_SM3_", 5) && > + eps.smbios3.length >= sizeof(eps.smbios3) && > + q <= p + 0x10000 - eps.smbios3.length && > + dmi_checksum(q, eps.smbios3.length)) { > + *base = eps.smbios3.address; > + *len = eps.smbios3.max_size; > + instance |= 2; > + return "SMBIOSv3"; > + } > } > } > - return -1; > + return NULL; > } > > +typedef union { > + const struct smbios_eps __iomem *legacy; > + const struct smbios3_eps __iomem *v3; > +} smbios_eps_u __attribute__((transparent_union)); > + > static int __init _dmi_iterate(const struct dmi_eps *dmi, > - const struct smbios_eps __iomem *smbios, > + const smbios_eps_u smbios, > void (*decode)(struct dmi_header *)) > { > - u16 num = dmi->num_structures; > - u16 len = dmi->size; > - u32 base = dmi->address; > + int num; > + u32 len; > + paddr_t base; > + > + if (!dmi) { > + num = -1; > + len = smbios.v3->max_size; > + base = smbios.v3->address; > + printk(KERN_INFO "SMBIOS %d.%d present.\n", > + smbios.v3->major, smbios.v3->minor); > + dmi_printk((KERN_INFO "SMBIOS v3 table at 0x%"PRIpaddr".\n", > base)); > + } else { > + num = dmi->num_structures; > + len = dmi->size; > + base = dmi->address; > > - /* > - * DMI version 0.0 means that the real version is taken from > - * the SMBIOS version, which we may not know at this point. > - */ > - if (dmi->revision) > - printk(KERN_INFO "DMI %d.%d present.\n", > - dmi->revision >> 4, dmi->revision & 0x0f); > - else if (!smbios) > - printk(KERN_INFO "DMI present.\n"); > - dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n", > - num, len)); > - dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", base)); > + /* > + * DMI version 0.0 means that the real version is taken from > + * the SMBIOS version, which we may not know at this point. > + */ > + if (dmi->revision) > + printk(KERN_INFO "DMI %d.%d present.\n", > + dmi->revision >> 4, dmi->revision & 0x0f); > + else if (!smbios.legacy) > + printk(KERN_INFO "DMI present.\n"); > + dmi_printk((KERN_INFO "%d structures occupying %u bytes.\n", > + num, len)); > + dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", (u32)base)); > + } > return dmi_table(base, len, num, decode); > } > > static int __init dmi_iterate(void (*decode)(struct dmi_header *)) > { > - struct dmi_eps eps; > + struct dmi_eps dmi; > + struct smbios3_eps smbios3; > char __iomem *p, *q; > > + dmi.size = 0; > + smbios3.length = 0; > + > p = maddr_to_virt(0xF0000); > for (q = p; q < p + 0x10000; q += 16) { > - memcpy_fromio(&eps, q, sizeof(eps)); > - if (memcmp(eps.anchor, "_DMI_", 5) == 0 && > - dmi_checksum(&eps, sizeof(eps))) > - return _dmi_iterate(&eps, NULL, decode); > + if (!dmi.size) { > + memcpy_fromio(&dmi, q, sizeof(dmi)); > + if (memcmp(dmi.anchor, "_DMI_", 5) || > + !dmi_checksum(&dmi, sizeof(dmi))) > + dmi.size = 0; > + } > + if (!smbios3.length && > + q <= p + 0x10000 - sizeof(smbios3)) { > + memcpy_fromio(&smbios3, q, sizeof(smbios3)); > + if (memcmp(smbios3.anchor, "_SM3_", 5) || > + smbios3.length < sizeof(smbios3) || > + q < p + 0x10000 - smbios3.length || > + !dmi_checksum(q, smbios3.length)) > + smbios3.length = 0; > + } > } > + > + if (smbios3.length) > + return _dmi_iterate(NULL, &smbios3, decode); > + if (dmi.size) > + return _dmi_iterate(&dmi, NULL, decode); > return -1; > } > > static int __init dmi_efi_iterate(void (*decode)(struct dmi_header *)) > { > - struct smbios_eps eps; > - const struct smbios_eps __iomem *p; > int ret = -1; > > - if (efi.smbios == EFI_INVALID_TABLE_ADDR) > - return -1; > + while (efi.smbios3 != EFI_INVALID_TABLE_ADDR) { > + struct smbios3_eps eps; > + const struct smbios3_eps __iomem *p; > > - p = bt_ioremap(efi.smbios, sizeof(eps)); > - if (!p) > - return -1; > - memcpy_fromio(&eps, p, sizeof(eps)); > - bt_iounmap(p, sizeof(eps)); > + p = bt_ioremap(efi.smbios3, sizeof(eps)); > + if (!p) > + break; > + memcpy_fromio(&eps, p, sizeof(eps)); > + bt_iounmap(p, sizeof(eps)); > > - if (memcmp(eps.anchor, "_SM_", 4)) > - return -1; > + if (memcmp(eps.anchor, "_SM3_", 5) || > + eps.length < sizeof(eps)) > + break; > > - p = bt_ioremap(efi.smbios, eps.length); > - if (!p) > - return -1; > - if (dmi_checksum(p, eps.length) && > - memcmp(eps.dmi.anchor, "_DMI_", 5) == 0 && > - dmi_checksum(&eps.dmi, sizeof(eps.dmi))) { > - printk(KERN_INFO "SMBIOS %d.%d present.\n", > - eps.major, eps.minor); > - ret = _dmi_iterate(&eps.dmi, p, decode); > + p = bt_ioremap(efi.smbios3, eps.length); > + if (!p) > + break; > + if (dmi_checksum(p, eps.length)) > + ret = _dmi_iterate(NULL, p, decode); > + bt_iounmap(p, eps.length); > + break; > + } > + > + if (ret != 0 && efi.smbios != EFI_INVALID_TABLE_ADDR) { > + struct smbios_eps eps; > + const struct smbios_eps __iomem *p; > + > + p = bt_ioremap(efi.smbios, sizeof(eps)); > + if (!p) > + return -1; > + memcpy_fromio(&eps, p, sizeof(eps)); > + bt_iounmap(p, sizeof(eps)); > + > + if (memcmp(eps.anchor, "_SM_", 4) || > + eps.length < sizeof(eps)) > + return -1; > + > + p = bt_ioremap(efi.smbios, eps.length); > + if (!p) > + return -1; > + if (dmi_checksum(p, eps.length) && > + memcmp(eps.dmi.anchor, "_DMI_", 5) == 0 && > + dmi_checksum(&eps.dmi, sizeof(eps.dmi))) { > + printk(KERN_INFO "SMBIOS %d.%d present.\n", > + eps.major, eps.minor); > + ret = _dmi_iterate(&eps.dmi, p, decode); > + } > + bt_iounmap(p, eps.length); > } > - bt_iounmap(p, eps.length); > > return ret; > } > @@ -476,7 +641,7 @@ static void __init dmi_decode(struct dmi > > switch(dm->type) > { > - case 0: > + case DMI_ENTRY_BIOS: > dmi_printk(("BIOS Vendor: %s\n", > dmi_string(dm, data[4]))); > dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); > @@ -487,7 +652,7 @@ static void __init dmi_decode(struct dmi > dmi_string(dm, data[8]))); > dmi_save_ident(dm, DMI_BIOS_DATE, 8); > break; > - case 1: > + case DMI_ENTRY_SYSTEM: > dmi_printk(("System Vendor: %s\n", > dmi_string(dm, data[4]))); > dmi_save_ident(dm, DMI_SYS_VENDOR, 4); > @@ -500,7 +665,7 @@ static void __init dmi_decode(struct dmi > dmi_printk(("Serial Number: %s\n", > dmi_string(dm, data[7]))); > break; > - case 2: > + case DMI_ENTRY_BASEBOARD: > dmi_printk(("Board Vendor: %s\n", > dmi_string(dm, data[4]))); > dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); > --- a/xen/arch/x86/e820.c > +++ b/xen/arch/x86/e820.c > @@ -504,11 +504,19 @@ static uint64_t __init mtrr_top_of_ram(v > > static void __init reserve_dmi_region(void) > { > - u32 base, len; > - if ( (dmi_get_table(&base, &len) == 0) && ((base + len) > base) && > - reserve_e820_ram(&e820, base, base + len) ) > - printk("WARNING: DMI table located in E820 RAM %08x-%08x. Fixed.\n", > - base, base+len); > + for ( ; ; ) > + { > + paddr_t base; > + u32 len; > + const char *what = dmi_get_table(&base, &len); > + > + if ( !what ) > + break; > + if ( ((base + len) > base) && > + reserve_e820_ram(&e820, base, base + len) ) > + printk("WARNING: %s table located in E820 RAM > %"PRIpaddr"-%"PRIpaddr". Fixed.\n", > + what, base, base + len); > + } > } > > static void __init machine_specific_memory_setup( > --- a/xen/common/efi/boot.c > +++ b/xen/common/efi/boot.c > @@ -32,6 +32,8 @@ > /* Using SetVirtualAddressMap() is incompatible with kexec: */ > #undef USE_SET_VIRTUAL_ADDRESS_MAP > > +#define SMBIOS3_TABLE_GUID \ > + { 0xf2fd1544, 0x9794, 0x4a2c, {0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, > 0x94} } > #define SHIM_LOCK_PROTOCOL_GUID \ > { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, > 0x23} } > > @@ -993,6 +995,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY > static EFI_GUID __initdata acpi_guid = ACPI_TABLE_GUID; > static EFI_GUID __initdata mps_guid = MPS_TABLE_GUID; > static EFI_GUID __initdata smbios_guid = SMBIOS_TABLE_GUID; > + static EFI_GUID __initdata smbios3_guid = SMBIOS3_TABLE_GUID; > > if ( match_guid(&acpi2_guid, &efi_ct[i].VendorGuid) ) > efi.acpi20 = (long)efi_ct[i].VendorTable; > @@ -1002,11 +1005,15 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY > efi.mps = (long)efi_ct[i].VendorTable; > if ( match_guid(&smbios_guid, &efi_ct[i].VendorGuid) ) > efi.smbios = (long)efi_ct[i].VendorTable; > + if ( match_guid(&smbios3_guid, &efi_ct[i].VendorGuid) ) > + efi.smbios3 = (long)efi_ct[i].VendorTable; > } > > #ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */ > - if (efi.smbios != EFI_INVALID_TABLE_ADDR) > - dmi_efi_get_table((void *)(long)efi.smbios); > + dmi_efi_get_table(efi.smbios != EFI_INVALID_TABLE_ADDR > + ? (void *)(long)efi.smbios : NULL, > + efi.smbios3 != EFI_INVALID_TABLE_ADDR > + ? (void *)(long)efi.smbios3 : NULL); > #endif > > /* Collect PCI ROM contents. */ > --- a/xen/common/efi/runtime.c > +++ b/xen/common/efi/runtime.c > @@ -45,6 +45,7 @@ struct efi __read_mostly efi = { > .acpi20 = EFI_INVALID_TABLE_ADDR, > .mps = EFI_INVALID_TABLE_ADDR, > .smbios = EFI_INVALID_TABLE_ADDR, > + .smbios3 = EFI_INVALID_TABLE_ADDR, > }; > > const struct efi_pci_rom *__read_mostly efi_pci_roms; > --- a/xen/include/xen/dmi.h > +++ b/xen/include/xen/dmi.h > @@ -34,8 +34,8 @@ struct dmi_system_id { > > extern int dmi_check_system(struct dmi_system_id *list); > extern void dmi_scan_machine(void); > -extern int dmi_get_table(u32 *base, u32 *len); > -extern void dmi_efi_get_table(void *); > +extern const char *dmi_get_table(paddr_t *base, u32 *len); > +extern void dmi_efi_get_table(const void *smbios, const void *smbios3); > bool_t dmi_get_date(int field, int *yearp, int *monthp, int *dayp); > extern void dmi_end_boot(void); > > --- a/xen/include/xen/efi.h > +++ b/xen/include/xen/efi.h > @@ -15,6 +15,7 @@ struct efi { > unsigned long acpi; /* ACPI table (IA64 ext 0.71) */ > unsigned long acpi20; /* ACPI table (ACPI 2.0) */ > unsigned long smbios; /* SM BIOS table */ > + unsigned long smbios3; /* SMBIOS v3 table */ > }; > > extern struct efi efi; > > > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
_______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel