Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Francesco Pompo and committed by
Ard Biesheuvel
4f90742d 3a866087

+100 -1
+100 -1
drivers/firmware/efi/libstub/x86-stub.c
··· 203 203 } 204 204 } 205 205 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 + 206 304 static bool apple_match_product_name(void) 207 305 { 208 306 static const char type1_product_matches[][15] = { ··· 316 218 const struct efi_smbios_type1_record *record; 317 219 const u8 *product; 318 220 319 - record = (struct efi_smbios_type1_record *)efi_get_smbios_record(1); 221 + record = (struct efi_smbios_type1_record *) 222 + (efi_get_smbios_record(1) ?: get_table_record(1)); 320 223 if (!record) 321 224 return false; 322 225