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