Skip to content

Commit 550b33c

Browse files
committed
arm64: efi: Force the use of SetVirtualAddressMap() on Altra machines
Ampere Altra machines are reported to misbehave when the SetTime() EFI runtime service is called after ExitBootServices() but before calling SetVirtualAddressMap(). Given that the latter is horrid, pointless and explicitly documented as optional by the EFI spec, we no longer invoke it at boot if the configured size of the VA space guarantees that the EFI runtime memory regions can remain mapped 1:1 like they are at boot time. On Ampere Altra machines, this results in SetTime() calls issued by the rtc-efi driver triggering synchronous exceptions during boot. We can now recover from those without bringing down the system entirely, due to commit 23715a2 ("arm64: efi: Recover from synchronous exceptions occurring in firmware"). However, it would be better to avoid the issue entirely, given that the firmware appears to remain in a funny state after this. So attempt to identify these machines based on the 'family' field in the type #1 SMBIOS record, and call SetVirtualAddressMap() unconditionally in that case. Tested-by: Alexandru Elisei <[email protected]> Signed-off-by: Ard Biesheuvel <[email protected]>
1 parent 23715a2 commit 550b33c

File tree

5 files changed

+94
-2
lines changed

5 files changed

+94
-2
lines changed

drivers/firmware/efi/libstub/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
8282
lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o
8383

8484
lib-$(CONFIG_ARM) += arm32-stub.o
85-
lib-$(CONFIG_ARM64) += arm64-stub.o
85+
lib-$(CONFIG_ARM64) += arm64-stub.o smbios.o
8686
lib-$(CONFIG_X86) += x86-stub.o
8787
lib-$(CONFIG_RISCV) += riscv-stub.o
8888
lib-$(CONFIG_LOONGARCH) += loongarch-stub.o

drivers/firmware/efi/libstub/arm64-stub.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,21 @@
1515

1616
#include "efistub.h"
1717

18+
static bool system_needs_vamap(void)
19+
{
20+
const u8 *type1_family = efi_get_smbios_string(1, family);
21+
22+
/*
23+
* Ampere Altra machines crash in SetTime() if SetVirtualAddressMap()
24+
* has not been called prior.
25+
*/
26+
if (!type1_family || strcmp(type1_family, "Altra"))
27+
return false;
28+
29+
efi_warn("Working around broken SetVirtualAddressMap()\n");
30+
return true;
31+
}
32+
1833
efi_status_t check_platform_features(void)
1934
{
2035
u64 tg;
@@ -24,7 +39,7 @@ efi_status_t check_platform_features(void)
2439
* UEFI runtime regions 1:1 and so calling SetVirtualAddressMap() is
2540
* unnecessary.
2641
*/
27-
if (VA_BITS_MIN >= 48)
42+
if (VA_BITS_MIN >= 48 && !system_needs_vamap())
2843
efi_novamap = true;
2944

3045
/* UEFI mandates support for 4 KB granularity, no need to check */

drivers/firmware/efi/libstub/efistub.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,4 +975,32 @@ efi_enable_reset_attack_mitigation(void) { }
975975

976976
void efi_retrieve_tpm2_eventlog(void);
977977

978+
struct efi_smbios_record {
979+
u8 type;
980+
u8 length;
981+
u16 handle;
982+
};
983+
984+
struct efi_smbios_type1_record {
985+
struct efi_smbios_record header;
986+
987+
u8 manufacturer;
988+
u8 product_name;
989+
u8 version;
990+
u8 serial_number;
991+
efi_guid_t uuid;
992+
u8 wakeup_type;
993+
u8 sku_number;
994+
u8 family;
995+
};
996+
997+
#define efi_get_smbios_string(__type, __name) ({ \
998+
int size = sizeof(struct efi_smbios_type ## __type ## _record); \
999+
int off = offsetof(struct efi_smbios_type ## __type ## _record, \
1000+
__name); \
1001+
__efi_get_smbios_string(__type, off, size); \
1002+
})
1003+
1004+
const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize);
1005+
9781006
#endif

drivers/firmware/efi/libstub/smbios.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
// Copyright 2022 Google LLC
3+
// Author: Ard Biesheuvel <[email protected]>
4+
5+
#include <linux/efi.h>
6+
7+
#include "efistub.h"
8+
9+
typedef struct efi_smbios_protocol efi_smbios_protocol_t;
10+
11+
struct efi_smbios_protocol {
12+
efi_status_t (__efiapi *add)(efi_smbios_protocol_t *, efi_handle_t,
13+
u16 *, struct efi_smbios_record *);
14+
efi_status_t (__efiapi *update_string)(efi_smbios_protocol_t *, u16 *,
15+
unsigned long *, u8 *);
16+
efi_status_t (__efiapi *remove)(efi_smbios_protocol_t *, u16);
17+
efi_status_t (__efiapi *get_next)(efi_smbios_protocol_t *, u16 *, u8 *,
18+
struct efi_smbios_record **,
19+
efi_handle_t *);
20+
21+
u8 major_version;
22+
u8 minor_version;
23+
};
24+
25+
const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize)
26+
{
27+
struct efi_smbios_record *record;
28+
efi_smbios_protocol_t *smbios;
29+
efi_status_t status;
30+
u16 handle = 0xfffe;
31+
const u8 *strtable;
32+
33+
status = efi_bs_call(locate_protocol, &EFI_SMBIOS_PROTOCOL_GUID, NULL,
34+
(void **)&smbios) ?:
35+
efi_call_proto(smbios, get_next, &handle, &type, &record, NULL);
36+
if (status != EFI_SUCCESS)
37+
return NULL;
38+
39+
strtable = (u8 *)record + recsize;
40+
for (int i = 1; i < ((u8 *)record)[offset]; i++) {
41+
int len = strlen(strtable);
42+
43+
if (!len)
44+
return NULL;
45+
strtable += len + 1;
46+
}
47+
return strtable;
48+
}

include/linux/efi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,7 @@ void efi_native_runtime_setup(void);
389389
#define EFI_LOAD_FILE2_PROTOCOL_GUID EFI_GUID(0x4006c0c1, 0xfcb3, 0x403e, 0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d)
390390
#define EFI_RT_PROPERTIES_TABLE_GUID EFI_GUID(0xeb66918a, 0x7eef, 0x402a, 0x84, 0x2e, 0x93, 0x1d, 0x21, 0xc3, 0x8a, 0xe9)
391391
#define EFI_DXE_SERVICES_TABLE_GUID EFI_GUID(0x05ad34ba, 0x6f02, 0x4214, 0x95, 0x2e, 0x4d, 0xa0, 0x39, 0x8e, 0x2b, 0xb9)
392+
#define EFI_SMBIOS_PROTOCOL_GUID EFI_GUID(0x03583ff6, 0xcb36, 0x4940, 0x94, 0x7e, 0xb9, 0xb3, 0x9f, 0x4a, 0xfa, 0xf7)
392393

393394
#define EFI_IMAGE_SECURITY_DATABASE_GUID EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
394395
#define EFI_SHIM_LOCK_GUID EFI_GUID(0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)

0 commit comments

Comments
 (0)