forked from Minki/linux
Third batch of EFI fixes for v6.1
- Force the use of SetVirtualAddressMap() on Ampera Altra arm64 machines, which crash in SetTime() if no virtual remapping is used - Drop a spurious warning on misaligned runtime regions when using 16k or 64k pages on arm64 -----BEGIN PGP SIGNATURE----- iQGzBAABCgAdFiEE+9lifEBpyUIVN1cpw08iOZLZjyQFAmNvduwACgkQw08iOZLZ jySmkgv9GTFJUWJY1JWsQZf2OB+Ui2JAVCPJVbLGzDxWEFY/z+mgAcC6rJ6+T0Ju 9fNNBnFXeSq5bOPqGFcBOsLxHcP1KpNQHNKHjFUv9RovQGiMD29Fl3kT8XiuqtsB SJcilTJs+J6umBOX+yQ1oho0P5eq/LkvDW3AFxzxrHAl/k9U0eePLIBAgIXS8Iuf wZP3b2Bqt0z9b6JBFBKmXlLTC1WGdoVPmcXc2n+6O3c4MxUrZnbDk9Ou8vA1sCy5 JO4GlU0qvHercsZwcRRcdsKeQPpXIeDDOklUkicxsuYVhi7ipIfLdYsMwFkxGp22 IhXfxfV8OyJm71uD4z7EJAIgZibG86UQlh3Lib5846xYAGbZiUx3CaiiPBgHXgeV PUy4FtYPlf0u8epC2QWKC3FGRIpkcAVwmZPnNvXV+NFg1wzd2B1dGFJajvCKfW93 joBsdWLUZABj5bNtSyLlaswT6gHt58w6PkHaqwi3mQaZs0oNt01iLbZCMy33y4A+ +jhAY/FE =sWO/ -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
ab57bc6f02
@ -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)
|
|||||||
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)
|
|||||||
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 this region is not aligned to the page size used by the OS, the
|
||||||
/*
|
* mapping will be rounded outwards, and may end up sharing a page
|
||||||
* If the end address of this region is not aligned to page
|
* frame with an adjacent runtime memory region. Given that the page
|
||||||
* size, the mapping is rounded up, and may end up sharing a
|
* table descriptor covering the shared page will be rewritten when the
|
||||||
* page frame with the next UEFI memory region. If we create
|
* adjacent region gets mapped, we must avoid block mappings here so we
|
||||||
* a block entry now, we may need to split it again when mapping
|
* don't have to worry about splitting them when that happens.
|
||||||
* the next region, and support for that is going to be removed
|
*/
|
||||||
* from the MMU routines. So avoid block mappings altogether in
|
if (region_is_misaligned(md))
|
||||||
* that case.
|
|
||||||
*/
|
|
||||||
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,
|
|||||||
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
|
|||||||
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 @@
|
|||||||
|
|
||||||
#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)
|
|||||||
* 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) { }
|
|||||||
|
|
||||||
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
|
||||||
|
48
drivers/firmware/efi/libstub/smbios.c
Normal file
48
drivers/firmware/efi/libstub/smbios.c
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// 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);
|
|||||||
#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)
|
||||||
|
Loading…
Reference in New Issue
Block a user