On Wed, Jun 07, 2023 at 05:26:12AM -0700, Ard Biesheuvel wrote:
[ Upstream commit eb684408f3ea4856639675d6465f0024e498e4b1 ]
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: 550b33cfd4452968 ("arm64: efi: Force the use of ...") Tested-by: Andrea Righi andrea.righi@canonical.com Signed-off-by: Ard Biesheuvel ardb@kernel.org Signed-off-by: Sasha Levin sashal@kernel.org
Where did Sasha sign off on this?
Signed-off-by: Jeremi Piotrowski jpiotrowski@linux.microsoft.com
drivers/firmware/efi/libstub/arm64-stub.c | 39 ++++++++++++++++----- drivers/firmware/efi/libstub/efistub.h | 41 +++++++++++++++++++++-- drivers/firmware/efi/libstub/smbios.c | 13 +++++-- 3 files changed, 80 insertions(+), 13 deletions(-)
diff --git a/drivers/firmware/efi/libstub/arm64-stub.c b/drivers/firmware/efi/libstub/arm64-stub.c index 42282c5c3fe6..e2f90566b291 100644 --- a/drivers/firmware/efi/libstub/arm64-stub.c +++ b/drivers/firmware/efi/libstub/arm64-stub.c @@ -17,20 +17,43 @@ static bool system_needs_vamap(void) {
- const u8 *type1_family = efi_get_smbios_string(1, family);
- const struct efi_smbios_type4_record *record;
- const u32 __aligned(1) *socid;
- const u8 *version;
/* * Ampere eMAG, Altra, and Altra Max machines crash in SetTime() if
* SetVirtualAddressMap() has not been called prior.
* SetVirtualAddressMap() has not been called prior. Most Altra systems
* can be identified by the SMCCC soc ID, which is conveniently exposed
* via the type 4 SMBIOS records. Otherwise, test the processor version
* field. eMAG systems all appear to have the processor version field
*/* set to "eMAG".
- 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) return false;
- efi_warn("Working around broken SetVirtualAddressMap()\n");
- return true;
- socid = (u32 *)record->processor_id;
- switch (*socid & 0xffff000f) {
static char const altra[] = "Ampere(TM) Altra(TM) Processor";
static char const emag[] = "eMAG";
- default:
version = efi_get_smbios_string(&record->header, 4,
processor_version);
if (!version || (strncmp(version, altra, sizeof(altra) - 1) &&
strncmp(version, emag, sizeof(emag) - 1)))
break;
fallthrough;
- case 0x0a160001: // Altra
- case 0x0a160002: // Altra Max
efi_warn("Working around broken SetVirtualAddressMap()\n");
return true;
- }
- return false;
} efi_status_t check_platform_features(void) diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index 900df67a2078..970e86e3aab0 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -983,6 +983,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; @@ -996,13 +998,46 @@ struct efi_smbios_type1_record { u8 family; }; -#define efi_get_smbios_string(__type, __name) ({ \ +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(__record, __type, __name) ({ \ int size = sizeof(struct efi_smbios_type ## __type ## _record); \ int off = offsetof(struct efi_smbios_type ## __type ## _record, \ __name); \
- __efi_get_smbios_string(__type, off, size); \
- __efi_get_smbios_string((__record), __type, off, size); \
}) -const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize); +const u8 *__efi_get_smbios_string(const struct efi_smbios_record *record,
u8 type, int offset, int recsize);
#endif diff --git a/drivers/firmware/efi/libstub/smbios.c b/drivers/firmware/efi/libstub/smbios.c index aadb422b9637..f9c159c28f46 100644 --- a/drivers/firmware/efi/libstub/smbios.c +++ b/drivers/firmware/efi/libstub/smbios.c @@ -22,19 +22,28 @@ 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(const struct efi_smbios_record *record,
u8 type, int offset, int recsize)
+{
- const u8 *strtable;
- if (!record)
return NULL;
strtable = (u8 *)record + record->length; for (int i = 1; i < ((u8 *)record)[offset]; i++) { -- 2.30.2