1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2013, 2014 Linaro Ltd;  <roy.franz@linaro.org>
4  *
5  * This file implements the EFI boot stub for the arm64 kernel.
6  * Adapted from ARM version by Mark Salter <msalter@redhat.com>
7  */
8 
9 
10 #include <linux/efi.h>
11 #include <asm/efi.h>
12 #include <asm/memory.h>
13 #include <asm/sections.h>
14 #include <asm/sysreg.h>
15 
16 #include "efistub.h"
17 
18 efi_status_t check_platform_features(void)
19 {
20 	u64 tg;
21 
22 	/* UEFI mandates support for 4 KB granularity, no need to check */
23 	if (IS_ENABLED(CONFIG_ARM64_4K_PAGES))
24 		return EFI_SUCCESS;
25 
26 	tg = (read_cpuid(ID_AA64MMFR0_EL1) >> ID_AA64MMFR0_TGRAN_SHIFT) & 0xf;
27 	if (tg != ID_AA64MMFR0_TGRAN_SUPPORTED) {
28 		if (IS_ENABLED(CONFIG_ARM64_64K_PAGES))
29 			efi_err("This 64 KB granular kernel is not supported by your CPU\n");
30 		else
31 			efi_err("This 16 KB granular kernel is not supported by your CPU\n");
32 		return EFI_UNSUPPORTED;
33 	}
34 	return EFI_SUCCESS;
35 }
36 
37 /*
38  * Relocatable kernels can fix up the misalignment with respect to
39  * MIN_KIMG_ALIGN, so they only require a minimum alignment of EFI_KIMG_ALIGN
40  * (which accounts for the alignment of statically allocated objects such as
41  * the swapper stack.)
42  */
43 static const u64 min_kimg_align = IS_ENABLED(CONFIG_RELOCATABLE) ? EFI_KIMG_ALIGN
44 								 : MIN_KIMG_ALIGN;
45 
46 efi_status_t handle_kernel_image(unsigned long *image_addr,
47 				 unsigned long *image_size,
48 				 unsigned long *reserve_addr,
49 				 unsigned long *reserve_size,
50 				 unsigned long dram_base,
51 				 efi_loaded_image_t *image)
52 {
53 	efi_status_t status;
54 	unsigned long kernel_size, kernel_memsize = 0;
55 	u32 phys_seed = 0;
56 
57 	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) {
58 		if (!efi_nokaslr) {
59 			status = efi_get_random_bytes(sizeof(phys_seed),
60 						      (u8 *)&phys_seed);
61 			if (status == EFI_NOT_FOUND) {
62 				efi_info("EFI_RNG_PROTOCOL unavailable, no randomness supplied\n");
63 			} else if (status != EFI_SUCCESS) {
64 				efi_err("efi_get_random_bytes() failed\n");
65 				return status;
66 			}
67 		} else {
68 			efi_info("KASLR disabled on kernel command line\n");
69 		}
70 	}
71 
72 	if (image->image_base != _text)
73 		efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n");
74 
75 	kernel_size = _edata - _text;
76 	kernel_memsize = kernel_size + (_end - _edata);
77 	*reserve_size = kernel_memsize + TEXT_OFFSET % min_kimg_align;
78 
79 	if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) {
80 		/*
81 		 * If KASLR is enabled, and we have some randomness available,
82 		 * locate the kernel at a randomized offset in physical memory.
83 		 */
84 		status = efi_random_alloc(*reserve_size, min_kimg_align,
85 					  reserve_addr, phys_seed);
86 	} else {
87 		status = EFI_OUT_OF_RESOURCES;
88 	}
89 
90 	if (status != EFI_SUCCESS) {
91 		if (IS_ALIGNED((u64)_text - TEXT_OFFSET, min_kimg_align)) {
92 			/*
93 			 * Just execute from wherever we were loaded by the
94 			 * UEFI PE/COFF loader if the alignment is suitable.
95 			 */
96 			*image_addr = (u64)_text;
97 			*reserve_size = 0;
98 			return EFI_SUCCESS;
99 		}
100 
101 		status = efi_allocate_pages_aligned(*reserve_size, reserve_addr,
102 						    ULONG_MAX, min_kimg_align);
103 
104 		if (status != EFI_SUCCESS) {
105 			efi_err("Failed to relocate kernel\n");
106 			*reserve_size = 0;
107 			return status;
108 		}
109 	}
110 
111 	*image_addr = *reserve_addr + TEXT_OFFSET % min_kimg_align;
112 	memcpy((void *)*image_addr, _text, kernel_size);
113 
114 	return EFI_SUCCESS;
115 }
116