14febfb8dSArd Biesheuvel // SPDX-License-Identifier: GPL-2.0 2bf457786SArd Biesheuvel /* 3bf457786SArd Biesheuvel * Copyright (C) 2013, 2014 Linaro Ltd; <roy.franz@linaro.org> 4bf457786SArd Biesheuvel * 5bf457786SArd Biesheuvel * This file implements the EFI boot stub for the arm64 kernel. 6bf457786SArd Biesheuvel * Adapted from ARM version by Mark Salter <msalter@redhat.com> 7bf457786SArd Biesheuvel */ 80426a4e6SArd Biesheuvel 90426a4e6SArd Biesheuvel 10bf457786SArd Biesheuvel #include <linux/efi.h> 11bf457786SArd Biesheuvel #include <asm/efi.h> 12170976bcSMark Rutland #include <asm/memory.h> 136f05106eSArd Biesheuvel #include <asm/sections.h> 1442b55734SArd Biesheuvel #include <asm/sysreg.h> 15bf457786SArd Biesheuvel 162b5fe07aSArd Biesheuvel #include "efistub.h" 172b5fe07aSArd Biesheuvel 18cd33a5c1SArd Biesheuvel efi_status_t check_platform_features(void) 1942b55734SArd Biesheuvel { 2042b55734SArd Biesheuvel u64 tg; 2142b55734SArd Biesheuvel 2242b55734SArd Biesheuvel /* UEFI mandates support for 4 KB granularity, no need to check */ 2342b55734SArd Biesheuvel if (IS_ENABLED(CONFIG_ARM64_4K_PAGES)) 2442b55734SArd Biesheuvel return EFI_SUCCESS; 2542b55734SArd Biesheuvel 2642b55734SArd Biesheuvel tg = (read_cpuid(ID_AA64MMFR0_EL1) >> ID_AA64MMFR0_TGRAN_SHIFT) & 0xf; 2742b55734SArd Biesheuvel if (tg != ID_AA64MMFR0_TGRAN_SUPPORTED) { 2842b55734SArd Biesheuvel if (IS_ENABLED(CONFIG_ARM64_64K_PAGES)) 29793473c2SArvind Sankar efi_err("This 64 KB granular kernel is not supported by your CPU\n"); 3042b55734SArd Biesheuvel else 31793473c2SArvind Sankar efi_err("This 16 KB granular kernel is not supported by your CPU\n"); 3242b55734SArd Biesheuvel return EFI_UNSUPPORTED; 3342b55734SArd Biesheuvel } 3442b55734SArd Biesheuvel return EFI_SUCCESS; 3542b55734SArd Biesheuvel } 36bf457786SArd Biesheuvel 3782046702SArd Biesheuvel /* 387c116db2SWill Deacon * Although relocatable kernels can fix up the misalignment with respect to 397c116db2SWill Deacon * MIN_KIMG_ALIGN, the resulting virtual text addresses are subtly out of 407c116db2SWill Deacon * sync with those recorded in the vmlinux when kaslr is disabled but the 417c116db2SWill Deacon * image required relocation anyway. Therefore retain 2M alignment unless 427c116db2SWill Deacon * KASLR is in use. 4382046702SArd Biesheuvel */ 447c116db2SWill Deacon static u64 min_kimg_align(void) 457c116db2SWill Deacon { 467c116db2SWill Deacon return efi_nokaslr ? MIN_KIMG_ALIGN : EFI_KIMG_ALIGN; 477c116db2SWill Deacon } 4882046702SArd Biesheuvel 49cd33a5c1SArd Biesheuvel efi_status_t handle_kernel_image(unsigned long *image_addr, 50bf457786SArd Biesheuvel unsigned long *image_size, 51bf457786SArd Biesheuvel unsigned long *reserve_addr, 52bf457786SArd Biesheuvel unsigned long *reserve_size, 53bf457786SArd Biesheuvel unsigned long dram_base, 54bf457786SArd Biesheuvel efi_loaded_image_t *image) 55bf457786SArd Biesheuvel { 56bf457786SArd Biesheuvel efi_status_t status; 57bf457786SArd Biesheuvel unsigned long kernel_size, kernel_memsize = 0; 585d12da9dSArd Biesheuvel u32 phys_seed = 0; 592b5fe07aSArd Biesheuvel 602b5fe07aSArd Biesheuvel if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { 61980771f6SArd Biesheuvel if (!efi_nokaslr) { 62cd33a5c1SArd Biesheuvel status = efi_get_random_bytes(sizeof(phys_seed), 632b5fe07aSArd Biesheuvel (u8 *)&phys_seed); 642b5fe07aSArd Biesheuvel if (status == EFI_NOT_FOUND) { 65793473c2SArvind Sankar efi_info("EFI_RNG_PROTOCOL unavailable, no randomness supplied\n"); 662b5fe07aSArd Biesheuvel } else if (status != EFI_SUCCESS) { 67793473c2SArvind Sankar efi_err("efi_get_random_bytes() failed\n"); 682b5fe07aSArd Biesheuvel return status; 692b5fe07aSArd Biesheuvel } 702b5fe07aSArd Biesheuvel } else { 71793473c2SArvind Sankar efi_info("KASLR disabled on kernel command line\n"); 722b5fe07aSArd Biesheuvel } 732b5fe07aSArd Biesheuvel } 742dc10ad8SLinus Torvalds 7582046702SArd Biesheuvel if (image->image_base != _text) 76793473c2SArvind Sankar efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n"); 77bf457786SArd Biesheuvel 78bf457786SArd Biesheuvel kernel_size = _edata - _text; 79bf457786SArd Biesheuvel kernel_memsize = kernel_size + (_end - _edata); 80120dc60dSArd Biesheuvel *reserve_size = kernel_memsize; 81bf457786SArd Biesheuvel 822b5fe07aSArd Biesheuvel if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) { 83bf457786SArd Biesheuvel /* 842b5fe07aSArd Biesheuvel * If KASLR is enabled, and we have some randomness available, 852b5fe07aSArd Biesheuvel * locate the kernel at a randomized offset in physical memory. 862b5fe07aSArd Biesheuvel */ 877c116db2SWill Deacon status = efi_random_alloc(*reserve_size, min_kimg_align(), 885d12da9dSArd Biesheuvel reserve_addr, phys_seed); 892b5fe07aSArd Biesheuvel } else { 9082046702SArd Biesheuvel status = EFI_OUT_OF_RESOURCES; 912b5fe07aSArd Biesheuvel } 922b5fe07aSArd Biesheuvel 93bf457786SArd Biesheuvel if (status != EFI_SUCCESS) { 94120dc60dSArd Biesheuvel if (IS_ALIGNED((u64)_text, min_kimg_align())) { 9582046702SArd Biesheuvel /* 9682046702SArd Biesheuvel * Just execute from wherever we were loaded by the 9782046702SArd Biesheuvel * UEFI PE/COFF loader if the alignment is suitable. 9882046702SArd Biesheuvel */ 9982046702SArd Biesheuvel *image_addr = (u64)_text; 10082046702SArd Biesheuvel *reserve_size = 0; 10182046702SArd Biesheuvel return EFI_SUCCESS; 10282046702SArd Biesheuvel } 10382046702SArd Biesheuvel 104e71356feSArd Biesheuvel status = efi_allocate_pages_aligned(*reserve_size, reserve_addr, 1057c116db2SWill Deacon ULONG_MAX, min_kimg_align()); 106bf457786SArd Biesheuvel 107bf457786SArd Biesheuvel if (status != EFI_SUCCESS) { 108793473c2SArvind Sankar efi_err("Failed to relocate kernel\n"); 1092b5fe07aSArd Biesheuvel *reserve_size = 0; 110bf457786SArd Biesheuvel return status; 111bf457786SArd Biesheuvel } 112bf457786SArd Biesheuvel } 113c2136dceSArd Biesheuvel 114120dc60dSArd Biesheuvel *image_addr = *reserve_addr; 115c2136dceSArd Biesheuvel memcpy((void *)*image_addr, _text, kernel_size); 116bf457786SArd Biesheuvel 117bf457786SArd Biesheuvel return EFI_SUCCESS; 118bf457786SArd Biesheuvel } 119