mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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:
committed by
Ard Biesheuvel
parent
3a86608788
commit
4f90742d4a
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user