svn commit: r190814 - head/sys/boot/i386/libi386

Jung-uk Kim jkim at FreeBSD.org
Tue Apr 7 10:58:16 PDT 2009


Author: jkim
Date: Tue Apr  7 17:58:15 2009
New Revision: 190814
URL: http://svn.freebsd.org/changeset/base/190814

Log:
  Rewrite SMBIOS for loader:
  
  - First three fields of system UUID may be little-endian as described in
  SMBIOS Specification v2.6.  For now, we keep the network byte order for
  backward compatibility (and consistency with popular dmidecode tool)
  if SMBIOS table revision is less than 2.6.  However, little-endian format
  can be forced by defining BOOT_LITTLE_ENDIAN_UUID from make.conf(5) if it
  is necessary.
  - Replace overly ambitious optimizations with more readable code.
  - Update comments to SMBIOS Specification v2.6 and clean up style(9) bugs.

Modified:
  head/sys/boot/i386/libi386/Makefile
  head/sys/boot/i386/libi386/smbios.c

Modified: head/sys/boot/i386/libi386/Makefile
==============================================================================
--- head/sys/boot/i386/libi386/Makefile	Tue Apr  7 17:24:25 2009	(r190813)
+++ head/sys/boot/i386/libi386/Makefile	Tue Apr  7 17:58:15 2009	(r190814)
@@ -31,6 +31,10 @@ CFLAGS+= -DDISK_DEBUG
 .if !defined(BOOT_HIDE_SERIAL_NUMBERS)
 # Export serial numbers, UUID, and asset tag from loader.
 CFLAGS+= -DSMBIOS_SERIAL_NUMBERS
+.if defined(BOOT_LITTLE_ENDIAN_UUID)
+# Use little-endian UUID format as defined in SMBIOS 2.6.
+CFLAGS+= -DSMBIOS_LITTLE_ENDIAN_UUID
+.endif
 .endif
 
 .if !defined(LOADER_NO_GPT_SUPPORT)

Modified: head/sys/boot/i386/libi386/smbios.c
==============================================================================
--- head/sys/boot/i386/libi386/smbios.c	Tue Apr  7 17:24:25 2009	(r190813)
+++ head/sys/boot/i386/libi386/smbios.c	Tue Apr  7 17:58:15 2009	(r190814)
@@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$");
 
 #include <stand.h>
 #include <bootstrap.h>
+#include <sys/endian.h>
 
 #include "btxv86.h"
 #include "libi386.h"
@@ -37,17 +38,18 @@ __FBSDID("$FreeBSD$");
  * Detect SMBIOS and export information about the SMBIOS into the
  * environment.
  *
- * System Management BIOS Reference Specification, v2.4 Final
- * http://www.dmtf.org/standards/published_documents/DSP0134.pdf
+ * System Management BIOS Reference Specification, v2.6 Final
+ * http://www.dmtf.org/standards/published_documents/DSP0134_2.6.0.pdf
  */
 
 /*
- * Spec. 2.1.1 SMBIOS Structure Table Entry Point
+ * 2.1.1 SMBIOS Structure Table Entry Point
  *
- * 'The SMBIOS Entry Point structure, described below, can be located by
- * application software by searching for the anchor-string on paragraph
- * (16-byte) boundaries within the physical memory address range
- * 000F0000h to 000FFFFFh.'
+ * "On non-EFI systems, the SMBIOS Entry Point structure, described below, can
+ * be located by application software by searching for the anchor-string on
+ * paragraph (16-byte) boundaries within the physical memory address range
+ * 000F0000h to 000FFFFFh. This entry point encapsulates an intermediate anchor
+ * string that is used by some existing DMI browsers."
  */
 #define	SMBIOS_START		0xf0000
 #define	SMBIOS_LENGTH		0x10000
@@ -55,100 +57,174 @@ __FBSDID("$FreeBSD$");
 #define	SMBIOS_SIG		"_SM_"
 #define	SMBIOS_DMI_SIG		"_DMI_"
 
+#define	SMBIOS_GET8(base, off)	(*(uint8_t *)((base) + (off)))
+#define	SMBIOS_GET16(base, off)	(*(uint16_t *)((base) + (off)))
+#define	SMBIOS_GET32(base, off)	(*(uint32_t *)((base) + (off)))
+
+#define	SMBIOS_GETLEN(base)	SMBIOS_GET8(base, 0x01)
+#define	SMBIOS_GETSTR(base)	((base) + SMBIOS_GETLEN(base))
+
 static uint32_t	smbios_enabled_memory = 0;
 static uint32_t	smbios_old_enabled_memory = 0;
 static uint8_t	smbios_enabled_sockets = 0;
 static uint8_t	smbios_populated_sockets = 0;
 
-static uint8_t	*smbios_parse_table(const uint8_t *dmi);
-static void	smbios_setenv(const char *name, const uint8_t *dmi,
-		    const int offset);
-static uint8_t	smbios_checksum(const caddr_t addr, const uint8_t len);
-static uint8_t	*smbios_sigsearch(const caddr_t addr, const uint32_t len);
+static uint8_t
+smbios_checksum(const caddr_t addr, const uint8_t len)
+{
+	uint8_t		sum;
+	int		i;
 
-#ifdef SMBIOS_SERIAL_NUMBERS
-static void	smbios_setuuid(const char *name, const uint8_t *dmi,
-		    const int offset);
-#endif
+	for (sum = 0, i = 0; i < len; i++)
+		sum += SMBIOS_GET8(addr, i);
+	return (sum);
+}
 
-void
-smbios_detect(void)
+static caddr_t
+smbios_sigsearch(const caddr_t addr, const uint32_t len)
 {
-	uint8_t		*smbios, *dmi, *addr;
-	uint16_t	i, length, count;
-	uint32_t	paddr;
-	char		buf[16];
+	caddr_t		cp;
 
-	/* locate and validate the SMBIOS */
-	smbios = smbios_sigsearch(PTOV(SMBIOS_START), SMBIOS_LENGTH);
-	if (smbios == NULL)
-		return;
+	/* Search on 16-byte boundaries. */
+	for (cp = addr; cp < addr + len; cp += SMBIOS_STEP)
+		if (strncmp(cp, SMBIOS_SIG, 4) == 0 &&
+		    smbios_checksum(cp, SMBIOS_GET8(cp, 0x05)) == 0 &&
+		    strncmp(cp + 0x10, SMBIOS_DMI_SIG, 5) == 0 &&
+		    smbios_checksum(cp + 0x10, 0x0f) == 0)
+			return (cp);
+	return (NULL);
+}
 
-	length = *(uint16_t *)(smbios + 0x16);	/* Structure Table Length */
-	paddr = *(uint32_t *)(smbios + 0x18);	/* Structure Table Address */
-	count = *(uint16_t *)(smbios + 0x1c);	/* No of SMBIOS Structures */
-
-	for (dmi = addr = PTOV(paddr), i = 0;
-	     dmi - addr < length && i < count; i++)
-		dmi = smbios_parse_table(dmi);
-	if (smbios_enabled_memory > 0 || smbios_old_enabled_memory > 0) {
-		sprintf(buf, "%u", smbios_enabled_memory > 0 ?
-		    smbios_enabled_memory : smbios_old_enabled_memory);
-		setenv("smbios.memory.enabled", buf, 1);
+static void
+smbios_setenv(const char *name, caddr_t addr, const int offset)
+{
+	caddr_t		cp;
+	int		i, idx;
+
+	idx = SMBIOS_GET8(addr, offset);
+	if (idx != 0) {
+		cp = SMBIOS_GETSTR(addr);
+		for (i = 1; i < idx; i++)
+			cp += strlen(cp) + 1;
+		setenv(name, cp, 1);
 	}
-	if (smbios_enabled_sockets > 0) {
-		sprintf(buf, "%u", smbios_enabled_sockets);
-		setenv("smbios.socket.enabled", buf, 1);
+}
+
+#ifdef SMBIOS_SERIAL_NUMBERS
+
+#define	UUID_SIZE		16
+#define	UUID_TYPE		uint32_t
+#define	UUID_STEP		sizeof(UUID_TYPE)
+#define	UUID_ALL_BITS		(UUID_SIZE / UUID_STEP)
+#define	UUID_GET(base, off)	(*(UUID_TYPE *)((base) + (off)))
+
+static void
+smbios_setuuid(const char *name, const caddr_t addr, const int ver)
+{
+	char		uuid[37];
+	int		i, ones, zeros;
+	UUID_TYPE	n;
+	uint32_t	f1;
+	uint16_t	f2, f3;
+
+	for (i = 0, ones = 0, zeros = 0; i < UUID_SIZE; i += UUID_STEP) {
+		n = UUID_GET(addr, i) + 1;
+		if (zeros == 0 && n == 0)
+			ones++;
+		else if (ones == 0 && n == 1)
+			zeros++;
+		else
+			break;
 	}
-	if (smbios_populated_sockets > 0) {
-		sprintf(buf, "%u", smbios_populated_sockets);
-		setenv("smbios.socket.populated", buf, 1);
+
+	if (ones != UUID_ALL_BITS && zeros != UUID_ALL_BITS) {
+		/*
+		 * 3.3.2.1 System UUID
+		 *
+		 * "Although RFC 4122 recommends network byte order for all
+		 * fields, the PC industry (including the ACPI, UEFI, and
+		 * Microsoft specifications) has consistently used
+		 * little-endian byte encoding for the first three fields:
+		 * time_low, time_mid, time_hi_and_version. The same encoding,
+		 * also known as wire format, should also be used for the
+		 * SMBIOS representation of the UUID."
+		 *
+		 * Note: We use network byte order for backward compatibility
+		 * unless SMBIOS version is 2.6+ or little-endian is forced.
+		 */
+#ifndef SMBIOS_LITTLE_ENDIAN_UUID
+		if (ver < 0x0206) {
+			f1 = ntohl(SMBIOS_GET32(addr, 0));
+			f2 = ntohs(SMBIOS_GET16(addr, 4));
+			f3 = ntohs(SMBIOS_GET16(addr, 6));
+		} else
+#endif
+		{
+			f1 = le32toh(SMBIOS_GET32(addr, 0));
+			f2 = le16toh(SMBIOS_GET16(addr, 4));
+			f3 = le16toh(SMBIOS_GET16(addr, 6));
+		}
+		sprintf(uuid,
+		    "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+		    f1, f2, f3, SMBIOS_GET8(addr, 8), SMBIOS_GET8(addr, 9),
+		    SMBIOS_GET8(addr, 10), SMBIOS_GET8(addr, 11),
+		    SMBIOS_GET8(addr, 12), SMBIOS_GET8(addr, 13),
+		    SMBIOS_GET8(addr, 14), SMBIOS_GET8(addr, 15));
+		setenv(name, uuid, 1);
 	}
 }
 
-static uint8_t *
-smbios_parse_table(const uint8_t *dmi)
+#undef UUID_SIZE
+#undef UUID_TYPE
+#undef UUID_STEP
+#undef UUID_ALL_BITS
+#undef UUID_GET
+
+#endif
+
+static caddr_t
+smbios_parse_table(const caddr_t addr, const int ver)
 {
-	uint8_t		*dp;
-	uint16_t	size;
-	uint8_t		osize;
-
-	switch(dmi[0]) {
-	case 0:		/* Type 0: BIOS */
-		smbios_setenv("smbios.bios.vendor", dmi, 0x04);
-		smbios_setenv("smbios.bios.version", dmi, 0x05);
-		smbios_setenv("smbios.bios.reldate", dmi, 0x08);
+	caddr_t		cp;
+	int		proc, size, osize, type;
+
+	type = SMBIOS_GET8(addr, 0);	/* 3.1.2 Structure Header Format */
+	switch(type) {
+	case 0:		/* 3.3.1 BIOS Information (Type 0) */
+		smbios_setenv("smbios.bios.vendor", addr, 0x04);
+		smbios_setenv("smbios.bios.version", addr, 0x05);
+		smbios_setenv("smbios.bios.reldate", addr, 0x08);
 		break;
 
-	case 1:		/* Type 1: System */
-		smbios_setenv("smbios.system.maker", dmi, 0x04);
-		smbios_setenv("smbios.system.product", dmi, 0x05);
-		smbios_setenv("smbios.system.version", dmi, 0x06);
+	case 1:		/* 3.3.2 System Information (Type 1) */
+		smbios_setenv("smbios.system.maker", addr, 0x04);
+		smbios_setenv("smbios.system.product", addr, 0x05);
+		smbios_setenv("smbios.system.version", addr, 0x06);
 #ifdef SMBIOS_SERIAL_NUMBERS
-		smbios_setenv("smbios.system.serial", dmi, 0x07);
-		smbios_setuuid("smbios.system.uuid", dmi, 0x08);
+		smbios_setenv("smbios.system.serial", addr, 0x07);
+		smbios_setuuid("smbios.system.uuid", addr + 0x08, ver);
 #endif
 		break;
 
-	case 2:		/* Type 2: Base Board (or Module) */
-		smbios_setenv("smbios.planar.maker", dmi, 0x04);
-		smbios_setenv("smbios.planar.product", dmi, 0x05);
-		smbios_setenv("smbios.planar.version", dmi, 0x06);
+	case 2:		/* 3.3.3 Base Board (or Module) Information (Type 2) */
+		smbios_setenv("smbios.planar.maker", addr, 0x04);
+		smbios_setenv("smbios.planar.product", addr, 0x05);
+		smbios_setenv("smbios.planar.version", addr, 0x06);
 #ifdef SMBIOS_SERIAL_NUMBERS
-		smbios_setenv("smbios.planar.serial", dmi, 0x07);
+		smbios_setenv("smbios.planar.serial", addr, 0x07);
 #endif
 		break;
 
-	case 3:		/* Type 3: System Enclosure or Chassis */
-		smbios_setenv("smbios.chassis.maker", dmi, 0x04);
-		smbios_setenv("smbios.chassis.version", dmi, 0x06);
+	case 3:		/* 3.3.4 System Enclosure or Chassis (Type 3) */
+		smbios_setenv("smbios.chassis.maker", addr, 0x04);
+		smbios_setenv("smbios.chassis.version", addr, 0x06);
 #ifdef SMBIOS_SERIAL_NUMBERS
-		smbios_setenv("smbios.chassis.serial", dmi, 0x07);
-		smbios_setenv("smbios.chassis.tag", dmi, 0x08);
+		smbios_setenv("smbios.chassis.serial", addr, 0x07);
+		smbios_setenv("smbios.chassis.tag", addr, 0x08);
 #endif
 		break;
 
-	case 4:		/* Type 4: Processor Information */
+	case 4:		/* 3.3.5 Processor Information (Type 4) */
 		/*
 		 * Offset 18h: Processor Status
 		 *
@@ -166,13 +242,14 @@ smbios_parse_table(const uint8_t *dmi)
 		 *		5-6h - Reserved
 		 *		7h - Other
 		 */
-		if ((dmi[0x18] & 0x07) == 1)
+		proc = SMBIOS_GET8(addr, 0x18);
+		if ((proc & 0x07) == 1)
 			smbios_enabled_sockets++;
-		if (dmi[0x18] & 0x40)
+		if ((proc & 0x40) != 0)
 			smbios_populated_sockets++;
 		break;
 
-	case 6:		/* Type 6: Memory Module Information (Obsolete) */
+	case 6:		/* 3.3.7 Memory Module Information (Type 6, Obsolete) */
 		/*
 		 * Offset 0Ah: Enabled Size
 		 *
@@ -185,12 +262,12 @@ smbios_parse_table(const uint8_t *dmi)
 		 *		      has been enabled
 		 *		7Fh - Not installed
 		 */
-		osize = dmi[0x0a] & 0x7f;
+		osize = SMBIOS_GET8(addr, 0x0a) & 0x7f;
 		if (osize > 0 && osize < 22)
-			smbios_old_enabled_memory += (1U << (osize + 10));
+			smbios_old_enabled_memory += 1 << (osize + 10);
 		break;
 
-	case 17:	/* Type 17: Memory Device */
+	case 17:	/* 3.3.18 Memory Device (Type 17) */
 		/*
 		 * Offset 0Ch: Size
 		 *
@@ -199,99 +276,72 @@ smbios_parse_table(const uint8_t *dmi)
 		 *		0 - Value is in megabytes units
 		 * Bit 14:0	Size
 		 */
-		size = *(uint16_t *)(dmi + 0x0c);
+		size = SMBIOS_GET16(addr, 0x0c);
 		if (size != 0 && size != 0xffff)
 			smbios_enabled_memory += (size & 0x8000) != 0 ?
-			    (size & 0x7fff) : ((uint32_t)size << 10);
+			    (size & 0x7fff) : (size << 10);
 		break;
 
-	default: /* skip other types */
+	default:	/* skip other types */
 		break;
 	}
 
-	/* find structure terminator */
-	dp = __DECONST(uint8_t *, dmi + dmi[1]);
-	while (dp[0] != 0 || dp[1] != 0)
-		dp++;
+	/* Find structure terminator. */
+	cp = SMBIOS_GETSTR(addr);
+	while (SMBIOS_GET16(cp, 0) != 0)
+		cp++;
 
-	return(dp + 2);
+	return (cp + 2);
 }
 
-static void
-smbios_setenv(const char *name, const uint8_t *dmi, const int offset)
+void
+smbios_detect(void)
 {
-	char		*cp = __DECONST(char *, dmi + dmi[1]);
-	int		i;
+	char		buf[16];
+	caddr_t		addr, dmi, smbios;
+	size_t		count, length;
+	uint32_t	paddr;
+	int		i, major, minor, ver;
 
-	/* skip undefined string */
-	if (dmi[offset] == 0)
+	/* Search signatures and validate checksums. */
+	smbios = smbios_sigsearch(PTOV(SMBIOS_START), SMBIOS_LENGTH);
+	if (smbios == NULL)
 		return;
 
-	for (i = 0; i < dmi[offset] - 1; i++)
-		cp += strlen(cp) + 1;
-	setenv(name, cp, 1);
-}
-
-static uint8_t
-smbios_checksum(const caddr_t addr, const uint8_t len)
-{
-	const uint8_t	*cp = addr;
-	uint8_t		sum;
-	int		i;
-
-	for (sum = 0, i = 0; i < len; i++)
-		sum += cp[i];
-
-	return(sum);
-}
-
-static uint8_t *
-smbios_sigsearch(const caddr_t addr, const uint32_t len)
-{
-	caddr_t		cp;
-
-	/* search on 16-byte boundaries */
-	for (cp = addr; cp < addr + len; cp += SMBIOS_STEP) {
-		/* compare signature, validate checksum */
-		if (!strncmp(cp, SMBIOS_SIG, 4)) {
-			if (smbios_checksum(cp, *(uint8_t *)(cp + 0x05)))
-				continue;
-			if (strncmp(cp + 0x10, SMBIOS_DMI_SIG, 5))
-				continue;
-			if (smbios_checksum(cp + 0x10, 0x0f))
-				continue;
-
-			return(cp);
-		}
+	length = SMBIOS_GET16(smbios, 0x16);	/* Structure Table Length */
+	paddr = SMBIOS_GET32(smbios, 0x18);	/* Structure Table Address */
+	count = SMBIOS_GET16(smbios, 0x1c);	/* No of SMBIOS Structures */
+	ver = SMBIOS_GET8(smbios, 0x1e);	/* SMBIOS BCD Revision */
+
+	if (ver != 0) {
+		major = ver >> 4;
+		minor = ver & 0x0f;
+		if (major > 9 || minor > 9)
+			ver = 0;
 	}
+	if (ver == 0) {
+		major = SMBIOS_GET8(smbios, 0x06); /* SMBIOS Major Version */
+		minor = SMBIOS_GET8(smbios, 0x07); /* SMBIOS Minor Version */
+	}
+	ver = (major << 8) | minor;
 
-	return(NULL);
-}
+	addr = PTOV(paddr);
+	for (dmi = addr, i = 0; dmi < addr + length && i < count; i++)
+		dmi = smbios_parse_table(dmi, ver);
 
-#ifdef SMBIOS_SERIAL_NUMBERS
-static void
-smbios_setuuid(const char *name, const uint8_t *dmi, const int offset)
-{
-	const uint8_t	*idp = dmi + offset;
-	int		i, f = 0, z = 0;
-	char		uuid[37];
-
-	for (i = 0; i < 16; i++) {
-		if (idp[i] == 0xff)
-			f++;
-		else if (idp[i] == 0x00)
-			z++;
-		else
-			break;
+	sprintf(buf, "%d.%d", major, minor);
+	setenv("smbios.version", buf, 1);
+	if (smbios_enabled_memory > 0 || smbios_old_enabled_memory > 0) {
+		sprintf(buf, "%u", smbios_enabled_memory > 0 ?
+		    smbios_enabled_memory : smbios_old_enabled_memory);
+		setenv("smbios.memory.enabled", buf, 1);
 	}
-	if (f != 16 && z != 16) {
-		sprintf(uuid, "%02x%02x%02x%02x-"
-		    "%02x%02x-%02x%02x-%02x%02x-"
-		    "%02x%02x%02x%02x%02x%02x",
-		    idp[0], idp[1], idp[2], idp[3],
-		    idp[4], idp[5], idp[6], idp[7], idp[8], idp[9],
-		    idp[10], idp[11], idp[12], idp[13], idp[14], idp[15]);
-		setenv(name, uuid, 1);
+	if (smbios_enabled_sockets > 0) {
+		sprintf(buf, "%u", smbios_enabled_sockets);
+		setenv("smbios.socket.enabled", buf, 1);
+	}
+	if (smbios_populated_sockets > 0) {
+		sprintf(buf, "%u", smbios_populated_sockets);
+		setenv("smbios.socket.populated", buf, 1);
 	}
 }
-#endif


More information about the svn-src-head mailing list