1616 */
1717static char dmi_empty_string [] = " " ;
1818
19+ static u16 __initdata dmi_ver ;
1920/*
2021 * Catch too early calls to dmi_check_system():
2122 */
@@ -118,12 +119,12 @@ static int __init dmi_walk_early(void (*decode)(const struct dmi_header *,
118119 return 0 ;
119120}
120121
121- static int __init dmi_checksum (const u8 * buf )
122+ static int __init dmi_checksum (const u8 * buf , u8 len )
122123{
123124 u8 sum = 0 ;
124125 int a ;
125126
126- for (a = 0 ; a < 15 ; a ++ )
127+ for (a = 0 ; a < len ; a ++ )
127128 sum += buf [a ];
128129
129130 return sum == 0 ;
@@ -161,8 +162,10 @@ static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int inde
161162 return ;
162163
163164 for (i = 0 ; i < 16 && (is_ff || is_00 ); i ++ ) {
164- if (d [i ] != 0x00 ) is_ff = 0 ;
165- if (d [i ] != 0xFF ) is_00 = 0 ;
165+ if (d [i ] != 0x00 )
166+ is_00 = 0 ;
167+ if (d [i ] != 0xFF )
168+ is_ff = 0 ;
166169 }
167170
168171 if (is_ff || is_00 )
@@ -172,7 +175,15 @@ static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int inde
172175 if (!s )
173176 return ;
174177
175- sprintf (s , "%pUB" , d );
178+ /*
179+ * As of version 2.6 of the SMBIOS specification, the first 3 fields of
180+ * the UUID are supposed to be little-endian encoded. The specification
181+ * says that this is the defacto standard.
182+ */
183+ if (dmi_ver >= 0x0206 )
184+ sprintf (s , "%pUL" , d );
185+ else
186+ sprintf (s , "%pUB" , d );
176187
177188 dmi_ident [slot ] = s ;
178189}
@@ -404,29 +415,57 @@ static int __init dmi_present(const char __iomem *p)
404415 u8 buf [15 ];
405416
406417 memcpy_fromio (buf , p , 15 );
407- if (( memcmp ( buf , "_DMI_" , 5 ) == 0 ) && dmi_checksum ( buf )) {
418+ if (dmi_checksum ( buf , 15 )) {
408419 dmi_num = (buf [13 ] << 8 ) | buf [12 ];
409420 dmi_len = (buf [7 ] << 8 ) | buf [6 ];
410421 dmi_base = (buf [11 ] << 24 ) | (buf [10 ] << 16 ) |
411422 (buf [9 ] << 8 ) | buf [8 ];
412423
413- /*
414- * DMI version 0.0 means that the real version is taken from
415- * the SMBIOS version, which we don't know at this point.
416- */
417- if (buf [14 ] != 0 )
418- printk (KERN_INFO "DMI %d.%d present.\n" ,
419- buf [14 ] >> 4 , buf [14 ] & 0xF );
420- else
421- printk (KERN_INFO "DMI present.\n" );
422424 if (dmi_walk_early (dmi_decode ) == 0 ) {
425+ if (dmi_ver )
426+ pr_info ("SMBIOS %d.%d present.\n" ,
427+ dmi_ver >> 8 , dmi_ver & 0xFF );
428+ else {
429+ dmi_ver = (buf [14 ] & 0xF0 ) << 4 |
430+ (buf [14 ] & 0x0F );
431+ pr_info ("Legacy DMI %d.%d present.\n" ,
432+ dmi_ver >> 8 , dmi_ver & 0xFF );
433+ }
423434 dmi_dump_ids ();
424435 return 0 ;
425436 }
426437 }
438+ dmi_ver = 0 ;
427439 return 1 ;
428440}
429441
442+ static int __init smbios_present (const char __iomem * p )
443+ {
444+ u8 buf [32 ];
445+ int offset = 0 ;
446+
447+ memcpy_fromio (buf , p , 32 );
448+ if ((buf [5 ] < 32 ) && dmi_checksum (buf , buf [5 ])) {
449+ dmi_ver = (buf [6 ] << 8 ) + buf [7 ];
450+
451+ /* Some BIOS report weird SMBIOS version, fix that up */
452+ switch (dmi_ver ) {
453+ case 0x021F :
454+ case 0x0221 :
455+ pr_debug ("SMBIOS version fixup(2.%d->2.%d)\n" ,
456+ dmi_ver & 0xFF , 3 );
457+ dmi_ver = 0x0203 ;
458+ break ;
459+ case 0x0233 :
460+ pr_debug ("SMBIOS version fixup(2.%d->2.%d)\n" , 51 , 6 );
461+ dmi_ver = 0x0206 ;
462+ break ;
463+ }
464+ offset = 16 ;
465+ }
466+ return dmi_present (buf + offset );
467+ }
468+
430469void __init dmi_scan_machine (void )
431470{
432471 char __iomem * p , * q ;
@@ -444,7 +483,7 @@ void __init dmi_scan_machine(void)
444483 if (p == NULL )
445484 goto error ;
446485
447- rc = dmi_present ( p + 0x10 ); /* offset of _DMI_ string */
486+ rc = smbios_present ( p );
448487 dmi_iounmap (p , 32 );
449488 if (!rc ) {
450489 dmi_available = 1 ;
@@ -462,7 +501,12 @@ void __init dmi_scan_machine(void)
462501 goto error ;
463502
464503 for (q = p ; q < p + 0x10000 ; q += 16 ) {
465- rc = dmi_present (q );
504+ if (memcmp (q , "_SM_" , 4 ) == 0 && q - p <= 0xFFE0 )
505+ rc = smbios_present (q );
506+ else if (memcmp (q , "_DMI_" , 5 ) == 0 )
507+ rc = dmi_present (q );
508+ else
509+ continue ;
466510 if (!rc ) {
467511 dmi_available = 1 ;
468512 dmi_iounmap (p , 0x10000 );
0 commit comments