mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-01-14 10:06:07 +07:00
7c116db24d
Since commit82046702e2
("efi/libstub/arm64: Replace 'preferred' offset with alignment check"), loading a relocatable arm64 kernel at a physical address which is not 2MB aligned and subsequently booting with EFI will leave the Image in-place, relying on the kernel to relocate itself early during boot. In conjunction with commitdd4bc60765
("arm64: warn on incorrect placement of the kernel by the bootloader"), which enables CONFIG_RELOCATABLE by default, this effectively means that entering an arm64 kernel loaded at an alignment smaller than 2MB with EFI (e.g. using QEMU) will result in silent relocation at runtime. Unfortunately, this has a subtle but confusing affect for developers trying to inspect the PC value during a crash and comparing it to the symbol addresses in vmlinux using tools such as 'nm' or 'addr2line'; all text addresses will be displaced by a sub-2MB offset, resulting in the wrong symbol being identified in many cases. Passing "nokaslr" on the command line or disabling "CONFIG_RANDOMIZE_BASE" does not help, since the EFI stub only copies the kernel Image to a 2MB boundary if it is not relocatable. Adjust the EFI stub for arm64 so that the minimum Image alignment is 2MB unless KASLR is in use. Cc: Mark Rutland <mark.rutland@arm.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Marc Zyngier <maz@kernel.org> Cc: David Brazdil <dbrazdil@google.com> Acked-by: Ard Biesheuvel <ardb@kernel.org> Signed-off-by: Will Deacon <will@kernel.org>
119 lines
3.3 KiB
C
119 lines
3.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* 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>
|
|
*/
|
|
|
|
|
|
#include <linux/efi.h>
|
|
#include <asm/efi.h>
|
|
#include <asm/memory.h>
|
|
#include <asm/sections.h>
|
|
#include <asm/sysreg.h>
|
|
|
|
#include "efistub.h"
|
|
|
|
efi_status_t check_platform_features(void)
|
|
{
|
|
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))
|
|
efi_err("This 64 KB granular kernel is not supported by your CPU\n");
|
|
else
|
|
efi_err("This 16 KB granular kernel is not supported by your CPU\n");
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Although relocatable kernels can fix up the misalignment with respect to
|
|
* MIN_KIMG_ALIGN, the resulting virtual text addresses are subtly out of
|
|
* sync with those recorded in the vmlinux when kaslr is disabled but the
|
|
* image required relocation anyway. Therefore retain 2M alignment unless
|
|
* KASLR is in use.
|
|
*/
|
|
static u64 min_kimg_align(void)
|
|
{
|
|
return efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN;
|
|
}
|
|
|
|
efi_status_t handle_kernel_image(unsigned long *image_addr,
|
|
unsigned long *image_size,
|
|
unsigned long *reserve_addr,
|
|
unsigned long *reserve_size,
|
|
unsigned long dram_base,
|
|
efi_loaded_image_t *image)
|
|
{
|
|
efi_status_t status;
|
|
unsigned long kernel_size, kernel_memsize = 0;
|
|
u32 phys_seed = 0;
|
|
|
|
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
|
|
if (!efi_nokaslr) {
|
|
status = efi_get_random_bytes(sizeof(phys_seed),
|
|
(u8 *)&phys_seed);
|
|
if (status == EFI_NOT_FOUND) {
|
|
efi_info("EFI_RNG_PROTOCOL unavailable, no randomness supplied\n");
|
|
} else if (status != EFI_SUCCESS) {
|
|
efi_err("efi_get_random_bytes() failed\n");
|
|
return status;
|
|
}
|
|
} else {
|
|
efi_info("KASLR disabled on kernel command line\n");
|
|
}
|
|
}
|
|
|
|
if (image->image_base != _text)
|
|
efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n");
|
|
|
|
kernel_size = _edata - _text;
|
|
kernel_memsize = kernel_size + (_end - _edata);
|
|
*reserve_size = kernel_memsize + TEXT_OFFSET % min_kimg_align();
|
|
|
|
if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) {
|
|
/*
|
|
* If KASLR is enabled, and we have some randomness available,
|
|
* locate the kernel at a randomized offset in physical memory.
|
|
*/
|
|
status = efi_random_alloc(*reserve_size, min_kimg_align(),
|
|
reserve_addr, phys_seed);
|
|
} else {
|
|
status = EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
if (status != EFI_SUCCESS) {
|
|
if (IS_ALIGNED((u64)_text - TEXT_OFFSET, min_kimg_align())) {
|
|
/*
|
|
* Just execute from wherever we were loaded by the
|
|
* UEFI PE/COFF loader if the alignment is suitable.
|
|
*/
|
|
*image_addr = (u64)_text;
|
|
*reserve_size = 0;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
status = efi_allocate_pages_aligned(*reserve_size, reserve_addr,
|
|
ULONG_MAX, min_kimg_align());
|
|
|
|
if (status != EFI_SUCCESS) {
|
|
efi_err("Failed to relocate kernel\n");
|
|
*reserve_size = 0;
|
|
return status;
|
|
}
|
|
}
|
|
|
|
*image_addr = *reserve_addr + TEXT_OFFSET % min_kimg_align();
|
|
memcpy((void *)*image_addr, _text, kernel_size);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|