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

Reply via email to