git: 7f005c6699f4 - main - libsa: smbios: Use 64-bit entry point if table below 4GB on non-EFI boot

From: Olivier Certner <olce_at_FreeBSD.org>
Date: Tue, 11 Mar 2025 14:04:45 UTC
The branch main has been updated by olce:

URL: https://cgit.FreeBSD.org/src/commit/?id=7f005c6699f429c2f762b4dd8fb39b3bcf5378e2

commit 7f005c6699f429c2f762b4dd8fb39b3bcf5378e2
Author:     Olivier Certner <olce@FreeBSD.org>
AuthorDate: 2025-03-03 21:10:25 +0000
Commit:     Olivier Certner <olce@FreeBSD.org>
CommitDate: 2025-03-11 13:54:09 +0000

    libsa: smbios: Use 64-bit entry point if table below 4GB on non-EFI boot
    
    On amd64, boot blocks and the non-EFI loader are 32-bit compiled as
    clients of BTX, so cannot access addresses beyond 4GB.  However, the
    64-bit entry point may refer to a structure table below 4GB, which we
    want to use if the BIOS does not provide a 32-bit entry point.  The
    situation is similar for powerpc64.
    
    Consequently, always compile-in support for the 64-bit entry point, but
    ensure that it is not selected on 32-bit-compiled boot loaders if the
    structure table it points to grows beyond 4GB (as it is then not
    accessible).
    
    PR:             284460
    Reviewed by:    markj
    MFC after:      2 weeks
    Relnotes:       yes
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D49288
---
 stand/libsa/smbios.c | 37 ++++++++++++++-----------------------
 1 file changed, 14 insertions(+), 23 deletions(-)

diff --git a/stand/libsa/smbios.c b/stand/libsa/smbios.c
index 2477c0ccf2d3..e0531eab01da 100644
--- a/stand/libsa/smbios.c
+++ b/stand/libsa/smbios.c
@@ -29,11 +29,6 @@
 
 #define PTOV(x)		ptov(x)
 
-/* Only enable 64-bit entry point if it makes sense */
-#if __SIZEOF_POINTER__ > 4
-#define	SMBIOS_64BIT_EP	1
-#endif
-
 /*
  * Detect SMBIOS and export information about the SMBIOS into the
  * environment.
@@ -145,9 +140,7 @@ SMBIOS_GET64(const caddr_t base, int off)
 
 struct smbios_attr {
 	int		probed;
-#ifdef SMBIOS_64BIT_EP
 	int		is_64bit_ep;
-#endif
 	caddr_t		addr;
 	size_t		length;
 	size_t		count;
@@ -184,7 +177,6 @@ smbios_sigsearch(const caddr_t addr, const uint32_t len)
 
 	/* Search on 16-byte boundaries. */
 	for (cp = addr; cp < addr + len; cp += SMBIOS_STEP) {
-#ifdef SMBIOS_64BIT_EP
 		/* v3.0, 64-bit Entry point */
 		if (strncmp(cp, SMBIOS3_SIG, sizeof(SMBIOS3_SIG) - 1) == 0 &&
 		    /*
@@ -195,10 +187,19 @@ smbios_sigsearch(const caddr_t addr, const uint32_t len)
 		     */
 		    SMBIOS_GET8(cp, 0x0a) != 0 &&
 		    smbios_checksum(cp, SMBIOS_GET8(cp, 0x06)) == 0) {
+#ifdef __ILP32__
+			uint64_t end_addr;
+
+			end_addr = SMBIOS_GET64(cp, 0x10) + /* Start address. */
+			    SMBIOS_GET32(cp, 0x0c); /* Maximum size. */
+			/* Is the table (or part of it) located above 4G? */
+			if (end_addr >= (uint64_t)1 << 32)
+				/* Can't access it with 32-bit addressing. */
+				continue;
+#endif
 			smbios.is_64bit_ep = 1;
 			return (cp);
 		}
-#endif
 
 		/* v2.1, 32-bit Entry point */
 		if (strncmp(cp, SMBIOS_SIG, sizeof(SMBIOS_SIG) - 1) == 0 &&
@@ -207,13 +208,9 @@ smbios_sigsearch(const caddr_t addr, const uint32_t len)
 		    smbios_checksum(cp + 0x10, 0x0f) == 0) {
 			/*
 			 * Note that we saw this entry point, but don't return
-			 * it right now on SMBIOS_64BIT_EP as we favor the 64-bit
-			 * one if present.
+			 * it right now as we favor the 64-bit one if present.
 			 */
 			v2_p = cp;
-#ifndef SMBIOS_64BIT_EP
-			break;
-#endif
 		}
 	}
 	return (v2_p);
@@ -586,7 +583,6 @@ smbios_probe(const caddr_t addr)
 	if (saddr == NULL)
 		return;
 
-#ifdef SMBIOS_64BIT_EP
 	if (smbios.is_64bit_ep) {
 		/* Structure Table Length */
 		smbios.length = SMBIOS_GET32(saddr, 0x0c);
@@ -601,9 +597,7 @@ smbios_probe(const caddr_t addr)
 		smbios.ver = 0;
 		maj_off = 0x07;
 		min_off = 0x08;
-	} else
-#endif
-	{
+	} else {
 		/* Structure Table Length */
 		smbios.length = SMBIOS_GET16(saddr, 0x16);
 		/* Structure Table Address */
@@ -661,11 +655,8 @@ smbios_detect(const caddr_t addr)
 	    dmi < smbios.addr + smbios.length && i < smbios.count; i++)
 		dmi = smbios_parse_table(dmi);
 
-	setenv("smbios.entry_point_type",
-#ifdef SMBIOS_64BIT_EP
-	    smbios.is_64bit_ep ? "v3 (64-bit)" :
-#endif
-	    "v2.1 (32-bit)", 1);
+	setenv("smbios.entry_point_type", smbios.is_64bit_ep ?
+	    "v3 (64-bit)" : "v2.1 (32-bit)", 1);
 	sprintf(buf, "%d.%d", smbios.major, smbios.minor);
 	setenv("smbios.version", buf, 1);
 	if (smbios.enabled_memory > 0 || smbios.old_enabled_memory > 0) {