efistub/x86: Add fallback for SMBIOS record lookup

Some Apple EFI firmwares do not provide the SMBIOS Protocol,
causing efi_get_smbios_record() to fail. This prevents retrieval of
system information such as product name, which is needed by
apple_set_os() to enable the integrated GPU on dual-graphics Intel
MacBooks.

Add a fallback that directly parses the SMBIOS entry point table when
the protocol is unavailable.

Signed-off-by: Francesco Pompo <francescopompo2@gmail.com>
[ardb: cosmetic tweaks]
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
Francesco Pompo
2025-11-03 13:25:39 +01:00
committed by Ard Biesheuvel
parent 3a86608788
commit 4f90742d4a

View File

@@ -203,6 +203,104 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
}
}
struct smbios_entry_point {
u8 anchor[4];
u8 ep_checksum;
u8 ep_length;
u8 major_version;
u8 minor_version;
u16 max_size_entry;
u8 ep_rev;
u8 reserved[5];
struct __packed {
u8 anchor[5];
u8 checksum;
u16 st_length;
u32 st_address;
u16 number_of_entries;
u8 bcd_rev;
} intm;
};
static bool verify_ep_checksum(const void *ptr, int length)
{
u8 sum = 0;
for (int i = 0; i < length; i++)
sum += ((u8 *)ptr)[i];
return sum == 0;
}
static bool verify_ep_integrity(const struct smbios_entry_point *ep)
{
if (memcmp(ep->anchor, "_SM_", sizeof(ep->anchor)) != 0)
return false;
if (memcmp(ep->intm.anchor, "_DMI_", sizeof(ep->intm.anchor)) != 0)
return false;
if (!verify_ep_checksum(ep, ep->ep_length) ||
!verify_ep_checksum(&ep->intm, sizeof(ep->intm)))
return false;
return true;
}
static const struct efi_smbios_record *search_record(void *table, u32 length,
u8 type)
{
const u8 *p, *end;
p = (u8 *)table;
end = p + length;
while (p + sizeof(struct efi_smbios_record) < end) {
const struct efi_smbios_record *hdr =
(struct efi_smbios_record *)p;
const u8 *next;
if (hdr->type == type)
return hdr;
/* Type 127 = End-of-Table */
if (hdr->type == 0x7F)
return NULL;
/* Jumping to the unformed section */
next = p + hdr->length;
/* Unformed section ends with 0000h */
while ((next[0] != 0 || next[1] != 0) && next + 1 < end)
next++;
next += 2;
p = next;
}
return NULL;
}
static const struct efi_smbios_record *get_table_record(u8 type)
{
const struct smbios_entry_point *ep;
/*
* Locate the legacy 32-bit SMBIOS entrypoint in memory, and parse it
* directly. Needed by some Macs that do not implement the EFI protocol.
*/
ep = get_efi_config_table(SMBIOS_TABLE_GUID);
if (!ep)
return NULL;
if (!verify_ep_integrity(ep))
return NULL;
return search_record((void *)(unsigned long)ep->intm.st_address,
ep->intm.st_length, type);
}
static bool apple_match_product_name(void)
{
static const char type1_product_matches[][15] = {
@@ -218,7 +316,8 @@ static bool apple_match_product_name(void)
const struct efi_smbios_type1_record *record;
const u8 *product;
record = (struct efi_smbios_type1_record *)efi_get_smbios_record(1);
record = (struct efi_smbios_type1_record *)
(efi_get_smbios_record(1) ?: get_table_record(1));
if (!record)
return false;