Skip to content

Commit eb68440

Browse files
committed
arm64: efi: Use SMBIOS processor version to key off Ampere quirk
Instead of using the SMBIOS type 1 record 'family' field, which is often modified by OEMs, use the type 4 'processor ID' and 'processor version' fields, which are set to a small set of probe-able values on all known Ampere EFI systems in the field. Fixes: 550b33c ("arm64: efi: Force the use of ...") Tested-by: Andrea Righi <[email protected]> Signed-off-by: Ard Biesheuvel <[email protected]>
1 parent 34343eb commit eb68440

File tree

3 files changed

+80
-13
lines changed

3 files changed

+80
-13
lines changed

drivers/firmware/efi/libstub/arm64.c

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,43 @@
1616

1717
static bool system_needs_vamap(void)
1818
{
19-
const u8 *type1_family = efi_get_smbios_string(1, family);
19+
const struct efi_smbios_type4_record *record;
20+
const u32 __aligned(1) *socid;
21+
const u8 *version;
2022

2123
/*
2224
* Ampere eMAG, Altra, and Altra Max machines crash in SetTime() if
23-
* SetVirtualAddressMap() has not been called prior.
25+
* SetVirtualAddressMap() has not been called prior. Most Altra systems
26+
* can be identified by the SMCCC soc ID, which is conveniently exposed
27+
* via the type 4 SMBIOS records. Otherwise, test the processor version
28+
* field. eMAG systems all appear to have the processor version field
29+
* set to "eMAG".
2430
*/
25-
if (!type1_family || (
26-
strcmp(type1_family, "eMAG") &&
27-
strcmp(type1_family, "Altra") &&
28-
strcmp(type1_family, "Altra Max")))
31+
record = (struct efi_smbios_type4_record *)efi_get_smbios_record(4);
32+
if (!record)
2933
return false;
3034

31-
efi_warn("Working around broken SetVirtualAddressMap()\n");
32-
return true;
35+
socid = (u32 *)record->processor_id;
36+
switch (*socid & 0xffff000f) {
37+
static char const altra[] = "Ampere(TM) Altra(TM) Processor";
38+
static char const emag[] = "eMAG";
39+
40+
default:
41+
version = efi_get_smbios_string(&record->header, 4,
42+
processor_version);
43+
if (!version || (strncmp(version, altra, sizeof(altra) - 1) &&
44+
strncmp(version, emag, sizeof(emag) - 1)))
45+
break;
46+
47+
fallthrough;
48+
49+
case 0x0a160001: // Altra
50+
case 0x0a160002: // Altra Max
51+
efi_warn("Working around broken SetVirtualAddressMap()\n");
52+
return true;
53+
}
54+
55+
return false;
3356
}
3457

3558
efi_status_t check_platform_features(void)

drivers/firmware/efi/libstub/efistub.h

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,6 +1074,8 @@ struct efi_smbios_record {
10741074
u16 handle;
10751075
};
10761076

1077+
const struct efi_smbios_record *efi_get_smbios_record(u8 type);
1078+
10771079
struct efi_smbios_type1_record {
10781080
struct efi_smbios_record header;
10791081

@@ -1087,14 +1089,47 @@ struct efi_smbios_type1_record {
10871089
u8 family;
10881090
};
10891091

1090-
#define efi_get_smbios_string(__type, __name) ({ \
1092+
struct efi_smbios_type4_record {
1093+
struct efi_smbios_record header;
1094+
1095+
u8 socket;
1096+
u8 processor_type;
1097+
u8 processor_family;
1098+
u8 processor_manufacturer;
1099+
u8 processor_id[8];
1100+
u8 processor_version;
1101+
u8 voltage;
1102+
u16 external_clock;
1103+
u16 max_speed;
1104+
u16 current_speed;
1105+
u8 status;
1106+
u8 processor_upgrade;
1107+
u16 l1_cache_handle;
1108+
u16 l2_cache_handle;
1109+
u16 l3_cache_handle;
1110+
u8 serial_number;
1111+
u8 asset_tag;
1112+
u8 part_number;
1113+
u8 core_count;
1114+
u8 enabled_core_count;
1115+
u8 thread_count;
1116+
u16 processor_characteristics;
1117+
u16 processor_family2;
1118+
u16 core_count2;
1119+
u16 enabled_core_count2;
1120+
u16 thread_count2;
1121+
u16 thread_enabled;
1122+
};
1123+
1124+
#define efi_get_smbios_string(__record, __type, __name) ({ \
10911125
int size = sizeof(struct efi_smbios_type ## __type ## _record); \
10921126
int off = offsetof(struct efi_smbios_type ## __type ## _record, \
10931127
__name); \
1094-
__efi_get_smbios_string(__type, off, size); \
1128+
__efi_get_smbios_string((__record), __type, off, size); \
10951129
})
10961130

1097-
const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize);
1131+
const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
1132+
u8 type, int offset, int recsize);
10981133

10991134
void efi_remap_image(unsigned long image_base, unsigned alloc_size,
11001135
unsigned long code_size);

drivers/firmware/efi/libstub/smbios.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,28 @@ struct efi_smbios_protocol {
2222
u8 minor_version;
2323
};
2424

25-
const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize)
25+
const struct efi_smbios_record *efi_get_smbios_record(u8 type)
2626
{
2727
struct efi_smbios_record *record;
2828
efi_smbios_protocol_t *smbios;
2929
efi_status_t status;
3030
u16 handle = 0xfffe;
31-
const u8 *strtable;
3231

3332
status = efi_bs_call(locate_protocol, &EFI_SMBIOS_PROTOCOL_GUID, NULL,
3433
(void **)&smbios) ?:
3534
efi_call_proto(smbios, get_next, &handle, &type, &record, NULL);
3635
if (status != EFI_SUCCESS)
3736
return NULL;
37+
return record;
38+
}
39+
40+
const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
41+
u8 type, int offset, int recsize)
42+
{
43+
const u8 *strtable;
44+
45+
if (!record)
46+
return NULL;
3847

3948
strtable = (u8 *)record + record->length;
4049
for (int i = 1; i < ((u8 *)record)[offset]; i++) {

0 commit comments

Comments
 (0)