Skip to content

Commit 4f90742

Browse files
Francesco Pompoardbiesheuvel
authored andcommitted
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>
1 parent 3a86608 commit 4f90742

1 file changed

Lines changed: 100 additions & 1 deletion

File tree

drivers/firmware/efi/libstub/x86-stub.c

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,104 @@ static void retrieve_apple_device_properties(struct boot_params *boot_params)
203203
}
204204
}
205205

206+
struct smbios_entry_point {
207+
u8 anchor[4];
208+
u8 ep_checksum;
209+
u8 ep_length;
210+
u8 major_version;
211+
u8 minor_version;
212+
u16 max_size_entry;
213+
u8 ep_rev;
214+
u8 reserved[5];
215+
216+
struct __packed {
217+
u8 anchor[5];
218+
u8 checksum;
219+
u16 st_length;
220+
u32 st_address;
221+
u16 number_of_entries;
222+
u8 bcd_rev;
223+
} intm;
224+
};
225+
226+
static bool verify_ep_checksum(const void *ptr, int length)
227+
{
228+
u8 sum = 0;
229+
230+
for (int i = 0; i < length; i++)
231+
sum += ((u8 *)ptr)[i];
232+
233+
return sum == 0;
234+
}
235+
236+
static bool verify_ep_integrity(const struct smbios_entry_point *ep)
237+
{
238+
if (memcmp(ep->anchor, "_SM_", sizeof(ep->anchor)) != 0)
239+
return false;
240+
241+
if (memcmp(ep->intm.anchor, "_DMI_", sizeof(ep->intm.anchor)) != 0)
242+
return false;
243+
244+
if (!verify_ep_checksum(ep, ep->ep_length) ||
245+
!verify_ep_checksum(&ep->intm, sizeof(ep->intm)))
246+
return false;
247+
248+
return true;
249+
}
250+
251+
static const struct efi_smbios_record *search_record(void *table, u32 length,
252+
u8 type)
253+
{
254+
const u8 *p, *end;
255+
256+
p = (u8 *)table;
257+
end = p + length;
258+
259+
while (p + sizeof(struct efi_smbios_record) < end) {
260+
const struct efi_smbios_record *hdr =
261+
(struct efi_smbios_record *)p;
262+
const u8 *next;
263+
264+
if (hdr->type == type)
265+
return hdr;
266+
267+
/* Type 127 = End-of-Table */
268+
if (hdr->type == 0x7F)
269+
return NULL;
270+
271+
/* Jumping to the unformed section */
272+
next = p + hdr->length;
273+
274+
/* Unformed section ends with 0000h */
275+
while ((next[0] != 0 || next[1] != 0) && next + 1 < end)
276+
next++;
277+
278+
next += 2;
279+
p = next;
280+
}
281+
282+
return NULL;
283+
}
284+
285+
static const struct efi_smbios_record *get_table_record(u8 type)
286+
{
287+
const struct smbios_entry_point *ep;
288+
289+
/*
290+
* Locate the legacy 32-bit SMBIOS entrypoint in memory, and parse it
291+
* directly. Needed by some Macs that do not implement the EFI protocol.
292+
*/
293+
ep = get_efi_config_table(SMBIOS_TABLE_GUID);
294+
if (!ep)
295+
return NULL;
296+
297+
if (!verify_ep_integrity(ep))
298+
return NULL;
299+
300+
return search_record((void *)(unsigned long)ep->intm.st_address,
301+
ep->intm.st_length, type);
302+
}
303+
206304
static bool apple_match_product_name(void)
207305
{
208306
static const char type1_product_matches[][15] = {
@@ -218,7 +316,8 @@ static bool apple_match_product_name(void)
218316
const struct efi_smbios_type1_record *record;
219317
const u8 *product;
220318

221-
record = (struct efi_smbios_type1_record *)efi_get_smbios_record(1);
319+
record = (struct efi_smbios_type1_record *)
320+
(efi_get_smbios_record(1) ?: get_table_record(1));
222321
if (!record)
223322
return false;
224323

0 commit comments

Comments
 (0)