1d9ffe524SArd Biesheuvel // SPDX-License-Identifier: GPL-2.0 2d9ffe524SArd Biesheuvel /* 3d9ffe524SArd Biesheuvel * Copyright (C) 2013, 2014 Linaro Ltd; <roy.franz@linaro.org> 4d9ffe524SArd Biesheuvel * 5d9ffe524SArd Biesheuvel * This file implements the EFI boot stub for the arm64 kernel. 6d9ffe524SArd Biesheuvel * Adapted from ARM version by Mark Salter <msalter@redhat.com> 7d9ffe524SArd Biesheuvel */ 8d9ffe524SArd Biesheuvel 9d9ffe524SArd Biesheuvel 10d9ffe524SArd Biesheuvel #include <linux/efi.h> 11d9ffe524SArd Biesheuvel #include <asm/efi.h> 12d9ffe524SArd Biesheuvel #include <asm/memory.h> 13d9ffe524SArd Biesheuvel #include <asm/sysreg.h> 14d9ffe524SArd Biesheuvel 15d9ffe524SArd Biesheuvel #include "efistub.h" 16d9ffe524SArd Biesheuvel 1797712289SArd Biesheuvel static bool system_needs_vamap(void) 1897712289SArd Biesheuvel { 19*eb684408SArd Biesheuvel const struct efi_smbios_type4_record *record; 20*eb684408SArd Biesheuvel const u32 __aligned(1) *socid; 21*eb684408SArd Biesheuvel const u8 *version; 2297712289SArd Biesheuvel 2397712289SArd Biesheuvel /* 2419023316SDarren Hart * Ampere eMAG, Altra, and Altra Max machines crash in SetTime() if 25*eb684408SArd Biesheuvel * SetVirtualAddressMap() has not been called prior. Most Altra systems 26*eb684408SArd Biesheuvel * can be identified by the SMCCC soc ID, which is conveniently exposed 27*eb684408SArd Biesheuvel * via the type 4 SMBIOS records. Otherwise, test the processor version 28*eb684408SArd Biesheuvel * field. eMAG systems all appear to have the processor version field 29*eb684408SArd Biesheuvel * set to "eMAG". 3097712289SArd Biesheuvel */ 31*eb684408SArd Biesheuvel record = (struct efi_smbios_type4_record *)efi_get_smbios_record(4); 32*eb684408SArd Biesheuvel if (!record) 3397712289SArd Biesheuvel return false; 3497712289SArd Biesheuvel 35*eb684408SArd Biesheuvel socid = (u32 *)record->processor_id; 36*eb684408SArd Biesheuvel switch (*socid & 0xffff000f) { 37*eb684408SArd Biesheuvel static char const altra[] = "Ampere(TM) Altra(TM) Processor"; 38*eb684408SArd Biesheuvel static char const emag[] = "eMAG"; 39*eb684408SArd Biesheuvel 40*eb684408SArd Biesheuvel default: 41*eb684408SArd Biesheuvel version = efi_get_smbios_string(&record->header, 4, 42*eb684408SArd Biesheuvel processor_version); 43*eb684408SArd Biesheuvel if (!version || (strncmp(version, altra, sizeof(altra) - 1) && 44*eb684408SArd Biesheuvel strncmp(version, emag, sizeof(emag) - 1))) 45*eb684408SArd Biesheuvel break; 46*eb684408SArd Biesheuvel 47*eb684408SArd Biesheuvel fallthrough; 48*eb684408SArd Biesheuvel 49*eb684408SArd Biesheuvel case 0x0a160001: // Altra 50*eb684408SArd Biesheuvel case 0x0a160002: // Altra Max 5197712289SArd Biesheuvel efi_warn("Working around broken SetVirtualAddressMap()\n"); 5297712289SArd Biesheuvel return true; 5397712289SArd Biesheuvel } 5497712289SArd Biesheuvel 55*eb684408SArd Biesheuvel return false; 56*eb684408SArd Biesheuvel } 57*eb684408SArd Biesheuvel 58d9ffe524SArd Biesheuvel efi_status_t check_platform_features(void) 59d9ffe524SArd Biesheuvel { 60d9ffe524SArd Biesheuvel u64 tg; 61d9ffe524SArd Biesheuvel 62d9ffe524SArd Biesheuvel /* 63d9ffe524SArd Biesheuvel * If we have 48 bits of VA space for TTBR0 mappings, we can map the 64d9ffe524SArd Biesheuvel * UEFI runtime regions 1:1 and so calling SetVirtualAddressMap() is 65d9ffe524SArd Biesheuvel * unnecessary. 66d9ffe524SArd Biesheuvel */ 6797712289SArd Biesheuvel if (VA_BITS_MIN >= 48 && !system_needs_vamap()) 68d9ffe524SArd Biesheuvel efi_novamap = true; 69d9ffe524SArd Biesheuvel 70d9ffe524SArd Biesheuvel /* UEFI mandates support for 4 KB granularity, no need to check */ 71d9ffe524SArd Biesheuvel if (IS_ENABLED(CONFIG_ARM64_4K_PAGES)) 72d9ffe524SArd Biesheuvel return EFI_SUCCESS; 73d9ffe524SArd Biesheuvel 74d9ffe524SArd Biesheuvel tg = (read_cpuid(ID_AA64MMFR0_EL1) >> ID_AA64MMFR0_EL1_TGRAN_SHIFT) & 0xf; 75d9ffe524SArd Biesheuvel if (tg < ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN || tg > ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX) { 76d9ffe524SArd Biesheuvel if (IS_ENABLED(CONFIG_ARM64_64K_PAGES)) 77d9ffe524SArd Biesheuvel efi_err("This 64 KB granular kernel is not supported by your CPU\n"); 78d9ffe524SArd Biesheuvel else 79d9ffe524SArd Biesheuvel efi_err("This 16 KB granular kernel is not supported by your CPU\n"); 80d9ffe524SArd Biesheuvel return EFI_UNSUPPORTED; 81d9ffe524SArd Biesheuvel } 82d9ffe524SArd Biesheuvel return EFI_SUCCESS; 83d9ffe524SArd Biesheuvel } 84d9ffe524SArd Biesheuvel 8561786170SArd Biesheuvel #ifdef CONFIG_ARM64_WORKAROUND_CLEAN_CACHE 8661786170SArd Biesheuvel #define DCTYPE "civac" 8761786170SArd Biesheuvel #else 8861786170SArd Biesheuvel #define DCTYPE "cvau" 8961786170SArd Biesheuvel #endif 9061786170SArd Biesheuvel 91d9ffe524SArd Biesheuvel void efi_cache_sync_image(unsigned long image_base, 92d9ffe524SArd Biesheuvel unsigned long alloc_size, 93d9ffe524SArd Biesheuvel unsigned long code_size) 94d9ffe524SArd Biesheuvel { 95d9ffe524SArd Biesheuvel u32 ctr = read_cpuid_effective_cachetype(); 96d9ffe524SArd Biesheuvel u64 lsize = 4 << cpuid_feature_extract_unsigned_field(ctr, 97d9ffe524SArd Biesheuvel CTR_EL0_DminLine_SHIFT); 98d9ffe524SArd Biesheuvel 9961786170SArd Biesheuvel /* only perform the cache maintenance if needed for I/D coherency */ 10061786170SArd Biesheuvel if (!(ctr & BIT(CTR_EL0_IDC_SHIFT))) { 101d9ffe524SArd Biesheuvel do { 10261786170SArd Biesheuvel asm("dc " DCTYPE ", %0" :: "r"(image_base)); 103d9ffe524SArd Biesheuvel image_base += lsize; 10461786170SArd Biesheuvel code_size -= lsize; 10561786170SArd Biesheuvel } while (code_size >= lsize); 10661786170SArd Biesheuvel } 107d9ffe524SArd Biesheuvel 108d9ffe524SArd Biesheuvel asm("ic ialluis"); 109d9ffe524SArd Biesheuvel dsb(ish); 110d9ffe524SArd Biesheuvel isb(); 111d9ffe524SArd Biesheuvel } 11261786170SArd Biesheuvel 11361786170SArd Biesheuvel unsigned long __weak primary_entry_offset(void) 11461786170SArd Biesheuvel { 11561786170SArd Biesheuvel /* 11661786170SArd Biesheuvel * By default, we can invoke the kernel via the branch instruction in 11761786170SArd Biesheuvel * the image header, so offset #0. This will be overridden by the EFI 11861786170SArd Biesheuvel * stub build that is linked into the core kernel, as in that case, the 11961786170SArd Biesheuvel * image header may not have been loaded into memory, or may be mapped 12061786170SArd Biesheuvel * with non-executable permissions. 12161786170SArd Biesheuvel */ 12261786170SArd Biesheuvel return 0; 12361786170SArd Biesheuvel } 12461786170SArd Biesheuvel 12561786170SArd Biesheuvel void __noreturn efi_enter_kernel(unsigned long entrypoint, 12661786170SArd Biesheuvel unsigned long fdt_addr, 12761786170SArd Biesheuvel unsigned long fdt_size) 12861786170SArd Biesheuvel { 12961786170SArd Biesheuvel void (* __noreturn enter_kernel)(u64, u64, u64, u64); 13061786170SArd Biesheuvel 13161786170SArd Biesheuvel enter_kernel = (void *)entrypoint + primary_entry_offset(); 13261786170SArd Biesheuvel enter_kernel(fdt_addr, 0, 0, 0); 13361786170SArd Biesheuvel } 134