2019-02-02 17:41:15 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2015-11-30 20:28:18 +08:00
|
|
|
/*
|
|
|
|
* Extensible Firmware Interface
|
|
|
|
*
|
|
|
|
* Based on Extensible Firmware Interface Specification version 2.4
|
|
|
|
*
|
|
|
|
* Copyright (C) 2013 - 2015 Linaro Ltd.
|
|
|
|
*/
|
|
|
|
|
2016-04-26 04:06:53 +08:00
|
|
|
#define pr_fmt(fmt) "efi: " fmt
|
|
|
|
|
2015-11-30 20:28:18 +08:00
|
|
|
#include <linux/efi.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/memblock.h>
|
|
|
|
#include <linux/mm_types.h>
|
|
|
|
#include <linux/of.h>
|
|
|
|
#include <linux/of_fdt.h>
|
2016-04-26 04:06:55 +08:00
|
|
|
#include <linux/platform_device.h>
|
2016-04-26 04:06:53 +08:00
|
|
|
#include <linux/screen_info.h>
|
2015-11-30 20:28:18 +08:00
|
|
|
|
|
|
|
#include <asm/efi.h>
|
|
|
|
|
|
|
|
u64 efi_system_table;
|
|
|
|
|
efi/arm64: Treat regions with WT/WC set but WB cleared as memory
Currently, memory regions are only recorded in the memblock memory table
if they have the EFI_MEMORY_WB memory type attribute set. In case the
region is of a reserved type, it is also marked as MEMBLOCK_NOMAP, which
will leave it out of the linear mapping.
However, memory regions may legally have the EFI_MEMORY_WT or EFI_MEMORY_WC
attributes set, and the EFI_MEMORY_WB cleared, in which case the region in
question is obviously backed by normal memory, but is not recorded in the
memblock memory table at all. Since it would be useful to be able to
identify any UEFI reported memory region using memblock_is_memory(), it
makes sense to add all memory to the memblock memory table, and simply mark
it as MEMBLOCK_NOMAP if it lacks the EFI_MEMORY_WB attribute.
While implementing this, let's refactor the code slightly to make it easier
to understand: replace is_normal_ram() with is_memory(), and make it return
true for each region that has any of the WB|WT|WC bits set. (This follows
the AArch64 bindings in the UEFI spec, which state that those are the
attributes that map to normal memory)
Also, replace is_reserve_region() with is_usable_memory(), and only invoke
it if the region in question was identified as memory by is_memory() in the
first place. The net result is the same (only reserved regions that are
backed by memory end up in the memblock memory table with the MEMBLOCK_NOMAP
flag set) but carried out in a more straightforward way.
Finally, we remove the trailing asterisk in the EFI debug output. Keeping it
clutters the code, and it serves no real purpose now that we no longer
temporarily reserve BootServices code and data regions like we did in the
early days of EFI support on arm64 Linux (which it inherited from the x86
implementation)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
Tested-by: James Morse <james.morse@arm.com>
Reviewed-by: James Morse <james.morse@arm.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
2016-08-26 00:17:09 +08:00
|
|
|
static int __init is_memory(efi_memory_desc_t *md)
|
2015-11-30 20:28:18 +08:00
|
|
|
{
|
efi/arm64: Treat regions with WT/WC set but WB cleared as memory
Currently, memory regions are only recorded in the memblock memory table
if they have the EFI_MEMORY_WB memory type attribute set. In case the
region is of a reserved type, it is also marked as MEMBLOCK_NOMAP, which
will leave it out of the linear mapping.
However, memory regions may legally have the EFI_MEMORY_WT or EFI_MEMORY_WC
attributes set, and the EFI_MEMORY_WB cleared, in which case the region in
question is obviously backed by normal memory, but is not recorded in the
memblock memory table at all. Since it would be useful to be able to
identify any UEFI reported memory region using memblock_is_memory(), it
makes sense to add all memory to the memblock memory table, and simply mark
it as MEMBLOCK_NOMAP if it lacks the EFI_MEMORY_WB attribute.
While implementing this, let's refactor the code slightly to make it easier
to understand: replace is_normal_ram() with is_memory(), and make it return
true for each region that has any of the WB|WT|WC bits set. (This follows
the AArch64 bindings in the UEFI spec, which state that those are the
attributes that map to normal memory)
Also, replace is_reserve_region() with is_usable_memory(), and only invoke
it if the region in question was identified as memory by is_memory() in the
first place. The net result is the same (only reserved regions that are
backed by memory end up in the memblock memory table with the MEMBLOCK_NOMAP
flag set) but carried out in a more straightforward way.
Finally, we remove the trailing asterisk in the EFI debug output. Keeping it
clutters the code, and it serves no real purpose now that we no longer
temporarily reserve BootServices code and data regions like we did in the
early days of EFI support on arm64 Linux (which it inherited from the x86
implementation)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
Tested-by: James Morse <james.morse@arm.com>
Reviewed-by: James Morse <james.morse@arm.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
2016-08-26 00:17:09 +08:00
|
|
|
if (md->attribute & (EFI_MEMORY_WB|EFI_MEMORY_WT|EFI_MEMORY_WC))
|
2015-11-30 20:28:18 +08:00
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Translate a EFI virtual address into a physical address: this is necessary,
|
|
|
|
* as some data members of the EFI system table are virtually remapped after
|
|
|
|
* SetVirtualAddressMap() has been called.
|
|
|
|
*/
|
|
|
|
static phys_addr_t efi_to_phys(unsigned long addr)
|
|
|
|
{
|
|
|
|
efi_memory_desc_t *md;
|
|
|
|
|
2016-04-26 04:06:39 +08:00
|
|
|
for_each_efi_memory_desc(md) {
|
2015-11-30 20:28:18 +08:00
|
|
|
if (!(md->attribute & EFI_MEMORY_RUNTIME))
|
|
|
|
continue;
|
|
|
|
if (md->virt_addr == 0)
|
|
|
|
/* no virtual mapping has been installed by the stub */
|
|
|
|
break;
|
|
|
|
if (md->virt_addr <= addr &&
|
|
|
|
(addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT))
|
|
|
|
return md->phys_addr + addr - md->virt_addr;
|
|
|
|
}
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
2016-04-26 04:06:53 +08:00
|
|
|
static __initdata unsigned long screen_info_table = EFI_INVALID_TABLE_ADDR;
|
|
|
|
|
|
|
|
static __initdata efi_config_table_type_t arch_tables[] = {
|
|
|
|
{LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID, NULL, &screen_info_table},
|
|
|
|
{NULL_GUID, NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static void __init init_screen_info(void)
|
|
|
|
{
|
|
|
|
struct screen_info *si;
|
|
|
|
|
|
|
|
if (screen_info_table != EFI_INVALID_TABLE_ADDR) {
|
|
|
|
si = early_memremap_ro(screen_info_table, sizeof(*si));
|
|
|
|
if (!si) {
|
|
|
|
pr_err("Could not map screen_info config table\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
screen_info = *si;
|
|
|
|
early_memunmap(si, sizeof(*si));
|
|
|
|
|
|
|
|
/* dummycon on ARM needs non-zero values for columns/lines */
|
|
|
|
screen_info.orig_video_cols = 80;
|
|
|
|
screen_info.orig_video_lines = 25;
|
|
|
|
}
|
2016-04-26 04:06:55 +08:00
|
|
|
|
|
|
|
if (screen_info.orig_video_isVGA == VIDEO_TYPE_EFI &&
|
|
|
|
memblock_is_map_memory(screen_info.lfb_base))
|
|
|
|
memblock_mark_nomap(screen_info.lfb_base, screen_info.lfb_size);
|
2016-04-26 04:06:53 +08:00
|
|
|
}
|
|
|
|
|
2015-11-30 20:28:18 +08:00
|
|
|
static int __init uefi_init(void)
|
|
|
|
{
|
|
|
|
efi_char16_t *c16;
|
|
|
|
void *config_tables;
|
2015-11-30 20:28:19 +08:00
|
|
|
size_t table_size;
|
2015-11-30 20:28:18 +08:00
|
|
|
char vendor[100] = "unknown";
|
|
|
|
int i, retval;
|
|
|
|
|
2016-02-17 20:36:00 +08:00
|
|
|
efi.systab = early_memremap_ro(efi_system_table,
|
|
|
|
sizeof(efi_system_table_t));
|
2015-11-30 20:28:18 +08:00
|
|
|
if (efi.systab == NULL) {
|
|
|
|
pr_warn("Unable to map EFI system table.\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_bit(EFI_BOOT, &efi.flags);
|
2015-11-30 20:28:19 +08:00
|
|
|
if (IS_ENABLED(CONFIG_64BIT))
|
|
|
|
set_bit(EFI_64BIT, &efi.flags);
|
2015-11-30 20:28:18 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Verify the EFI Table
|
|
|
|
*/
|
|
|
|
if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
|
|
|
|
pr_err("System table signature incorrect\n");
|
|
|
|
retval = -EINVAL;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if ((efi.systab->hdr.revision >> 16) < 2)
|
|
|
|
pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n",
|
|
|
|
efi.systab->hdr.revision >> 16,
|
|
|
|
efi.systab->hdr.revision & 0xffff);
|
|
|
|
|
efi/arm*: Drop writable mapping of the UEFI System table
Commit:
2eec5dedf770 ("efi/arm-init: Use read-only early mappings")
updated the early ARM UEFI init code to create the temporary, early
mapping of the UEFI System table using read-only attributes, as a
hardening measure against inadvertent modification.
However, this still leaves the permanent, writable mapping of the UEFI
System table, which is only ever referenced during invocations of UEFI
Runtime Services, at which time the UEFI virtual mapping is available,
which also covers the system table. (This is guaranteed by the fact that
SetVirtualAddressMap(), which is a runtime service itself, converts
various entries in the table to their virtual equivalents, which implies
that the table must be covered by a RuntimeServicesData region that has
the EFI_MEMORY_RUNTIME attribute.)
So instead of creating this permanent mapping, record the virtual address
of the system table inside the UEFI virtual mapping, and dereference that
when accessing the table. This protects the contents of the system table
from inadvertent (or deliberate) modification when no UEFI Runtime
Services calls are in progress.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/1461614832-17633-3-git-send-email-matt@codeblueprint.co.uk
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2016-04-26 04:06:34 +08:00
|
|
|
efi.runtime_version = efi.systab->hdr.revision;
|
|
|
|
|
2015-11-30 20:28:18 +08:00
|
|
|
/* Show what we know for posterity */
|
2016-02-17 20:36:00 +08:00
|
|
|
c16 = early_memremap_ro(efi_to_phys(efi.systab->fw_vendor),
|
|
|
|
sizeof(vendor) * sizeof(efi_char16_t));
|
2015-11-30 20:28:18 +08:00
|
|
|
if (c16) {
|
|
|
|
for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
|
|
|
|
vendor[i] = c16[i];
|
|
|
|
vendor[i] = '\0';
|
|
|
|
early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("EFI v%u.%.02u by %s\n",
|
|
|
|
efi.systab->hdr.revision >> 16,
|
|
|
|
efi.systab->hdr.revision & 0xffff, vendor);
|
|
|
|
|
|
|
|
table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables;
|
2016-02-17 20:36:00 +08:00
|
|
|
config_tables = early_memremap_ro(efi_to_phys(efi.systab->tables),
|
|
|
|
table_size);
|
2015-11-30 20:28:18 +08:00
|
|
|
if (config_tables == NULL) {
|
|
|
|
pr_warn("Unable to map EFI config table array.\n");
|
|
|
|
retval = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
|
2016-04-26 04:06:53 +08:00
|
|
|
sizeof(efi_config_table_t),
|
|
|
|
arch_tables);
|
2015-11-30 20:28:18 +08:00
|
|
|
|
2017-08-19 03:49:38 +08:00
|
|
|
if (!retval)
|
|
|
|
efi.config_table = (unsigned long)efi.systab->tables;
|
|
|
|
|
2015-11-30 20:28:18 +08:00
|
|
|
early_memunmap(config_tables, table_size);
|
|
|
|
out:
|
|
|
|
early_memunmap(efi.systab, sizeof(efi_system_table_t));
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
efi/arm64: Treat regions with WT/WC set but WB cleared as memory
Currently, memory regions are only recorded in the memblock memory table
if they have the EFI_MEMORY_WB memory type attribute set. In case the
region is of a reserved type, it is also marked as MEMBLOCK_NOMAP, which
will leave it out of the linear mapping.
However, memory regions may legally have the EFI_MEMORY_WT or EFI_MEMORY_WC
attributes set, and the EFI_MEMORY_WB cleared, in which case the region in
question is obviously backed by normal memory, but is not recorded in the
memblock memory table at all. Since it would be useful to be able to
identify any UEFI reported memory region using memblock_is_memory(), it
makes sense to add all memory to the memblock memory table, and simply mark
it as MEMBLOCK_NOMAP if it lacks the EFI_MEMORY_WB attribute.
While implementing this, let's refactor the code slightly to make it easier
to understand: replace is_normal_ram() with is_memory(), and make it return
true for each region that has any of the WB|WT|WC bits set. (This follows
the AArch64 bindings in the UEFI spec, which state that those are the
attributes that map to normal memory)
Also, replace is_reserve_region() with is_usable_memory(), and only invoke
it if the region in question was identified as memory by is_memory() in the
first place. The net result is the same (only reserved regions that are
backed by memory end up in the memblock memory table with the MEMBLOCK_NOMAP
flag set) but carried out in a more straightforward way.
Finally, we remove the trailing asterisk in the EFI debug output. Keeping it
clutters the code, and it serves no real purpose now that we no longer
temporarily reserve BootServices code and data regions like we did in the
early days of EFI support on arm64 Linux (which it inherited from the x86
implementation)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
Tested-by: James Morse <james.morse@arm.com>
Reviewed-by: James Morse <james.morse@arm.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
2016-08-26 00:17:09 +08:00
|
|
|
* Return true for regions that can be used as System RAM.
|
2015-11-30 20:28:18 +08:00
|
|
|
*/
|
efi/arm64: Treat regions with WT/WC set but WB cleared as memory
Currently, memory regions are only recorded in the memblock memory table
if they have the EFI_MEMORY_WB memory type attribute set. In case the
region is of a reserved type, it is also marked as MEMBLOCK_NOMAP, which
will leave it out of the linear mapping.
However, memory regions may legally have the EFI_MEMORY_WT or EFI_MEMORY_WC
attributes set, and the EFI_MEMORY_WB cleared, in which case the region in
question is obviously backed by normal memory, but is not recorded in the
memblock memory table at all. Since it would be useful to be able to
identify any UEFI reported memory region using memblock_is_memory(), it
makes sense to add all memory to the memblock memory table, and simply mark
it as MEMBLOCK_NOMAP if it lacks the EFI_MEMORY_WB attribute.
While implementing this, let's refactor the code slightly to make it easier
to understand: replace is_normal_ram() with is_memory(), and make it return
true for each region that has any of the WB|WT|WC bits set. (This follows
the AArch64 bindings in the UEFI spec, which state that those are the
attributes that map to normal memory)
Also, replace is_reserve_region() with is_usable_memory(), and only invoke
it if the region in question was identified as memory by is_memory() in the
first place. The net result is the same (only reserved regions that are
backed by memory end up in the memblock memory table with the MEMBLOCK_NOMAP
flag set) but carried out in a more straightforward way.
Finally, we remove the trailing asterisk in the EFI debug output. Keeping it
clutters the code, and it serves no real purpose now that we no longer
temporarily reserve BootServices code and data regions like we did in the
early days of EFI support on arm64 Linux (which it inherited from the x86
implementation)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
Tested-by: James Morse <james.morse@arm.com>
Reviewed-by: James Morse <james.morse@arm.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
2016-08-26 00:17:09 +08:00
|
|
|
static __init int is_usable_memory(efi_memory_desc_t *md)
|
2015-11-30 20:28:18 +08:00
|
|
|
{
|
|
|
|
switch (md->type) {
|
|
|
|
case EFI_LOADER_CODE:
|
|
|
|
case EFI_LOADER_DATA:
|
efi/arm: Don't mark ACPI reclaim memory as MEMBLOCK_NOMAP
On ARM, regions of memory that are described by UEFI as having special
significance to the firmware itself are omitted from the linear mapping.
This is necessary since we cannot guarantee that alternate mappings of
the same physical region will use attributes that are compatible with
the ones we use for the linear mapping, and aliases with mismatched
attributes are prohibited by the architecture.
The above does not apply to ACPI reclaim regions: such regions have no
special significance to the firmware, and it is up to the OS to decide
whether or not to preserve them after it has consumed their contents,
and for how long, after which time the OS can use the memory in any way
it likes. In the Linux case, such regions are preserved indefinitely,
and are simply treated the same way as other 'reserved' memory types.
Punching holes into the linear mapping causes page table fragmentation,
which increases TLB pressure, and so we should avoid doing so if we can.
So add a special case for regions of type EFI_ACPI_RECLAIM_MEMORY, and
memblock_reserve() them instead of marking them MEMBLOCK_NOMAP.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/20170818194947.19347-2-ard.biesheuvel@linaro.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-08-19 03:49:34 +08:00
|
|
|
case EFI_ACPI_RECLAIM_MEMORY:
|
2015-11-30 20:28:18 +08:00
|
|
|
case EFI_BOOT_SERVICES_CODE:
|
|
|
|
case EFI_BOOT_SERVICES_DATA:
|
|
|
|
case EFI_CONVENTIONAL_MEMORY:
|
|
|
|
case EFI_PERSISTENT_MEMORY:
|
efi/arm64: Treat regions with WT/WC set but WB cleared as memory
Currently, memory regions are only recorded in the memblock memory table
if they have the EFI_MEMORY_WB memory type attribute set. In case the
region is of a reserved type, it is also marked as MEMBLOCK_NOMAP, which
will leave it out of the linear mapping.
However, memory regions may legally have the EFI_MEMORY_WT or EFI_MEMORY_WC
attributes set, and the EFI_MEMORY_WB cleared, in which case the region in
question is obviously backed by normal memory, but is not recorded in the
memblock memory table at all. Since it would be useful to be able to
identify any UEFI reported memory region using memblock_is_memory(), it
makes sense to add all memory to the memblock memory table, and simply mark
it as MEMBLOCK_NOMAP if it lacks the EFI_MEMORY_WB attribute.
While implementing this, let's refactor the code slightly to make it easier
to understand: replace is_normal_ram() with is_memory(), and make it return
true for each region that has any of the WB|WT|WC bits set. (This follows
the AArch64 bindings in the UEFI spec, which state that those are the
attributes that map to normal memory)
Also, replace is_reserve_region() with is_usable_memory(), and only invoke
it if the region in question was identified as memory by is_memory() in the
first place. The net result is the same (only reserved regions that are
backed by memory end up in the memblock memory table with the MEMBLOCK_NOMAP
flag set) but carried out in a more straightforward way.
Finally, we remove the trailing asterisk in the EFI debug output. Keeping it
clutters the code, and it serves no real purpose now that we no longer
temporarily reserve BootServices code and data regions like we did in the
early days of EFI support on arm64 Linux (which it inherited from the x86
implementation)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
Tested-by: James Morse <james.morse@arm.com>
Reviewed-by: James Morse <james.morse@arm.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
2016-08-26 00:17:09 +08:00
|
|
|
/*
|
|
|
|
* According to the spec, these regions are no longer reserved
|
|
|
|
* after calling ExitBootServices(). However, we can only use
|
|
|
|
* them as System RAM if they can be mapped writeback cacheable.
|
|
|
|
*/
|
|
|
|
return (md->attribute & EFI_MEMORY_WB);
|
2015-11-30 20:28:18 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
efi/arm64: Treat regions with WT/WC set but WB cleared as memory
Currently, memory regions are only recorded in the memblock memory table
if they have the EFI_MEMORY_WB memory type attribute set. In case the
region is of a reserved type, it is also marked as MEMBLOCK_NOMAP, which
will leave it out of the linear mapping.
However, memory regions may legally have the EFI_MEMORY_WT or EFI_MEMORY_WC
attributes set, and the EFI_MEMORY_WB cleared, in which case the region in
question is obviously backed by normal memory, but is not recorded in the
memblock memory table at all. Since it would be useful to be able to
identify any UEFI reported memory region using memblock_is_memory(), it
makes sense to add all memory to the memblock memory table, and simply mark
it as MEMBLOCK_NOMAP if it lacks the EFI_MEMORY_WB attribute.
While implementing this, let's refactor the code slightly to make it easier
to understand: replace is_normal_ram() with is_memory(), and make it return
true for each region that has any of the WB|WT|WC bits set. (This follows
the AArch64 bindings in the UEFI spec, which state that those are the
attributes that map to normal memory)
Also, replace is_reserve_region() with is_usable_memory(), and only invoke
it if the region in question was identified as memory by is_memory() in the
first place. The net result is the same (only reserved regions that are
backed by memory end up in the memblock memory table with the MEMBLOCK_NOMAP
flag set) but carried out in a more straightforward way.
Finally, we remove the trailing asterisk in the EFI debug output. Keeping it
clutters the code, and it serves no real purpose now that we no longer
temporarily reserve BootServices code and data regions like we did in the
early days of EFI support on arm64 Linux (which it inherited from the x86
implementation)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
Tested-by: James Morse <james.morse@arm.com>
Reviewed-by: James Morse <james.morse@arm.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
2016-08-26 00:17:09 +08:00
|
|
|
return false;
|
2015-11-30 20:28:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static __init void reserve_regions(void)
|
|
|
|
{
|
|
|
|
efi_memory_desc_t *md;
|
|
|
|
u64 paddr, npages, size;
|
|
|
|
|
|
|
|
if (efi_enabled(EFI_DBG))
|
|
|
|
pr_info("Processing EFI memory map:\n");
|
|
|
|
|
2016-04-09 06:50:23 +08:00
|
|
|
/*
|
|
|
|
* Discard memblocks discovered so far: if there are any at this
|
|
|
|
* point, they originate from memory nodes in the DT, and UEFI
|
|
|
|
* uses its own memory map instead.
|
|
|
|
*/
|
|
|
|
memblock_dump_all();
|
2018-06-15 06:28:02 +08:00
|
|
|
memblock_remove(0, PHYS_ADDR_MAX);
|
2016-04-09 06:50:23 +08:00
|
|
|
|
2016-04-26 04:06:39 +08:00
|
|
|
for_each_efi_memory_desc(md) {
|
2015-11-30 20:28:18 +08:00
|
|
|
paddr = md->phys_addr;
|
|
|
|
npages = md->num_pages;
|
|
|
|
|
|
|
|
if (efi_enabled(EFI_DBG)) {
|
|
|
|
char buf[64];
|
|
|
|
|
efi/arm64: Treat regions with WT/WC set but WB cleared as memory
Currently, memory regions are only recorded in the memblock memory table
if they have the EFI_MEMORY_WB memory type attribute set. In case the
region is of a reserved type, it is also marked as MEMBLOCK_NOMAP, which
will leave it out of the linear mapping.
However, memory regions may legally have the EFI_MEMORY_WT or EFI_MEMORY_WC
attributes set, and the EFI_MEMORY_WB cleared, in which case the region in
question is obviously backed by normal memory, but is not recorded in the
memblock memory table at all. Since it would be useful to be able to
identify any UEFI reported memory region using memblock_is_memory(), it
makes sense to add all memory to the memblock memory table, and simply mark
it as MEMBLOCK_NOMAP if it lacks the EFI_MEMORY_WB attribute.
While implementing this, let's refactor the code slightly to make it easier
to understand: replace is_normal_ram() with is_memory(), and make it return
true for each region that has any of the WB|WT|WC bits set. (This follows
the AArch64 bindings in the UEFI spec, which state that those are the
attributes that map to normal memory)
Also, replace is_reserve_region() with is_usable_memory(), and only invoke
it if the region in question was identified as memory by is_memory() in the
first place. The net result is the same (only reserved regions that are
backed by memory end up in the memblock memory table with the MEMBLOCK_NOMAP
flag set) but carried out in a more straightforward way.
Finally, we remove the trailing asterisk in the EFI debug output. Keeping it
clutters the code, and it serves no real purpose now that we no longer
temporarily reserve BootServices code and data regions like we did in the
early days of EFI support on arm64 Linux (which it inherited from the x86
implementation)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
Tested-by: James Morse <james.morse@arm.com>
Reviewed-by: James Morse <james.morse@arm.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
2016-08-26 00:17:09 +08:00
|
|
|
pr_info(" 0x%012llx-0x%012llx %s\n",
|
2015-11-30 20:28:18 +08:00
|
|
|
paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1,
|
efi/arm64: Treat regions with WT/WC set but WB cleared as memory
Currently, memory regions are only recorded in the memblock memory table
if they have the EFI_MEMORY_WB memory type attribute set. In case the
region is of a reserved type, it is also marked as MEMBLOCK_NOMAP, which
will leave it out of the linear mapping.
However, memory regions may legally have the EFI_MEMORY_WT or EFI_MEMORY_WC
attributes set, and the EFI_MEMORY_WB cleared, in which case the region in
question is obviously backed by normal memory, but is not recorded in the
memblock memory table at all. Since it would be useful to be able to
identify any UEFI reported memory region using memblock_is_memory(), it
makes sense to add all memory to the memblock memory table, and simply mark
it as MEMBLOCK_NOMAP if it lacks the EFI_MEMORY_WB attribute.
While implementing this, let's refactor the code slightly to make it easier
to understand: replace is_normal_ram() with is_memory(), and make it return
true for each region that has any of the WB|WT|WC bits set. (This follows
the AArch64 bindings in the UEFI spec, which state that those are the
attributes that map to normal memory)
Also, replace is_reserve_region() with is_usable_memory(), and only invoke
it if the region in question was identified as memory by is_memory() in the
first place. The net result is the same (only reserved regions that are
backed by memory end up in the memblock memory table with the MEMBLOCK_NOMAP
flag set) but carried out in a more straightforward way.
Finally, we remove the trailing asterisk in the EFI debug output. Keeping it
clutters the code, and it serves no real purpose now that we no longer
temporarily reserve BootServices code and data regions like we did in the
early days of EFI support on arm64 Linux (which it inherited from the x86
implementation)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
Tested-by: James Morse <james.morse@arm.com>
Reviewed-by: James Morse <james.morse@arm.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
2016-08-26 00:17:09 +08:00
|
|
|
efi_md_typeattr_format(buf, sizeof(buf), md));
|
2015-11-30 20:28:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
memrange_efi_to_native(&paddr, &npages);
|
|
|
|
size = npages << PAGE_SHIFT;
|
|
|
|
|
efi/arm64: Treat regions with WT/WC set but WB cleared as memory
Currently, memory regions are only recorded in the memblock memory table
if they have the EFI_MEMORY_WB memory type attribute set. In case the
region is of a reserved type, it is also marked as MEMBLOCK_NOMAP, which
will leave it out of the linear mapping.
However, memory regions may legally have the EFI_MEMORY_WT or EFI_MEMORY_WC
attributes set, and the EFI_MEMORY_WB cleared, in which case the region in
question is obviously backed by normal memory, but is not recorded in the
memblock memory table at all. Since it would be useful to be able to
identify any UEFI reported memory region using memblock_is_memory(), it
makes sense to add all memory to the memblock memory table, and simply mark
it as MEMBLOCK_NOMAP if it lacks the EFI_MEMORY_WB attribute.
While implementing this, let's refactor the code slightly to make it easier
to understand: replace is_normal_ram() with is_memory(), and make it return
true for each region that has any of the WB|WT|WC bits set. (This follows
the AArch64 bindings in the UEFI spec, which state that those are the
attributes that map to normal memory)
Also, replace is_reserve_region() with is_usable_memory(), and only invoke
it if the region in question was identified as memory by is_memory() in the
first place. The net result is the same (only reserved regions that are
backed by memory end up in the memblock memory table with the MEMBLOCK_NOMAP
flag set) but carried out in a more straightforward way.
Finally, we remove the trailing asterisk in the EFI debug output. Keeping it
clutters the code, and it serves no real purpose now that we no longer
temporarily reserve BootServices code and data regions like we did in the
early days of EFI support on arm64 Linux (which it inherited from the x86
implementation)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
Tested-by: James Morse <james.morse@arm.com>
Reviewed-by: James Morse <james.morse@arm.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
2016-08-26 00:17:09 +08:00
|
|
|
if (is_memory(md)) {
|
2015-11-30 20:28:18 +08:00
|
|
|
early_init_dt_add_memory_arch(paddr, size);
|
|
|
|
|
efi/arm64: Treat regions with WT/WC set but WB cleared as memory
Currently, memory regions are only recorded in the memblock memory table
if they have the EFI_MEMORY_WB memory type attribute set. In case the
region is of a reserved type, it is also marked as MEMBLOCK_NOMAP, which
will leave it out of the linear mapping.
However, memory regions may legally have the EFI_MEMORY_WT or EFI_MEMORY_WC
attributes set, and the EFI_MEMORY_WB cleared, in which case the region in
question is obviously backed by normal memory, but is not recorded in the
memblock memory table at all. Since it would be useful to be able to
identify any UEFI reported memory region using memblock_is_memory(), it
makes sense to add all memory to the memblock memory table, and simply mark
it as MEMBLOCK_NOMAP if it lacks the EFI_MEMORY_WB attribute.
While implementing this, let's refactor the code slightly to make it easier
to understand: replace is_normal_ram() with is_memory(), and make it return
true for each region that has any of the WB|WT|WC bits set. (This follows
the AArch64 bindings in the UEFI spec, which state that those are the
attributes that map to normal memory)
Also, replace is_reserve_region() with is_usable_memory(), and only invoke
it if the region in question was identified as memory by is_memory() in the
first place. The net result is the same (only reserved regions that are
backed by memory end up in the memblock memory table with the MEMBLOCK_NOMAP
flag set) but carried out in a more straightforward way.
Finally, we remove the trailing asterisk in the EFI debug output. Keeping it
clutters the code, and it serves no real purpose now that we no longer
temporarily reserve BootServices code and data regions like we did in the
early days of EFI support on arm64 Linux (which it inherited from the x86
implementation)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
Tested-by: James Morse <james.morse@arm.com>
Reviewed-by: James Morse <james.morse@arm.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
2016-08-26 00:17:09 +08:00
|
|
|
if (!is_usable_memory(md))
|
|
|
|
memblock_mark_nomap(paddr, size);
|
efi/arm: Don't mark ACPI reclaim memory as MEMBLOCK_NOMAP
On ARM, regions of memory that are described by UEFI as having special
significance to the firmware itself are omitted from the linear mapping.
This is necessary since we cannot guarantee that alternate mappings of
the same physical region will use attributes that are compatible with
the ones we use for the linear mapping, and aliases with mismatched
attributes are prohibited by the architecture.
The above does not apply to ACPI reclaim regions: such regions have no
special significance to the firmware, and it is up to the OS to decide
whether or not to preserve them after it has consumed their contents,
and for how long, after which time the OS can use the memory in any way
it likes. In the Linux case, such regions are preserved indefinitely,
and are simply treated the same way as other 'reserved' memory types.
Punching holes into the linear mapping causes page table fragmentation,
which increases TLB pressure, and so we should avoid doing so if we can.
So add a special case for regions of type EFI_ACPI_RECLAIM_MEMORY, and
memblock_reserve() them instead of marking them MEMBLOCK_NOMAP.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: http://lkml.kernel.org/r/20170818194947.19347-2-ard.biesheuvel@linaro.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-08-19 03:49:34 +08:00
|
|
|
|
|
|
|
/* keep ACPI reclaim memory intact for kexec etc. */
|
|
|
|
if (md->type == EFI_ACPI_RECLAIM_MEMORY)
|
|
|
|
memblock_reserve(paddr, size);
|
efi/arm64: Treat regions with WT/WC set but WB cleared as memory
Currently, memory regions are only recorded in the memblock memory table
if they have the EFI_MEMORY_WB memory type attribute set. In case the
region is of a reserved type, it is also marked as MEMBLOCK_NOMAP, which
will leave it out of the linear mapping.
However, memory regions may legally have the EFI_MEMORY_WT or EFI_MEMORY_WC
attributes set, and the EFI_MEMORY_WB cleared, in which case the region in
question is obviously backed by normal memory, but is not recorded in the
memblock memory table at all. Since it would be useful to be able to
identify any UEFI reported memory region using memblock_is_memory(), it
makes sense to add all memory to the memblock memory table, and simply mark
it as MEMBLOCK_NOMAP if it lacks the EFI_MEMORY_WB attribute.
While implementing this, let's refactor the code slightly to make it easier
to understand: replace is_normal_ram() with is_memory(), and make it return
true for each region that has any of the WB|WT|WC bits set. (This follows
the AArch64 bindings in the UEFI spec, which state that those are the
attributes that map to normal memory)
Also, replace is_reserve_region() with is_usable_memory(), and only invoke
it if the region in question was identified as memory by is_memory() in the
first place. The net result is the same (only reserved regions that are
backed by memory end up in the memblock memory table with the MEMBLOCK_NOMAP
flag set) but carried out in a more straightforward way.
Finally, we remove the trailing asterisk in the EFI debug output. Keeping it
clutters the code, and it serves no real purpose now that we no longer
temporarily reserve BootServices code and data regions like we did in the
early days of EFI support on arm64 Linux (which it inherited from the x86
implementation)
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org>
Tested-by: James Morse <james.morse@arm.com>
Reviewed-by: James Morse <james.morse@arm.com>
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
2016-08-26 00:17:09 +08:00
|
|
|
}
|
2015-11-30 20:28:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void __init efi_init(void)
|
|
|
|
{
|
2016-02-27 05:22:05 +08:00
|
|
|
struct efi_memory_map_data data;
|
2015-11-30 20:28:18 +08:00
|
|
|
struct efi_fdt_params params;
|
|
|
|
|
|
|
|
/* Grab UEFI information placed in FDT by stub */
|
|
|
|
if (!efi_get_fdt_params(¶ms))
|
|
|
|
return;
|
|
|
|
|
|
|
|
efi_system_table = params.system_table;
|
|
|
|
|
2016-02-27 05:22:05 +08:00
|
|
|
data.desc_version = params.desc_ver;
|
|
|
|
data.desc_size = params.desc_size;
|
|
|
|
data.size = params.mmap_size;
|
|
|
|
data.phys_map = params.mmap;
|
|
|
|
|
|
|
|
if (efi_memmap_init_early(&data) < 0) {
|
2015-11-30 20:28:18 +08:00
|
|
|
/*
|
|
|
|
* If we are booting via UEFI, the UEFI memory map is the only
|
|
|
|
* description of memory we have, so there is little point in
|
|
|
|
* proceeding if we cannot access it.
|
|
|
|
*/
|
|
|
|
panic("Unable to map EFI memory map.\n");
|
|
|
|
}
|
|
|
|
|
2016-04-26 04:06:40 +08:00
|
|
|
WARN(efi.memmap.desc_version != 1,
|
|
|
|
"Unexpected EFI_MEMORY_DESCRIPTOR version %ld",
|
|
|
|
efi.memmap.desc_version);
|
|
|
|
|
2016-10-18 22:33:13 +08:00
|
|
|
if (uefi_init() < 0) {
|
|
|
|
efi_memmap_unmap();
|
2015-11-30 20:28:18 +08:00
|
|
|
return;
|
2016-10-18 22:33:13 +08:00
|
|
|
}
|
2015-11-30 20:28:18 +08:00
|
|
|
|
|
|
|
reserve_regions();
|
2016-07-12 03:00:46 +08:00
|
|
|
efi_esrt_init();
|
efi/arm64: Don't apply MEMBLOCK_NOMAP to UEFI memory map mapping
Commit 4dffbfc48d65 ("arm64/efi: mark UEFI reserved regions as
MEMBLOCK_NOMAP") updated the mapping logic of both the RuntimeServices
regions as well as the kernel's copy of the UEFI memory map to set the
MEMBLOCK_NOMAP flag, which causes these regions to be omitted from the
kernel direct mapping, and from being covered by a struct page.
For the RuntimeServices regions, this is an obvious win, since the contents
of these regions have significance to the firmware executable code itself,
and are mapped in the EFI page tables using attributes that are described in
the UEFI memory map, and which may differ from the attributes we use for
mapping system RAM. It also prevents the contents from being modified
inadvertently, since the EFI page tables are only live during runtime
service invocations.
None of these concerns apply to the allocation that covers the UEFI memory
map, since it is entirely owned by the kernel. Setting the MEMBLOCK_NOMAP on
the region did allow us to use ioremap_cache() to map it both on arm64 and
on ARM, since the latter does not allow ioremap_cache() to be used on
regions that are covered by a struct page.
The ioremap_cache() on ARM restriction will be lifted in the v4.7 timeframe,
but in the mean time, it has been reported that commit 4dffbfc48d65 causes
a regression on 64k granule kernels. This is due to the fact that, given
the 64 KB page size, the region that we end up removing from the kernel
direct mapping is rounded up to 64 KB, and this 64 KB page frame may be
shared with the initrd when booting via GRUB (which does not align its
EFI_LOADER_DATA allocations to 64 KB like the stub does). This will crash
the kernel as soon as it tries to access the initrd.
Since the issue is specific to arm64, revert back to memblock_reserve()'ing
the UEFI memory map when running on arm64. This is a temporary fix for v4.5
and v4.6, and will be superseded in the v4.7 timeframe when we will be able
to move back to memblock_reserve() unconditionally.
Fixes: 4dffbfc48d65 ("arm64/efi: mark UEFI reserved regions as MEMBLOCK_NOMAP")
Reported-by: Mark Salter <msalter@redhat.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Acked-by: Will Deacon <will.deacon@arm.com>
Cc: Leif Lindholm <leif.lindholm@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Jeremy Linton <jeremy.linton@arm.com>
Cc: Mark Langsdorf <mlangsdo@redhat.com>
Cc: <stable@vger.kernel.org> # v4.5
Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
2016-03-30 15:46:23 +08:00
|
|
|
|
2016-04-26 04:07:02 +08:00
|
|
|
memblock_reserve(params.mmap & PAGE_MASK,
|
|
|
|
PAGE_ALIGN(params.mmap_size +
|
|
|
|
(params.mmap & ~PAGE_MASK)));
|
2016-04-26 04:06:53 +08:00
|
|
|
|
|
|
|
init_screen_info();
|
2018-11-15 01:55:41 +08:00
|
|
|
|
|
|
|
/* ARM does not permit early mappings to persist across paging_init() */
|
|
|
|
if (IS_ENABLED(CONFIG_ARM))
|
|
|
|
efi_memmap_unmap();
|
2015-11-30 20:28:18 +08:00
|
|
|
}
|
2016-04-26 04:06:55 +08:00
|
|
|
|
|
|
|
static int __init register_gop_device(void)
|
|
|
|
{
|
|
|
|
void *pd;
|
|
|
|
|
|
|
|
if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
pd = platform_device_register_data(NULL, "efi-framebuffer", 0,
|
|
|
|
&screen_info, sizeof(screen_info));
|
|
|
|
return PTR_ERR_OR_ZERO(pd);
|
|
|
|
}
|
|
|
|
subsys_initcall(register_gop_device);
|