2019-02-02 09:41:15 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2014-04-16 02:47:52 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2013, 2014 Linaro Ltd; <roy.franz@linaro.org>
|
|
|
|
*
|
|
|
|
* This file implements the EFI boot stub for the arm64 kernel.
|
|
|
|
* Adapted from ARM version by Mark Salter <msalter@redhat.com>
|
|
|
|
*/
|
2017-08-18 19:49:36 +00:00
|
|
|
|
|
|
|
|
2014-04-16 02:47:52 +00:00
|
|
|
#include <linux/efi.h>
|
2014-07-02 12:54:41 +00:00
|
|
|
#include <asm/efi.h>
|
2017-07-14 14:54:36 +00:00
|
|
|
#include <asm/memory.h>
|
2020-02-10 16:02:32 +00:00
|
|
|
#include <asm/sections.h>
|
2016-02-17 12:36:02 +00:00
|
|
|
#include <asm/sysreg.h>
|
2014-04-16 02:47:52 +00:00
|
|
|
|
2016-01-26 13:48:29 +00:00
|
|
|
#include "efistub.h"
|
|
|
|
|
2019-12-24 15:10:19 +00:00
|
|
|
efi_status_t check_platform_features(void)
|
2016-02-17 12:36:02 +00:00
|
|
|
{
|
|
|
|
u64 tg;
|
|
|
|
|
|
|
|
/* UEFI mandates support for 4 KB granularity, no need to check */
|
|
|
|
if (IS_ENABLED(CONFIG_ARM64_4K_PAGES))
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
|
|
|
|
tg = (read_cpuid(ID_AA64MMFR0_EL1) >> ID_AA64MMFR0_TGRAN_SHIFT) & 0xf;
|
|
|
|
if (tg != ID_AA64MMFR0_TGRAN_SUPPORTED) {
|
|
|
|
if (IS_ENABLED(CONFIG_ARM64_64K_PAGES))
|
2019-12-24 15:10:18 +00:00
|
|
|
pr_efi_err("This 64 KB granular kernel is not supported by your CPU\n");
|
2016-02-17 12:36:02 +00:00
|
|
|
else
|
2019-12-24 15:10:18 +00:00
|
|
|
pr_efi_err("This 16 KB granular kernel is not supported by your CPU\n");
|
2016-02-17 12:36:02 +00:00
|
|
|
return EFI_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
2014-04-16 02:47:52 +00:00
|
|
|
|
2019-12-24 15:10:19 +00:00
|
|
|
efi_status_t handle_kernel_image(unsigned long *image_addr,
|
2016-02-17 12:35:57 +00:00
|
|
|
unsigned long *image_size,
|
|
|
|
unsigned long *reserve_addr,
|
|
|
|
unsigned long *reserve_size,
|
|
|
|
unsigned long dram_base,
|
|
|
|
efi_loaded_image_t *image)
|
2014-04-16 02:47:52 +00:00
|
|
|
{
|
|
|
|
efi_status_t status;
|
|
|
|
unsigned long kernel_size, kernel_memsize = 0;
|
2015-10-29 14:07:25 +00:00
|
|
|
unsigned long preferred_offset;
|
2016-01-26 13:48:29 +00:00
|
|
|
u64 phys_seed = 0;
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
|
2017-04-04 16:09:08 +00:00
|
|
|
if (!nokaslr()) {
|
2019-12-24 15:10:19 +00:00
|
|
|
status = efi_get_random_bytes(sizeof(phys_seed),
|
2016-01-26 13:48:29 +00:00
|
|
|
(u8 *)&phys_seed);
|
|
|
|
if (status == EFI_NOT_FOUND) {
|
2019-12-24 15:10:18 +00:00
|
|
|
pr_efi("EFI_RNG_PROTOCOL unavailable, no randomness supplied\n");
|
2016-01-26 13:48:29 +00:00
|
|
|
} else if (status != EFI_SUCCESS) {
|
2019-12-24 15:10:18 +00:00
|
|
|
pr_efi_err("efi_get_random_bytes() failed\n");
|
2016-01-26 13:48:29 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
} else {
|
2019-12-24 15:10:18 +00:00
|
|
|
pr_efi("KASLR disabled on kernel command line\n");
|
2016-01-26 13:48:29 +00:00
|
|
|
}
|
|
|
|
}
|
2015-10-29 14:07:25 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The preferred offset of the kernel Image is TEXT_OFFSET bytes beyond
|
|
|
|
* a 2 MB aligned base, which itself may be lower than dram_base, as
|
|
|
|
* long as the resulting offset equals or exceeds it.
|
|
|
|
*/
|
2016-01-26 13:48:29 +00:00
|
|
|
preferred_offset = round_down(dram_base, MIN_KIMG_ALIGN) + TEXT_OFFSET;
|
2015-10-29 14:07:25 +00:00
|
|
|
if (preferred_offset < dram_base)
|
2016-01-26 13:48:29 +00:00
|
|
|
preferred_offset += MIN_KIMG_ALIGN;
|
2014-04-16 02:47:52 +00:00
|
|
|
|
|
|
|
kernel_size = _edata - _text;
|
2016-01-26 13:48:29 +00:00
|
|
|
kernel_memsize = kernel_size + (_end - _edata);
|
|
|
|
|
|
|
|
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) {
|
2016-04-18 15:09:48 +00:00
|
|
|
/*
|
arm64: remove CONFIG_DEBUG_ALIGN_RODATA feature
When CONFIG_DEBUG_ALIGN_RODATA is enabled, kernel segments mapped with
different permissions (r-x for .text, r-- for .rodata, rw- for .data,
etc) are rounded up to 2 MiB so they can be mapped more efficiently.
In particular, it permits the segments to be mapped using level 2
block entries when using 4k pages, which is expected to result in less
TLB pressure.
However, the mappings for the bulk of the kernel will use level 2
entries anyway, and the misaligned fringes are organized such that they
can take advantage of the contiguous bit, and use far fewer level 3
entries than would be needed otherwise.
This makes the value of this feature dubious at best, and since it is not
enabled in defconfig or in the distro configs, it does not appear to be
in wide use either. So let's just remove it.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Will Deacon <will@kernel.org>
Acked-by: Laura Abbott <labbott@kernel.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2020-03-29 14:12:58 +00:00
|
|
|
* Produce a displacement in the interval [0, MIN_KIMG_ALIGN)
|
|
|
|
* that doesn't violate this kernel's de-facto alignment
|
2017-07-14 14:54:36 +00:00
|
|
|
* constraints.
|
2016-04-18 15:09:48 +00:00
|
|
|
*/
|
2017-07-14 14:54:36 +00:00
|
|
|
u32 mask = (MIN_KIMG_ALIGN - 1) & ~(EFI_KIMG_ALIGN - 1);
|
arm64: remove CONFIG_DEBUG_ALIGN_RODATA feature
When CONFIG_DEBUG_ALIGN_RODATA is enabled, kernel segments mapped with
different permissions (r-x for .text, r-- for .rodata, rw- for .data,
etc) are rounded up to 2 MiB so they can be mapped more efficiently.
In particular, it permits the segments to be mapped using level 2
block entries when using 4k pages, which is expected to result in less
TLB pressure.
However, the mappings for the bulk of the kernel will use level 2
entries anyway, and the misaligned fringes are organized such that they
can take advantage of the contiguous bit, and use far fewer level 3
entries than would be needed otherwise.
This makes the value of this feature dubious at best, and since it is not
enabled in defconfig or in the distro configs, it does not appear to be
in wide use either. So let's just remove it.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Acked-by: Mark Rutland <mark.rutland@arm.com>
Acked-by: Will Deacon <will@kernel.org>
Acked-by: Laura Abbott <labbott@kernel.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2020-03-29 14:12:58 +00:00
|
|
|
u32 offset = (phys_seed >> 32) & mask;
|
2016-04-18 15:09:48 +00:00
|
|
|
|
2018-05-18 14:08:41 +00:00
|
|
|
/*
|
|
|
|
* With CONFIG_RANDOMIZE_TEXT_OFFSET=y, TEXT_OFFSET may not
|
|
|
|
* be a multiple of EFI_KIMG_ALIGN, and we must ensure that
|
|
|
|
* we preserve the misalignment of 'offset' relative to
|
|
|
|
* EFI_KIMG_ALIGN so that statically allocated objects whose
|
|
|
|
* alignment exceeds PAGE_SIZE appear correctly aligned in
|
|
|
|
* memory.
|
|
|
|
*/
|
|
|
|
offset |= TEXT_OFFSET % EFI_KIMG_ALIGN;
|
|
|
|
|
2016-01-26 13:48:29 +00:00
|
|
|
/*
|
|
|
|
* If KASLR is enabled, and we have some randomness available,
|
|
|
|
* locate the kernel at a randomized offset in physical memory.
|
|
|
|
*/
|
2016-04-18 15:09:48 +00:00
|
|
|
*reserve_size = kernel_memsize + offset;
|
2019-12-24 15:10:19 +00:00
|
|
|
status = efi_random_alloc(*reserve_size,
|
2016-01-26 13:48:29 +00:00
|
|
|
MIN_KIMG_ALIGN, reserve_addr,
|
2016-04-18 15:09:48 +00:00
|
|
|
(u32)phys_seed);
|
2015-07-24 11:38:27 +00:00
|
|
|
|
2016-04-18 15:09:48 +00:00
|
|
|
*image_addr = *reserve_addr + offset;
|
2016-01-26 13:48:29 +00:00
|
|
|
} else {
|
2015-07-24 11:38:27 +00:00
|
|
|
/*
|
2016-01-26 13:48:29 +00:00
|
|
|
* Else, try a straight allocation at the preferred offset.
|
2015-07-24 11:38:27 +00:00
|
|
|
* This will work around the issue where, if dram_base == 0x0,
|
|
|
|
* efi_low_alloc() refuses to allocate at 0x0 (to prevent the
|
|
|
|
* address of the allocation to be mistaken for a FAIL return
|
|
|
|
* value or a NULL pointer). It will also ensure that, on
|
|
|
|
* platforms where the [dram_base, dram_base + TEXT_OFFSET)
|
|
|
|
* interval is partially occupied by the firmware (like on APM
|
|
|
|
* Mustang), we can still place the kernel at the address
|
|
|
|
* 'dram_base + TEXT_OFFSET'.
|
|
|
|
*/
|
efi/libstub/arm64: Avoid image_base value from efi_loaded_image
Commit:
9f9223778ef3 ("efi/libstub/arm: Make efi_entry() an ordinary PE/COFF entrypoint")
did some code refactoring to get rid of the EFI entry point assembler
code, and in the process, it got rid of the assignment of image_addr
to the value of _text. Instead, it switched to using the image_base
field of the efi_loaded_image struct provided by UEFI, which should
contain the same value.
However, Michael reports that this is not the case: older GRUB builds
corrupt this value in some way, and since we can easily switch back to
referring to _text to discover this value, let's simply do that.
While at it, fix another issue in commit 9f9223778ef3, which may result
in the unassigned image_addr to be misidentified as the preferred load
offset of the kernel, which is unlikely but will cause a boot crash if
it does occur.
Finally, let's add a warning if the _text vs. image_base discrepancy is
detected, so we can tell more easily how widespread this issue actually
is.
Reported-by: Michael Kelley <mikelley@microsoft.com>
Tested-by: Michael Kelley <mikelley@microsoft.com>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-efi@vger.kernel.org
2020-03-29 08:05:43 +00:00
|
|
|
*image_addr = (unsigned long)_text;
|
2016-01-26 13:48:29 +00:00
|
|
|
if (*image_addr == preferred_offset)
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
|
2015-10-29 14:07:25 +00:00
|
|
|
*image_addr = *reserve_addr = preferred_offset;
|
2016-01-26 13:48:29 +00:00
|
|
|
*reserve_size = round_up(kernel_memsize, EFI_ALLOC_ALIGN);
|
|
|
|
|
efi/libstub: Rename efi_call_early/_runtime macros to be more intuitive
The macros efi_call_early and efi_call_runtime are used to call EFI
boot services and runtime services, respectively. However, the naming
is confusing, given that the early vs runtime distinction may suggest
that these are used for calling the same set of services either early
or late (== at runtime), while in reality, the sets of services they
can be used with are completely disjoint, and efi_call_runtime is also
only usable in 'early' code.
So do a global sweep to replace all occurrences with efi_bs_call or
efi_rt_call, respectively, where BS and RT match the idiom used by
the UEFI spec to refer to boot time or runtime services.
While at it, use 'func' as the macro parameter name for the function
pointers, which is less likely to collide and cause weird build errors.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Cc: Arvind Sankar <nivedita@alum.mit.edu>
Cc: Borislav Petkov <bp@alien8.de>
Cc: James Morse <james.morse@arm.com>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-efi@vger.kernel.org
Link: https://lkml.kernel.org/r/20191224151025.32482-24-ardb@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2019-12-24 15:10:23 +00:00
|
|
|
status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS,
|
|
|
|
EFI_LOADER_DATA,
|
|
|
|
*reserve_size / EFI_PAGE_SIZE,
|
|
|
|
(efi_physical_addr_t *)reserve_addr);
|
2016-01-26 13:48:29 +00:00
|
|
|
}
|
2015-07-24 11:38:27 +00:00
|
|
|
|
2016-01-26 13:48:29 +00:00
|
|
|
if (status != EFI_SUCCESS) {
|
|
|
|
*reserve_size = kernel_memsize + TEXT_OFFSET;
|
2019-12-24 15:10:19 +00:00
|
|
|
status = efi_low_alloc(*reserve_size,
|
2016-01-26 13:48:29 +00:00
|
|
|
MIN_KIMG_ALIGN, reserve_addr);
|
|
|
|
|
|
|
|
if (status != EFI_SUCCESS) {
|
2019-12-24 15:10:18 +00:00
|
|
|
pr_efi_err("Failed to relocate kernel\n");
|
2016-01-26 13:48:29 +00:00
|
|
|
*reserve_size = 0;
|
|
|
|
return status;
|
2014-04-16 02:47:52 +00:00
|
|
|
}
|
2016-01-26 13:48:29 +00:00
|
|
|
*image_addr = *reserve_addr + TEXT_OFFSET;
|
2014-04-16 02:47:52 +00:00
|
|
|
}
|
efi/libstub/arm64: Avoid image_base value from efi_loaded_image
Commit:
9f9223778ef3 ("efi/libstub/arm: Make efi_entry() an ordinary PE/COFF entrypoint")
did some code refactoring to get rid of the EFI entry point assembler
code, and in the process, it got rid of the assignment of image_addr
to the value of _text. Instead, it switched to using the image_base
field of the efi_loaded_image struct provided by UEFI, which should
contain the same value.
However, Michael reports that this is not the case: older GRUB builds
corrupt this value in some way, and since we can easily switch back to
referring to _text to discover this value, let's simply do that.
While at it, fix another issue in commit 9f9223778ef3, which may result
in the unassigned image_addr to be misidentified as the preferred load
offset of the kernel, which is unlikely but will cause a boot crash if
it does occur.
Finally, let's add a warning if the _text vs. image_base discrepancy is
detected, so we can tell more easily how widespread this issue actually
is.
Reported-by: Michael Kelley <mikelley@microsoft.com>
Tested-by: Michael Kelley <mikelley@microsoft.com>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-efi@vger.kernel.org
2020-03-29 08:05:43 +00:00
|
|
|
|
|
|
|
if (image->image_base != _text)
|
|
|
|
pr_efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n");
|
|
|
|
|
|
|
|
memcpy((void *)*image_addr, _text, kernel_size);
|
2014-04-16 02:47:52 +00:00
|
|
|
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|