From: Ard Biesheuvel <ardb@kernel.org>
Date: Tue, 28 Feb 2023 17:00:49 +0100
Subject: arm64: efi: Use SMBIOS processor ID to key off Altra quirk
Git-repo: https://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git#urgent
Git-commit: 22d9e53df5aa26f775d96222fbb049569720349f
Patch-mainline: Queued in subsystem maintainer repository
References: bsc#1208750
Instead of using the SMBIOS type 1 record 'family' field, which is often
modified by OEMs, use the type 4 'processor ID' field, which is always
set to the same value on all known Altra EFI systems in the field, and
is more likely to be left alone, given that it is based on the SOC id
SMCCC API call which is implemented in secure firmware.
Fixes: 550b33cfd4452968 ("arm64: efi: Force the use of ...")
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
drivers/firmware/efi/libstub/arm64.c | 12 +++++------
drivers/firmware/efi/libstub/efistub.h | 34 +++++++++++++++++++++++++++++++++
drivers/firmware/efi/libstub/smbios.c | 14 +++++++++++--
3 files changed, 52 insertions(+), 8 deletions(-)
--- a/drivers/firmware/efi/libstub/arm64.c
+++ b/drivers/firmware/efi/libstub/arm64.c
@@ -16,16 +16,16 @@
static bool system_needs_vamap(void)
{
- const u8 *type1_family = efi_get_smbios_string(1, family);
+ const struct efi_smbios_type4_record *record;
/*
* Ampere eMAG, Altra, and Altra Max machines crash in SetTime() if
- * SetVirtualAddressMap() has not been called prior.
+ * SetVirtualAddressMap() has not been called prior. These systems can
+ * be identified by the SMCCC soc ID, which is conveniently exposed via
+ * the type 4 SMBIOS records.
*/
- if (!type1_family || (
- strcmp(type1_family, "eMAG") &&
- strcmp(type1_family, "Altra") &&
- strcmp(type1_family, "Altra Max")))
+ record = (struct efi_smbios_type4_record *)efi_get_smbios_record(4);
+ if (!record || memcmp(record->processor_id, "\x1\0\x16\xA\xA1\0\0\0", 8))
return false;
efi_warn("Working around broken SetVirtualAddressMap()\n");
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -1054,6 +1054,8 @@ struct efi_smbios_record {
u16 handle;
};
+const struct efi_smbios_record *efi_get_smbios_record(u8 type);
+
struct efi_smbios_type1_record {
struct efi_smbios_record header;
@@ -1067,6 +1069,38 @@ struct efi_smbios_type1_record {
u8 family;
};
+struct efi_smbios_type4_record {
+ struct efi_smbios_record header;
+
+ u8 socket;
+ u8 processor_type;
+ u8 processor_family;
+ u8 processor_manufacturer;
+ u8 processor_id[8];
+ u8 processor_version;
+ u8 voltage;
+ u16 external_clock;
+ u16 max_speed;
+ u16 current_speed;
+ u8 status;
+ u8 processor_upgrade;
+ u16 l1_cache_handle;
+ u16 l2_cache_handle;
+ u16 l3_cache_handle;
+ u8 serial_number;
+ u8 asset_tag;
+ u8 part_number;
+ u8 core_count;
+ u8 enabled_core_count;
+ u8 thread_count;
+ u16 processor_characteristics;
+ u16 processor_family2;
+ u16 core_count2;
+ u16 enabled_core_count2;
+ u16 thread_count2;
+ u16 thread_enabled;
+};
+
#define efi_get_smbios_string(__type, __name) ({ \
int size = sizeof(struct efi_smbios_type ## __type ## _record); \
int off = offsetof(struct efi_smbios_type ## __type ## _record, \
--- a/drivers/firmware/efi/libstub/smbios.c
+++ b/drivers/firmware/efi/libstub/smbios.c
@@ -22,19 +22,29 @@ struct efi_smbios_protocol {
u8 minor_version;
};
-const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize)
+const struct efi_smbios_record *efi_get_smbios_record(u8 type)
{
struct efi_smbios_record *record;
efi_smbios_protocol_t *smbios;
efi_status_t status;
u16 handle = 0xfffe;
- const u8 *strtable;
status = efi_bs_call(locate_protocol, &EFI_SMBIOS_PROTOCOL_GUID, NULL,
(void **)&smbios) ?:
efi_call_proto(smbios, get_next, &handle, &type, &record, NULL);
if (status != EFI_SUCCESS)
return NULL;
+ return record;
+}
+
+const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize)
+{
+ const struct efi_smbios_record *record;
+ const u8 *strtable;
+
+ record = efi_get_smbios_record(type);
+ if (!record)
+ return NULL;
strtable = (u8 *)record + recsize;
for (int i = 1; i < ((u8 *)record)[offset]; i++) {