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 /* 3882046702SArd Biesheuvel * Relocatable kernels can fix up the misalignment with respect to 3982046702SArd Biesheuvel * MIN_KIMG_ALIGN, so they only require a minimum alignment of EFI_KIMG_ALIGN 4082046702SArd Biesheuvel * (which accounts for the alignment of statically allocated objects such as 4182046702SArd Biesheuvel * the swapper stack.) 4282046702SArd Biesheuvel */ 4382046702SArd Biesheuvel static const u64 min_kimg_align = IS_ENABLED(CONFIG_RELOCATABLE) ? EFI_KIMG_ALIGN 4482046702SArd Biesheuvel : MIN_KIMG_ALIGN; 4582046702SArd Biesheuvel 46cd33a5c1SArd Biesheuvel efi_status_t handle_kernel_image(unsigned long *image_addr, 47bf457786SArd Biesheuvel unsigned long *image_size, 48bf457786SArd Biesheuvel unsigned long *reserve_addr, 49bf457786SArd Biesheuvel unsigned long *reserve_size, 50bf457786SArd Biesheuvel unsigned long dram_base, 51bf457786SArd Biesheuvel efi_loaded_image_t *image) 52bf457786SArd Biesheuvel { 53bf457786SArd Biesheuvel efi_status_t status; 54bf457786SArd Biesheuvel unsigned long kernel_size, kernel_memsize = 0; 555d12da9dSArd Biesheuvel u32 phys_seed = 0; 562b5fe07aSArd Biesheuvel 572b5fe07aSArd Biesheuvel if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { 58980771f6SArd Biesheuvel if (!efi_nokaslr) { 59cd33a5c1SArd Biesheuvel status = efi_get_random_bytes(sizeof(phys_seed), 602b5fe07aSArd Biesheuvel (u8 *)&phys_seed); 612b5fe07aSArd Biesheuvel if (status == EFI_NOT_FOUND) { 62793473c2SArvind Sankar efi_info("EFI_RNG_PROTOCOL unavailable, no randomness supplied\n"); 632b5fe07aSArd Biesheuvel } else if (status != EFI_SUCCESS) { 64793473c2SArvind Sankar efi_err("efi_get_random_bytes() failed\n"); 652b5fe07aSArd Biesheuvel return status; 662b5fe07aSArd Biesheuvel } 672b5fe07aSArd Biesheuvel } else { 68793473c2SArvind Sankar efi_info("KASLR disabled on kernel command line\n"); 692b5fe07aSArd Biesheuvel } 702b5fe07aSArd Biesheuvel } 712dc10ad8SLinus Torvalds 7282046702SArd Biesheuvel if (image->image_base != _text) 73793473c2SArvind Sankar efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n"); 74bf457786SArd Biesheuvel 75bf457786SArd Biesheuvel kernel_size = _edata - _text; 76bf457786SArd Biesheuvel kernel_memsize = kernel_size + (_end - _edata); 775d12da9dSArd Biesheuvel *reserve_size = kernel_memsize + TEXT_OFFSET % min_kimg_align; 78bf457786SArd Biesheuvel 792b5fe07aSArd Biesheuvel if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) { 80bf457786SArd Biesheuvel /* 812b5fe07aSArd Biesheuvel * If KASLR is enabled, and we have some randomness available, 822b5fe07aSArd Biesheuvel * locate the kernel at a randomized offset in physical memory. 832b5fe07aSArd Biesheuvel */ 845d12da9dSArd Biesheuvel status = efi_random_alloc(*reserve_size, min_kimg_align, 855d12da9dSArd Biesheuvel reserve_addr, phys_seed); 862b5fe07aSArd Biesheuvel } else { 8782046702SArd Biesheuvel status = EFI_OUT_OF_RESOURCES; 882b5fe07aSArd Biesheuvel } 892b5fe07aSArd Biesheuvel 90bf457786SArd Biesheuvel if (status != EFI_SUCCESS) { 9182046702SArd Biesheuvel if (IS_ALIGNED((u64)_text - TEXT_OFFSET, min_kimg_align)) { 9282046702SArd Biesheuvel /* 9382046702SArd Biesheuvel * Just execute from wherever we were loaded by the 9482046702SArd Biesheuvel * UEFI PE/COFF loader if the alignment is suitable. 9582046702SArd Biesheuvel */ 9682046702SArd Biesheuvel *image_addr = (u64)_text; 9782046702SArd Biesheuvel *reserve_size = 0; 9882046702SArd Biesheuvel return EFI_SUCCESS; 9982046702SArd Biesheuvel } 10082046702SArd Biesheuvel 101e71356feSArd Biesheuvel status = efi_allocate_pages_aligned(*reserve_size, reserve_addr, 102e71356feSArd Biesheuvel ULONG_MAX, min_kimg_align); 103bf457786SArd Biesheuvel 104bf457786SArd Biesheuvel if (status != EFI_SUCCESS) { 105793473c2SArvind Sankar efi_err("Failed to relocate kernel\n"); 1062b5fe07aSArd Biesheuvel *reserve_size = 0; 107bf457786SArd Biesheuvel return status; 108bf457786SArd Biesheuvel } 109bf457786SArd Biesheuvel } 110c2136dceSArd Biesheuvel 1115d12da9dSArd Biesheuvel *image_addr = *reserve_addr + TEXT_OFFSET % min_kimg_align; 112c2136dceSArd Biesheuvel memcpy((void *)*image_addr, _text, kernel_size); 113bf457786SArd Biesheuvel 114bf457786SArd Biesheuvel return EFI_SUCCESS; 115bf457786SArd Biesheuvel } 116