linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: ard.biesheuvel@linaro.org (Ard Biesheuvel)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v2] dmi: add support for SMBIOS 3.0 64-bit entry point
Date: Wed, 29 Oct 2014 16:11:25 +0100	[thread overview]
Message-ID: <1414595485-5723-1-git-send-email-ard.biesheuvel@linaro.org> (raw)
In-Reply-To: <1414513123-20400-8-git-send-email-ard.biesheuvel@linaro.org>

The DMTF SMBIOS reference spec v3.0.0 defines a new 64-bit entry point,
which enables support for SMBIOS structure tables residing at a physical
offset over 4 GB. This is especially important for upcoming arm64
platforms whose system RAM resides entirely above the 4 GB boundary.

For the UEFI case, this code attempts to detect the new SMBIOS 3.0
header magic at the offset passed in the SMBIOS3_TABLE_GUID UEFI
configuration table. If this configuration table is not provided, or
if we fail to parse the header, we fall back to using the legacy
SMBIOS_TABLE_GUID configuration table. This is in line with the spec,
that allows both configuration tables to be provided, but mandates that
they must point to the same structure table, unless the version pointed
to by the 64-bit entry point is a superset of the 32-bit one.

For the non-UEFI case, the detection logic is modified to look for the
SMBIOS 3.0 header magic before it looks for the legacy header magic.

Note that this patch is based on version 3.0.0d [draft] of the
specification, which is expected not to deviate from the final version
in ways that would affect the correctness of this implementation.

Tested-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Acked-by: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Tony Luck <tony.luck@intel.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
v2: since dmi_base is now a phys_addr_t, prevent surprises caused by GCC's type
    promotion rules by replacing the open coded shifts/ORs with
    get_unaligned_leXX()
---
 drivers/firmware/dmi_scan.c | 79 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 72 insertions(+), 7 deletions(-)

diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 17afc51f3054..f617badc2698 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -93,6 +93,12 @@ static void dmi_table(u8 *buf, int len, int num,
 		const struct dmi_header *dm = (const struct dmi_header *)data;
 
 		/*
+		 * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0]
+		 */
+		if (dm->type == 127)
+			break;
+
+		/*
 		 *  We want to know the total length (formatted area and
 		 *  strings) before decoding to make sure we won't run off the
 		 *  table in dmi_decode or dmi_string
@@ -107,7 +113,7 @@ static void dmi_table(u8 *buf, int len, int num,
 	}
 }
 
-static u32 dmi_base;
+static phys_addr_t dmi_base;
 static u16 dmi_len;
 static u16 dmi_num;
 
@@ -467,7 +473,7 @@ static int __init dmi_present(const u8 *buf)
 
 	if (memcmp(buf, "_SM_", 4) == 0 &&
 	    buf[5] < 32 && dmi_checksum(buf, buf[5])) {
-		smbios_ver = (buf[6] << 8) + buf[7];
+		smbios_ver = get_unaligned_be16(buf + 6);
 
 		/* Some BIOS report weird SMBIOS version, fix that up */
 		switch (smbios_ver) {
@@ -489,10 +495,9 @@ static int __init dmi_present(const u8 *buf)
 	buf += 16;
 
 	if (memcmp(buf, "_DMI_", 5) == 0 && dmi_checksum(buf, 15)) {
-		dmi_num = (buf[13] << 8) | buf[12];
-		dmi_len = (buf[7] << 8) | buf[6];
-		dmi_base = (buf[11] << 24) | (buf[10] << 16) |
-			(buf[9] << 8) | buf[8];
+		dmi_num = get_unaligned_le16(buf + 12);
+		dmi_len = get_unaligned_le16(buf + 6);
+		dmi_base = get_unaligned_le32(buf + 8);
 
 		if (dmi_walk_early(dmi_decode) == 0) {
 			if (smbios_ver) {
@@ -514,12 +519,72 @@ static int __init dmi_present(const u8 *buf)
 	return 1;
 }
 
+/*
+ * Check for the SMBIOS 3.0 64-bit entry point signature. Unlike the legacy
+ * 32-bit entry point, there is no embedded DMI header (_DMI_) in here.
+ */
+static int __init dmi_smbios3_present(const u8 *buf)
+{
+	if (memcmp(buf, "_SM3_", 5) == 0 &&
+	    buf[6] < 32 && dmi_checksum(buf, buf[6])) {
+		dmi_ver = get_unaligned_be16(buf + 7);
+		dmi_len = get_unaligned_le32(buf + 12);
+		dmi_base = get_unaligned_le64(buf + 16);
+
+		/*
+		 * The 64-bit SMBIOS 3.0 entry point no longer has a field
+		 * containing the number of structures present in the table.
+		 * Instead, it defines the table size as a maximum size, and
+		 * relies on the end-of-table structure type (#127) to be used
+		 * to signal the end of the table.
+		 * So let's define dmi_num as an upper bound as well: each
+		 * structure has a 4 byte header, so dmi_len / 4 is an upper
+		 * bound for the number of structures in the table.
+		 */
+		dmi_num = dmi_len / 4;
+
+		if (dmi_walk_early(dmi_decode) == 0) {
+			pr_info("SMBIOS %d.%d present.\n",
+				dmi_ver >> 8, dmi_ver & 0xFF);
+			dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
+			pr_debug("DMI: %s\n", dmi_ids_string);
+			return 0;
+		}
+	}
+	return 1;
+}
+
 void __init dmi_scan_machine(void)
 {
 	char __iomem *p, *q;
 	char buf[32];
 
 	if (efi_enabled(EFI_CONFIG_TABLES)) {
+		/*
+		 * According to the DMTF SMBIOS reference spec v3.0.0, it is
+		 * allowed to define both the 64-bit entry point (smbios3) and
+		 * the 32-bit entry point (smbios), in which case they should
+		 * either both point to the same SMBIOS structure table, or the
+		 * table pointed to by the 64-bit entry point should contain a
+		 * superset of the table contents pointed to by the 32-bit entry
+		 * point (section 5.2)
+		 * This implies that the 64-bit entry point should have
+		 * precedence if it is defined and supported by the OS. If we
+		 * have the 64-bit entry point, but fail to decode it, fall
+		 * back to the legacy one (if available)
+		 */
+		if (efi.smbios3 != EFI_INVALID_TABLE_ADDR) {
+			p = dmi_early_remap(efi.smbios3, 32);
+			if (p == NULL)
+				goto error;
+			memcpy_fromio(buf, p, 32);
+			dmi_early_unmap(p, 32);
+
+			if (!dmi_smbios3_present(buf)) {
+				dmi_available = 1;
+				goto out;
+			}
+		}
 		if (efi.smbios == EFI_INVALID_TABLE_ADDR)
 			goto error;
 
@@ -552,7 +617,7 @@ void __init dmi_scan_machine(void)
 		memset(buf, 0, 16);
 		for (q = p; q < p + 0x10000; q += 16) {
 			memcpy_fromio(buf + 16, q, 16);
-			if (!dmi_present(buf)) {
+			if (!dmi_smbios3_present(buf) || !dmi_present(buf)) {
 				dmi_available = 1;
 				dmi_early_unmap(p, 0x10000);
 				goto out;
-- 
1.8.3.2

  reply	other threads:[~2014-10-29 15:11 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-10-28 16:18 [PATCH v2 00/10] arm64 EFI patches for 3.19 Ard Biesheuvel
2014-10-28 16:18 ` [PATCH v2 01/10] arm64/efi: efistub: jump to 'stext' directly, not through the header Ard Biesheuvel
2014-10-28 16:18 ` [PATCH v2 02/10] arm64/efi: set PE/COFF section alignment to 4 KB Ard Biesheuvel
2014-10-28 16:18 ` [PATCH v2 03/10] arm64/efi: set PE/COFF file alignment to 512 bytes Ard Biesheuvel
2014-10-28 16:18 ` [PATCH v2 04/10] arm64/efi: invert UEFI memory region reservation logic Ard Biesheuvel
2014-10-28 16:47   ` Mark Rutland
2014-10-28 17:08     ` Ard Biesheuvel
2014-10-28 17:28       ` Mark Rutland
2014-10-30  0:28   ` Roy Franz
2014-10-28 16:18 ` [PATCH v2 05/10] arm64/efi: drop redundant set_bit(EFI_CONFIG_TABLES) Ard Biesheuvel
2014-10-28 16:18 ` [PATCH v2 06/10] efi: dmi: add support for SMBIOS 3.0 UEFI configuration table Ard Biesheuvel
2014-11-04 17:20   ` Matt Fleming
2014-10-28 16:18 ` [PATCH v2 07/10] dmi: add support for SMBIOS 3.0 64-bit entry point Ard Biesheuvel
2014-10-29 15:11   ` Ard Biesheuvel [this message]
2014-10-29 16:19     ` [PATCH v2] " Leif Lindholm
2014-11-04 17:39   ` [PATCH v2 07/10] " Matt Fleming
2014-10-28 16:18 ` [PATCH v2 08/10] arm64: dmi: Add SMBIOS/DMI support Ard Biesheuvel
2014-10-29 16:23   ` Leif Lindholm
2014-10-28 16:18 ` [PATCH v2 09/10] arm64: dmi: set DMI string as dump stack arch description Ard Biesheuvel
2014-10-29 14:58   ` Leif Lindholm
2014-10-28 16:18 ` [PATCH v2 10/10] efi: efi-stub: notify on DTB absence Ard Biesheuvel
2014-11-04 17:42   ` Matt Fleming
2014-11-05  7:53 ` [PATCH v2 00/10] arm64 EFI patches for 3.19 Ard Biesheuvel
2014-11-05  9:52   ` Will Deacon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1414595485-5723-1-git-send-email-ard.biesheuvel@linaro.org \
    --to=ard.biesheuvel@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).