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 pr_efi_err("This 64 KB granular kernel is not supported by your CPU\n"); 30 else 31 pr_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 efi_status_t handle_kernel_image(unsigned long *image_addr, 38 unsigned long *image_size, 39 unsigned long *reserve_addr, 40 unsigned long *reserve_size, 41 unsigned long dram_base, 42 efi_loaded_image_t *image) 43 { 44 efi_status_t status; 45 unsigned long kernel_size, kernel_memsize = 0; 46 unsigned long preferred_offset; 47 u64 phys_seed = 0; 48 49 if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { 50 if (!nokaslr()) { 51 status = efi_get_random_bytes(sizeof(phys_seed), 52 (u8 *)&phys_seed); 53 if (status == EFI_NOT_FOUND) { 54 pr_efi("EFI_RNG_PROTOCOL unavailable, no randomness supplied\n"); 55 } else if (status != EFI_SUCCESS) { 56 pr_efi_err("efi_get_random_bytes() failed\n"); 57 return status; 58 } 59 } else { 60 pr_efi("KASLR disabled on kernel command line\n"); 61 } 62 } 63 64 /* 65 * The preferred offset of the kernel Image is TEXT_OFFSET bytes beyond 66 * a 2 MB aligned base, which itself may be lower than dram_base, as 67 * long as the resulting offset equals or exceeds it. 68 */ 69 preferred_offset = round_down(dram_base, MIN_KIMG_ALIGN) + TEXT_OFFSET; 70 if (preferred_offset < dram_base) 71 preferred_offset += MIN_KIMG_ALIGN; 72 73 kernel_size = _edata - _text; 74 kernel_memsize = kernel_size + (_end - _edata); 75 76 if (IS_ENABLED(CONFIG_RANDOMIZE_BASE) && phys_seed != 0) { 77 /* 78 * If CONFIG_DEBUG_ALIGN_RODATA is not set, produce a 79 * displacement in the interval [0, MIN_KIMG_ALIGN) that 80 * doesn't violate this kernel's de-facto alignment 81 * constraints. 82 */ 83 u32 mask = (MIN_KIMG_ALIGN - 1) & ~(EFI_KIMG_ALIGN - 1); 84 u32 offset = !IS_ENABLED(CONFIG_DEBUG_ALIGN_RODATA) ? 85 (phys_seed >> 32) & mask : TEXT_OFFSET; 86 87 /* 88 * With CONFIG_RANDOMIZE_TEXT_OFFSET=y, TEXT_OFFSET may not 89 * be a multiple of EFI_KIMG_ALIGN, and we must ensure that 90 * we preserve the misalignment of 'offset' relative to 91 * EFI_KIMG_ALIGN so that statically allocated objects whose 92 * alignment exceeds PAGE_SIZE appear correctly aligned in 93 * memory. 94 */ 95 offset |= TEXT_OFFSET % EFI_KIMG_ALIGN; 96 97 /* 98 * If KASLR is enabled, and we have some randomness available, 99 * locate the kernel at a randomized offset in physical memory. 100 */ 101 *reserve_size = kernel_memsize + offset; 102 status = efi_random_alloc(*reserve_size, 103 MIN_KIMG_ALIGN, reserve_addr, 104 (u32)phys_seed); 105 106 *image_addr = *reserve_addr + offset; 107 } else { 108 /* 109 * Else, try a straight allocation at the preferred offset. 110 * This will work around the issue where, if dram_base == 0x0, 111 * efi_low_alloc() refuses to allocate at 0x0 (to prevent the 112 * address of the allocation to be mistaken for a FAIL return 113 * value or a NULL pointer). It will also ensure that, on 114 * platforms where the [dram_base, dram_base + TEXT_OFFSET) 115 * interval is partially occupied by the firmware (like on APM 116 * Mustang), we can still place the kernel at the address 117 * 'dram_base + TEXT_OFFSET'. 118 */ 119 *image_addr = (unsigned long)_text; 120 if (*image_addr == preferred_offset) 121 return EFI_SUCCESS; 122 123 *image_addr = *reserve_addr = preferred_offset; 124 *reserve_size = round_up(kernel_memsize, EFI_ALLOC_ALIGN); 125 126 status = efi_bs_call(allocate_pages, EFI_ALLOCATE_ADDRESS, 127 EFI_LOADER_DATA, 128 *reserve_size / EFI_PAGE_SIZE, 129 (efi_physical_addr_t *)reserve_addr); 130 } 131 132 if (status != EFI_SUCCESS) { 133 *reserve_size = kernel_memsize + TEXT_OFFSET; 134 status = efi_low_alloc(*reserve_size, 135 MIN_KIMG_ALIGN, reserve_addr); 136 137 if (status != EFI_SUCCESS) { 138 pr_efi_err("Failed to relocate kernel\n"); 139 *reserve_size = 0; 140 return status; 141 } 142 *image_addr = *reserve_addr + TEXT_OFFSET; 143 } 144 145 if (image->image_base != _text) 146 pr_efi_err("FIRMWARE BUG: efi_loaded_image_t::image_base has bogus value\n"); 147 148 memcpy((void *)*image_addr, _text, kernel_size); 149 150 return EFI_SUCCESS; 151 } 152