Commit ab57bc6f authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'efi-fixes-for-v6.1-3' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi

Pull EFI fixes from Ard Biesheuvel:

 - Force the use of SetVirtualAddressMap() on Ampera Altra arm64
   machines, which crash in SetTime() if no virtual remapping is used

   This is the first time we've added an SMBIOS based quirk on arm64,
   but fortunately, we can just call a EFI protocol to grab the type #1
   SMBIOS record when running in the stub, so we don't need all the
   machinery we have in the kernel proper to parse SMBIOS data.

 - Drop a spurious warning on misaligned runtime regions when using 16k
   or 64k pages on arm64

* tag 'efi-fixes-for-v6.1-3' of git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi:
  arm64: efi: Fix handling of misaligned runtime regions and drop warning
  arm64: efi: Force the use of SetVirtualAddressMap() on Altra machines
parents fef7fd48 9b9eaee9
...@@ -13,6 +13,14 @@ ...@@ -13,6 +13,14 @@
#include <asm/efi.h> #include <asm/efi.h>
static bool region_is_misaligned(const efi_memory_desc_t *md)
{
if (PAGE_SIZE == EFI_PAGE_SIZE)
return false;
return !PAGE_ALIGNED(md->phys_addr) ||
!PAGE_ALIGNED(md->num_pages << EFI_PAGE_SHIFT);
}
/* /*
* Only regions of type EFI_RUNTIME_SERVICES_CODE need to be * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
* executable, everything else can be mapped with the XN bits * executable, everything else can be mapped with the XN bits
...@@ -26,14 +34,22 @@ static __init pteval_t create_mapping_protection(efi_memory_desc_t *md) ...@@ -26,14 +34,22 @@ static __init pteval_t create_mapping_protection(efi_memory_desc_t *md)
if (type == EFI_MEMORY_MAPPED_IO) if (type == EFI_MEMORY_MAPPED_IO)
return PROT_DEVICE_nGnRE; return PROT_DEVICE_nGnRE;
if (WARN_ONCE(!PAGE_ALIGNED(md->phys_addr), if (region_is_misaligned(md)) {
"UEFI Runtime regions are not aligned to 64 KB -- buggy firmware?")) static bool __initdata code_is_misaligned;
/* /*
* If the region is not aligned to the page size of the OS, we * Regions that are not aligned to the OS page size cannot be
* can not use strict permissions, since that would also affect * mapped with strict permissions, as those might interfere
* the mapping attributes of the adjacent regions. * with the permissions that are needed by the adjacent
* region's mapping. However, if we haven't encountered any
* misaligned runtime code regions so far, we can safely use
* non-executable permissions for non-code regions.
*/ */
return pgprot_val(PAGE_KERNEL_EXEC); code_is_misaligned |= (type == EFI_RUNTIME_SERVICES_CODE);
return code_is_misaligned ? pgprot_val(PAGE_KERNEL_EXEC)
: pgprot_val(PAGE_KERNEL);
}
/* R-- */ /* R-- */
if ((attr & (EFI_MEMORY_XP | EFI_MEMORY_RO)) == if ((attr & (EFI_MEMORY_XP | EFI_MEMORY_RO)) ==
...@@ -64,19 +80,16 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md) ...@@ -64,19 +80,16 @@ int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
bool page_mappings_only = (md->type == EFI_RUNTIME_SERVICES_CODE || bool page_mappings_only = (md->type == EFI_RUNTIME_SERVICES_CODE ||
md->type == EFI_RUNTIME_SERVICES_DATA); md->type == EFI_RUNTIME_SERVICES_DATA);
if (!PAGE_ALIGNED(md->phys_addr) ||
!PAGE_ALIGNED(md->num_pages << EFI_PAGE_SHIFT)) {
/* /*
* If the end address of this region is not aligned to page * If this region is not aligned to the page size used by the OS, the
* size, the mapping is rounded up, and may end up sharing a * mapping will be rounded outwards, and may end up sharing a page
* page frame with the next UEFI memory region. If we create * frame with an adjacent runtime memory region. Given that the page
* a block entry now, we may need to split it again when mapping * table descriptor covering the shared page will be rewritten when the
* the next region, and support for that is going to be removed * adjacent region gets mapped, we must avoid block mappings here so we
* from the MMU routines. So avoid block mappings altogether in * don't have to worry about splitting them when that happens.
* that case.
*/ */
if (region_is_misaligned(md))
page_mappings_only = true; page_mappings_only = true;
}
create_pgd_mapping(mm, md->phys_addr, md->virt_addr, create_pgd_mapping(mm, md->phys_addr, md->virt_addr,
md->num_pages << EFI_PAGE_SHIFT, md->num_pages << EFI_PAGE_SHIFT,
...@@ -103,6 +116,9 @@ int __init efi_set_mapping_permissions(struct mm_struct *mm, ...@@ -103,6 +116,9 @@ int __init efi_set_mapping_permissions(struct mm_struct *mm,
BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE && BUG_ON(md->type != EFI_RUNTIME_SERVICES_CODE &&
md->type != EFI_RUNTIME_SERVICES_DATA); md->type != EFI_RUNTIME_SERVICES_DATA);
if (region_is_misaligned(md))
return 0;
/* /*
* Calling apply_to_page_range() is only safe on regions that are * Calling apply_to_page_range() is only safe on regions that are
* guaranteed to be mapped down to pages. Since we are only called * guaranteed to be mapped down to pages. Since we are only called
......
...@@ -82,7 +82,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE ...@@ -82,7 +82,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o lib-$(CONFIG_EFI_GENERIC_STUB) += efi-stub.o string.o intrinsics.o systable.o
lib-$(CONFIG_ARM) += arm32-stub.o lib-$(CONFIG_ARM) += arm32-stub.o
lib-$(CONFIG_ARM64) += arm64-stub.o lib-$(CONFIG_ARM64) += arm64-stub.o smbios.o
lib-$(CONFIG_X86) += x86-stub.o lib-$(CONFIG_X86) += x86-stub.o
lib-$(CONFIG_RISCV) += riscv-stub.o lib-$(CONFIG_RISCV) += riscv-stub.o
lib-$(CONFIG_LOONGARCH) += loongarch-stub.o lib-$(CONFIG_LOONGARCH) += loongarch-stub.o
......
...@@ -15,6 +15,21 @@ ...@@ -15,6 +15,21 @@
#include "efistub.h" #include "efistub.h"
static bool system_needs_vamap(void)
{
const u8 *type1_family = efi_get_smbios_string(1, family);
/*
* Ampere Altra machines crash in SetTime() if SetVirtualAddressMap()
* has not been called prior.
*/
if (!type1_family || strcmp(type1_family, "Altra"))
return false;
efi_warn("Working around broken SetVirtualAddressMap()\n");
return true;
}
efi_status_t check_platform_features(void) efi_status_t check_platform_features(void)
{ {
u64 tg; u64 tg;
...@@ -24,7 +39,7 @@ efi_status_t check_platform_features(void) ...@@ -24,7 +39,7 @@ efi_status_t check_platform_features(void)
* UEFI runtime regions 1:1 and so calling SetVirtualAddressMap() is * UEFI runtime regions 1:1 and so calling SetVirtualAddressMap() is
* unnecessary. * unnecessary.
*/ */
if (VA_BITS_MIN >= 48) if (VA_BITS_MIN >= 48 && !system_needs_vamap())
efi_novamap = true; efi_novamap = true;
/* UEFI mandates support for 4 KB granularity, no need to check */ /* UEFI mandates support for 4 KB granularity, no need to check */
......
...@@ -975,4 +975,32 @@ efi_enable_reset_attack_mitigation(void) { } ...@@ -975,4 +975,32 @@ efi_enable_reset_attack_mitigation(void) { }
void efi_retrieve_tpm2_eventlog(void); void efi_retrieve_tpm2_eventlog(void);
struct efi_smbios_record {
u8 type;
u8 length;
u16 handle;
};
struct efi_smbios_type1_record {
struct efi_smbios_record header;
u8 manufacturer;
u8 product_name;
u8 version;
u8 serial_number;
efi_guid_t uuid;
u8 wakeup_type;
u8 sku_number;
u8 family;
};
#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, \
__name); \
__efi_get_smbios_string(__type, off, size); \
})
const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize);
#endif #endif
// SPDX-License-Identifier: GPL-2.0-only
// Copyright 2022 Google LLC
// Author: Ard Biesheuvel <ardb@google.com>
#include <linux/efi.h>
#include "efistub.h"
typedef struct efi_smbios_protocol efi_smbios_protocol_t;
struct efi_smbios_protocol {
efi_status_t (__efiapi *add)(efi_smbios_protocol_t *, efi_handle_t,
u16 *, struct efi_smbios_record *);
efi_status_t (__efiapi *update_string)(efi_smbios_protocol_t *, u16 *,
unsigned long *, u8 *);
efi_status_t (__efiapi *remove)(efi_smbios_protocol_t *, u16);
efi_status_t (__efiapi *get_next)(efi_smbios_protocol_t *, u16 *, u8 *,
struct efi_smbios_record **,
efi_handle_t *);
u8 major_version;
u8 minor_version;
};
const u8 *__efi_get_smbios_string(u8 type, int offset, int recsize)
{
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;
strtable = (u8 *)record + recsize;
for (int i = 1; i < ((u8 *)record)[offset]; i++) {
int len = strlen(strtable);
if (!len)
return NULL;
strtable += len + 1;
}
return strtable;
}
...@@ -389,6 +389,7 @@ void efi_native_runtime_setup(void); ...@@ -389,6 +389,7 @@ void efi_native_runtime_setup(void);
#define EFI_LOAD_FILE2_PROTOCOL_GUID EFI_GUID(0x4006c0c1, 0xfcb3, 0x403e, 0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d) #define EFI_LOAD_FILE2_PROTOCOL_GUID EFI_GUID(0x4006c0c1, 0xfcb3, 0x403e, 0x99, 0x6d, 0x4a, 0x6c, 0x87, 0x24, 0xe0, 0x6d)
#define EFI_RT_PROPERTIES_TABLE_GUID EFI_GUID(0xeb66918a, 0x7eef, 0x402a, 0x84, 0x2e, 0x93, 0x1d, 0x21, 0xc3, 0x8a, 0xe9) #define EFI_RT_PROPERTIES_TABLE_GUID EFI_GUID(0xeb66918a, 0x7eef, 0x402a, 0x84, 0x2e, 0x93, 0x1d, 0x21, 0xc3, 0x8a, 0xe9)
#define EFI_DXE_SERVICES_TABLE_GUID EFI_GUID(0x05ad34ba, 0x6f02, 0x4214, 0x95, 0x2e, 0x4d, 0xa0, 0x39, 0x8e, 0x2b, 0xb9) #define EFI_DXE_SERVICES_TABLE_GUID EFI_GUID(0x05ad34ba, 0x6f02, 0x4214, 0x95, 0x2e, 0x4d, 0xa0, 0x39, 0x8e, 0x2b, 0xb9)
#define EFI_SMBIOS_PROTOCOL_GUID EFI_GUID(0x03583ff6, 0xcb36, 0x4940, 0x94, 0x7e, 0xb9, 0xb3, 0x9f, 0x4a, 0xfa, 0xf7)
#define EFI_IMAGE_SECURITY_DATABASE_GUID EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f) #define EFI_IMAGE_SECURITY_DATABASE_GUID EFI_GUID(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
#define EFI_SHIM_LOCK_GUID EFI_GUID(0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23) #define EFI_SHIM_LOCK_GUID EFI_GUID(0x605dab50, 0xe046, 0x4300, 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment