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