14febfb8dSArd Biesheuvel // SPDX-License-Identifier: GPL-2.0 281a0bc39SRoy Franz /* 381a0bc39SRoy Franz * Copyright (C) 2013 Linaro Ltd; <roy.franz@linaro.org> 481a0bc39SRoy Franz */ 581a0bc39SRoy Franz #include <linux/efi.h> 681a0bc39SRoy Franz #include <asm/efi.h> 781a0bc39SRoy Franz 8eeff7d63SArd Biesheuvel #include "efistub.h" 9eeff7d63SArd Biesheuvel 102a55280aSArd Biesheuvel static efi_guid_t cpu_state_guid = LINUX_EFI_ARM_CPU_STATE_TABLE_GUID; 112a55280aSArd Biesheuvel 122a55280aSArd Biesheuvel struct efi_arm_entry_state *efi_entry_state; 132a55280aSArd Biesheuvel 142a55280aSArd Biesheuvel static void get_cpu_state(u32 *cpsr, u32 *sctlr) 152a55280aSArd Biesheuvel { 162a55280aSArd Biesheuvel asm("mrs %0, cpsr" : "=r"(*cpsr)); 172a55280aSArd Biesheuvel if ((*cpsr & MODE_MASK) == HYP_MODE) 182a55280aSArd Biesheuvel asm("mrc p15, 4, %0, c1, c0, 0" : "=r"(*sctlr)); 192a55280aSArd Biesheuvel else 202a55280aSArd Biesheuvel asm("mrc p15, 0, %0, c1, c0, 0" : "=r"(*sctlr)); 212a55280aSArd Biesheuvel } 222a55280aSArd Biesheuvel 23cd33a5c1SArd Biesheuvel efi_status_t check_platform_features(void) 242ec0f0a3SArd Biesheuvel { 252a55280aSArd Biesheuvel efi_status_t status; 262a55280aSArd Biesheuvel u32 cpsr, sctlr; 272ec0f0a3SArd Biesheuvel int block; 282ec0f0a3SArd Biesheuvel 292a55280aSArd Biesheuvel get_cpu_state(&cpsr, &sctlr); 302a55280aSArd Biesheuvel 312a55280aSArd Biesheuvel efi_info("Entering in %s mode with MMU %sabled\n", 322a55280aSArd Biesheuvel ((cpsr & MODE_MASK) == HYP_MODE) ? "HYP" : "SVC", 332a55280aSArd Biesheuvel (sctlr & 1) ? "en" : "dis"); 342a55280aSArd Biesheuvel 352a55280aSArd Biesheuvel status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, 362a55280aSArd Biesheuvel sizeof(*efi_entry_state), 372a55280aSArd Biesheuvel (void **)&efi_entry_state); 382a55280aSArd Biesheuvel if (status != EFI_SUCCESS) { 392a55280aSArd Biesheuvel efi_err("allocate_pool() failed\n"); 402a55280aSArd Biesheuvel return status; 412a55280aSArd Biesheuvel } 422a55280aSArd Biesheuvel 432a55280aSArd Biesheuvel efi_entry_state->cpsr_before_ebs = cpsr; 442a55280aSArd Biesheuvel efi_entry_state->sctlr_before_ebs = sctlr; 452a55280aSArd Biesheuvel 462a55280aSArd Biesheuvel status = efi_bs_call(install_configuration_table, &cpu_state_guid, 472a55280aSArd Biesheuvel efi_entry_state); 482a55280aSArd Biesheuvel if (status != EFI_SUCCESS) { 492a55280aSArd Biesheuvel efi_err("install_configuration_table() failed\n"); 502a55280aSArd Biesheuvel goto free_state; 512a55280aSArd Biesheuvel } 522a55280aSArd Biesheuvel 532ec0f0a3SArd Biesheuvel /* non-LPAE kernels can run anywhere */ 542ec0f0a3SArd Biesheuvel if (!IS_ENABLED(CONFIG_ARM_LPAE)) 552ec0f0a3SArd Biesheuvel return EFI_SUCCESS; 562ec0f0a3SArd Biesheuvel 572ec0f0a3SArd Biesheuvel /* LPAE kernels need compatible hardware */ 582ec0f0a3SArd Biesheuvel block = cpuid_feature_extract(CPUID_EXT_MMFR0, 0); 592ec0f0a3SArd Biesheuvel if (block < 5) { 60793473c2SArvind Sankar efi_err("This LPAE kernel is not supported by your CPU\n"); 612a55280aSArd Biesheuvel status = EFI_UNSUPPORTED; 622a55280aSArd Biesheuvel goto drop_table; 632ec0f0a3SArd Biesheuvel } 642ec0f0a3SArd Biesheuvel return EFI_SUCCESS; 652a55280aSArd Biesheuvel 662a55280aSArd Biesheuvel drop_table: 672a55280aSArd Biesheuvel efi_bs_call(install_configuration_table, &cpu_state_guid, NULL); 682a55280aSArd Biesheuvel free_state: 692a55280aSArd Biesheuvel efi_bs_call(free_pool, efi_entry_state); 702a55280aSArd Biesheuvel return status; 712a55280aSArd Biesheuvel } 722a55280aSArd Biesheuvel 732a55280aSArd Biesheuvel void efi_handle_post_ebs_state(void) 742a55280aSArd Biesheuvel { 752a55280aSArd Biesheuvel get_cpu_state(&efi_entry_state->cpsr_after_ebs, 762a55280aSArd Biesheuvel &efi_entry_state->sctlr_after_ebs); 772ec0f0a3SArd Biesheuvel } 782ec0f0a3SArd Biesheuvel 79801820beSArd Biesheuvel static efi_guid_t screen_info_guid = LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID; 80801820beSArd Biesheuvel 81cd33a5c1SArd Biesheuvel struct screen_info *alloc_screen_info(void) 82801820beSArd Biesheuvel { 83801820beSArd Biesheuvel struct screen_info *si; 84801820beSArd Biesheuvel efi_status_t status; 85801820beSArd Biesheuvel 86801820beSArd Biesheuvel /* 87801820beSArd Biesheuvel * Unlike on arm64, where we can directly fill out the screen_info 88801820beSArd Biesheuvel * structure from the stub, we need to allocate a buffer to hold 89801820beSArd Biesheuvel * its contents while we hand over to the kernel proper from the 90801820beSArd Biesheuvel * decompressor. 91801820beSArd Biesheuvel */ 92966291f6SArd Biesheuvel status = efi_bs_call(allocate_pool, EFI_RUNTIME_SERVICES_DATA, 93801820beSArd Biesheuvel sizeof(*si), (void **)&si); 94801820beSArd Biesheuvel 95801820beSArd Biesheuvel if (status != EFI_SUCCESS) 96801820beSArd Biesheuvel return NULL; 97801820beSArd Biesheuvel 98966291f6SArd Biesheuvel status = efi_bs_call(install_configuration_table, 99801820beSArd Biesheuvel &screen_info_guid, si); 100801820beSArd Biesheuvel if (status == EFI_SUCCESS) 101801820beSArd Biesheuvel return si; 102801820beSArd Biesheuvel 103966291f6SArd Biesheuvel efi_bs_call(free_pool, si); 104801820beSArd Biesheuvel return NULL; 105801820beSArd Biesheuvel } 106801820beSArd Biesheuvel 107cd33a5c1SArd Biesheuvel void free_screen_info(struct screen_info *si) 108801820beSArd Biesheuvel { 109801820beSArd Biesheuvel if (!si) 110801820beSArd Biesheuvel return; 111801820beSArd Biesheuvel 112966291f6SArd Biesheuvel efi_bs_call(install_configuration_table, &screen_info_guid, NULL); 113966291f6SArd Biesheuvel efi_bs_call(free_pool, si); 114801820beSArd Biesheuvel } 115801820beSArd Biesheuvel 116cd33a5c1SArd Biesheuvel static efi_status_t reserve_kernel_base(unsigned long dram_base, 117318532bfSArd Biesheuvel unsigned long *reserve_addr, 118318532bfSArd Biesheuvel unsigned long *reserve_size) 11981a0bc39SRoy Franz { 12081a0bc39SRoy Franz efi_physical_addr_t alloc_addr; 121318532bfSArd Biesheuvel efi_memory_desc_t *memory_map; 122318532bfSArd Biesheuvel unsigned long nr_pages, map_size, desc_size, buff_size; 123318532bfSArd Biesheuvel efi_status_t status; 124318532bfSArd Biesheuvel unsigned long l; 12581a0bc39SRoy Franz 126318532bfSArd Biesheuvel struct efi_boot_memmap map = { 127318532bfSArd Biesheuvel .map = &memory_map, 128318532bfSArd Biesheuvel .map_size = &map_size, 129318532bfSArd Biesheuvel .desc_size = &desc_size, 130318532bfSArd Biesheuvel .desc_ver = NULL, 131318532bfSArd Biesheuvel .key_ptr = NULL, 132318532bfSArd Biesheuvel .buff_size = &buff_size, 133318532bfSArd Biesheuvel }; 13481a0bc39SRoy Franz 13581a0bc39SRoy Franz /* 13681a0bc39SRoy Franz * Reserve memory for the uncompressed kernel image. This is 13781a0bc39SRoy Franz * all that prevents any future allocations from conflicting 13881a0bc39SRoy Franz * with the kernel. Since we can't tell from the compressed 13981a0bc39SRoy Franz * image how much DRAM the kernel actually uses (due to BSS 14081a0bc39SRoy Franz * size uncertainty) we allocate the maximum possible size. 14181a0bc39SRoy Franz * Do this very early, as prints can cause memory allocations 14281a0bc39SRoy Franz * that may conflict with this. 14381a0bc39SRoy Franz */ 144318532bfSArd Biesheuvel alloc_addr = dram_base + MAX_UNCOMP_KERNEL_SIZE; 145318532bfSArd Biesheuvel nr_pages = MAX_UNCOMP_KERNEL_SIZE / EFI_PAGE_SIZE; 146966291f6SArd Biesheuvel status = efi_bs_call(allocate_pages, EFI_ALLOCATE_MAX_ADDRESS, 147318532bfSArd Biesheuvel EFI_BOOT_SERVICES_DATA, nr_pages, &alloc_addr); 148318532bfSArd Biesheuvel if (status == EFI_SUCCESS) { 149318532bfSArd Biesheuvel if (alloc_addr == dram_base) { 150318532bfSArd Biesheuvel *reserve_addr = alloc_addr; 15181a0bc39SRoy Franz *reserve_size = MAX_UNCOMP_KERNEL_SIZE; 152318532bfSArd Biesheuvel return EFI_SUCCESS; 153318532bfSArd Biesheuvel } 154318532bfSArd Biesheuvel /* 155318532bfSArd Biesheuvel * If we end up here, the allocation succeeded but starts below 156318532bfSArd Biesheuvel * dram_base. This can only occur if the real base of DRAM is 157318532bfSArd Biesheuvel * not a multiple of 128 MB, in which case dram_base will have 158318532bfSArd Biesheuvel * been rounded up. Since this implies that a part of the region 159318532bfSArd Biesheuvel * was already occupied, we need to fall through to the code 160318532bfSArd Biesheuvel * below to ensure that the existing allocations don't conflict. 161318532bfSArd Biesheuvel * For this reason, we use EFI_BOOT_SERVICES_DATA above and not 162318532bfSArd Biesheuvel * EFI_LOADER_DATA, which we wouldn't able to distinguish from 163318532bfSArd Biesheuvel * allocations that we want to disallow. 164318532bfSArd Biesheuvel */ 165318532bfSArd Biesheuvel } 166318532bfSArd Biesheuvel 167318532bfSArd Biesheuvel /* 168318532bfSArd Biesheuvel * If the allocation above failed, we may still be able to proceed: 169318532bfSArd Biesheuvel * if the only allocations in the region are of types that will be 170318532bfSArd Biesheuvel * released to the OS after ExitBootServices(), the decompressor can 171318532bfSArd Biesheuvel * safely overwrite them. 172318532bfSArd Biesheuvel */ 173cd33a5c1SArd Biesheuvel status = efi_get_memory_map(&map); 17481a0bc39SRoy Franz if (status != EFI_SUCCESS) { 175793473c2SArvind Sankar efi_err("reserve_kernel_base(): Unable to retrieve memory map.\n"); 176318532bfSArd Biesheuvel return status; 177318532bfSArd Biesheuvel } 178318532bfSArd Biesheuvel 179318532bfSArd Biesheuvel for (l = 0; l < map_size; l += desc_size) { 180318532bfSArd Biesheuvel efi_memory_desc_t *desc; 181318532bfSArd Biesheuvel u64 start, end; 182318532bfSArd Biesheuvel 183318532bfSArd Biesheuvel desc = (void *)memory_map + l; 184318532bfSArd Biesheuvel start = desc->phys_addr; 185318532bfSArd Biesheuvel end = start + desc->num_pages * EFI_PAGE_SIZE; 186318532bfSArd Biesheuvel 187318532bfSArd Biesheuvel /* Skip if entry does not intersect with region */ 188318532bfSArd Biesheuvel if (start >= dram_base + MAX_UNCOMP_KERNEL_SIZE || 189318532bfSArd Biesheuvel end <= dram_base) 190318532bfSArd Biesheuvel continue; 191318532bfSArd Biesheuvel 192318532bfSArd Biesheuvel switch (desc->type) { 193318532bfSArd Biesheuvel case EFI_BOOT_SERVICES_CODE: 194318532bfSArd Biesheuvel case EFI_BOOT_SERVICES_DATA: 195318532bfSArd Biesheuvel /* Ignore types that are released to the OS anyway */ 196318532bfSArd Biesheuvel continue; 197318532bfSArd Biesheuvel 198318532bfSArd Biesheuvel case EFI_CONVENTIONAL_MEMORY: 19916993c0fSDan Williams /* Skip soft reserved conventional memory */ 20016993c0fSDan Williams if (efi_soft_reserve_enabled() && 20116993c0fSDan Williams (desc->attribute & EFI_MEMORY_SP)) 20216993c0fSDan Williams continue; 20316993c0fSDan Williams 204318532bfSArd Biesheuvel /* 205318532bfSArd Biesheuvel * Reserve the intersection between this entry and the 206318532bfSArd Biesheuvel * region. 207318532bfSArd Biesheuvel */ 208318532bfSArd Biesheuvel start = max(start, (u64)dram_base); 209318532bfSArd Biesheuvel end = min(end, (u64)dram_base + MAX_UNCOMP_KERNEL_SIZE); 210318532bfSArd Biesheuvel 211966291f6SArd Biesheuvel status = efi_bs_call(allocate_pages, 212318532bfSArd Biesheuvel EFI_ALLOCATE_ADDRESS, 213318532bfSArd Biesheuvel EFI_LOADER_DATA, 214318532bfSArd Biesheuvel (end - start) / EFI_PAGE_SIZE, 215318532bfSArd Biesheuvel &start); 216318532bfSArd Biesheuvel if (status != EFI_SUCCESS) { 217793473c2SArvind Sankar efi_err("reserve_kernel_base(): alloc failed.\n"); 218318532bfSArd Biesheuvel goto out; 219318532bfSArd Biesheuvel } 220318532bfSArd Biesheuvel break; 221318532bfSArd Biesheuvel 222318532bfSArd Biesheuvel case EFI_LOADER_CODE: 223318532bfSArd Biesheuvel case EFI_LOADER_DATA: 224318532bfSArd Biesheuvel /* 225318532bfSArd Biesheuvel * These regions may be released and reallocated for 226318532bfSArd Biesheuvel * another purpose (including EFI_RUNTIME_SERVICE_DATA) 227318532bfSArd Biesheuvel * at any time during the execution of the OS loader, 228318532bfSArd Biesheuvel * so we cannot consider them as safe. 229318532bfSArd Biesheuvel */ 230318532bfSArd Biesheuvel default: 231318532bfSArd Biesheuvel /* 232318532bfSArd Biesheuvel * Treat any other allocation in the region as unsafe */ 233318532bfSArd Biesheuvel status = EFI_OUT_OF_RESOURCES; 234318532bfSArd Biesheuvel goto out; 235318532bfSArd Biesheuvel } 236318532bfSArd Biesheuvel } 237318532bfSArd Biesheuvel 238318532bfSArd Biesheuvel status = EFI_SUCCESS; 239318532bfSArd Biesheuvel out: 240966291f6SArd Biesheuvel efi_bs_call(free_pool, memory_map); 241318532bfSArd Biesheuvel return status; 242318532bfSArd Biesheuvel } 243318532bfSArd Biesheuvel 244cd33a5c1SArd Biesheuvel efi_status_t handle_kernel_image(unsigned long *image_addr, 245318532bfSArd Biesheuvel unsigned long *image_size, 246318532bfSArd Biesheuvel unsigned long *reserve_addr, 247318532bfSArd Biesheuvel unsigned long *reserve_size, 248318532bfSArd Biesheuvel unsigned long dram_base, 249318532bfSArd Biesheuvel efi_loaded_image_t *image) 250318532bfSArd Biesheuvel { 25141cd96faSArd Biesheuvel unsigned long kernel_base; 252318532bfSArd Biesheuvel efi_status_t status; 253318532bfSArd Biesheuvel 254d0f9ca9bSArd Biesheuvel /* use a 16 MiB aligned base for the decompressed kernel */ 255d0f9ca9bSArd Biesheuvel kernel_base = round_up(dram_base, SZ_16M) + TEXT_OFFSET; 256318532bfSArd Biesheuvel 25741cd96faSArd Biesheuvel /* 25841cd96faSArd Biesheuvel * Note that some platforms (notably, the Raspberry Pi 2) put 25941cd96faSArd Biesheuvel * spin-tables and other pieces of firmware at the base of RAM, 26041cd96faSArd Biesheuvel * abusing the fact that the window of TEXT_OFFSET bytes at the 26141cd96faSArd Biesheuvel * base of the kernel image is only partially used at the moment. 26241cd96faSArd Biesheuvel * (Up to 5 pages are used for the swapper page tables) 26341cd96faSArd Biesheuvel */ 264d0f9ca9bSArd Biesheuvel status = reserve_kernel_base(kernel_base - 5 * PAGE_SIZE, reserve_addr, 265d0f9ca9bSArd Biesheuvel reserve_size); 266318532bfSArd Biesheuvel if (status != EFI_SUCCESS) { 267793473c2SArvind Sankar efi_err("Unable to allocate memory for uncompressed kernel.\n"); 26881a0bc39SRoy Franz return status; 26981a0bc39SRoy Franz } 27081a0bc39SRoy Franz 271d0f9ca9bSArd Biesheuvel *image_addr = kernel_base; 27281a0bc39SRoy Franz *image_size = 0; 27381a0bc39SRoy Franz return EFI_SUCCESS; 27481a0bc39SRoy Franz } 275