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