1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2013, 2014 Linaro Ltd; <roy.franz@linaro.org>
5 * This file implements the EFI boot stub for the arm64 kernel.
6 * Adapted from ARM version by Mark Salter <msalter@redhat.com>
10 #include <linux/efi.h>
12 #include <asm/image.h>
13 #include <asm/memory.h>
14 #include <asm/sysreg.h>
18 static bool system_needs_vamap(void)
20 const struct efi_smbios_type4_record
*record
;
21 const u32
__aligned(1) *socid
;
25 * Ampere eMAG, Altra, and Altra Max machines crash in SetTime() if
26 * SetVirtualAddressMap() has not been called prior. Most Altra systems
27 * can be identified by the SMCCC soc ID, which is conveniently exposed
28 * via the type 4 SMBIOS records. Otherwise, test the processor version
29 * field. eMAG systems all appear to have the processor version field
32 record
= (struct efi_smbios_type4_record
*)efi_get_smbios_record(4);
36 socid
= (u32
*)record
->processor_id
;
37 switch (*socid
& 0xffff000f) {
38 static char const altra
[] = "Ampere(TM) Altra(TM) Processor";
39 static char const emag
[] = "eMAG";
42 version
= efi_get_smbios_string(record
, processor_version
);
43 if (!version
|| (strncmp(version
, altra
, sizeof(altra
) - 1) &&
44 strncmp(version
, emag
, sizeof(emag
) - 1)))
49 case 0x0a160001: // Altra
50 case 0x0a160002: // Altra Max
51 efi_warn("Working around broken SetVirtualAddressMap()\n");
58 efi_status_t
check_platform_features(void)
63 * If we have 48 bits of VA space for TTBR0 mappings, we can map the
64 * UEFI runtime regions 1:1 and so calling SetVirtualAddressMap() is
67 if (VA_BITS_MIN
>= 48 && !system_needs_vamap())
70 /* UEFI mandates support for 4 KB granularity, no need to check */
71 if (IS_ENABLED(CONFIG_ARM64_4K_PAGES
))
74 tg
= (read_cpuid(ID_AA64MMFR0_EL1
) >> ID_AA64MMFR0_EL1_TGRAN_SHIFT
) & 0xf;
75 if (tg
< ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN
|| tg
> ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX
) {
76 if (IS_ENABLED(CONFIG_ARM64_64K_PAGES
))
77 efi_err("This 64 KB granular kernel is not supported by your CPU\n");
79 efi_err("This 16 KB granular kernel is not supported by your CPU\n");
80 return EFI_UNSUPPORTED
;
85 #ifdef CONFIG_ARM64_WORKAROUND_CLEAN_CACHE
86 #define DCTYPE "civac"
93 void efi_cache_sync_image(unsigned long image_base
,
94 unsigned long alloc_size
)
96 u32 ctr
= read_cpuid_effective_cachetype();
97 u64 lsize
= 4 << cpuid_feature_extract_unsigned_field(ctr
,
98 CTR_EL0_DminLine_SHIFT
);
100 /* only perform the cache maintenance if needed for I/D coherency */
101 if (!(ctr
& BIT(CTR_EL0_IDC_SHIFT
))) {
102 unsigned long base
= image_base
;
103 unsigned long size
= code_size
;
106 asm("dc " DCTYPE
", %0" :: "r"(base
));
109 } while (size
>= lsize
);
116 efi_remap_image(image_base
, alloc_size
, code_size
);
119 unsigned long __weak
primary_entry_offset(void)
122 * By default, we can invoke the kernel via the branch instruction in
123 * the image header, so offset #0. This will be overridden by the EFI
124 * stub build that is linked into the core kernel, as in that case, the
125 * image header may not have been loaded into memory, or may be mapped
126 * with non-executable permissions.
131 void __noreturn
efi_enter_kernel(unsigned long entrypoint
,
132 unsigned long fdt_addr
,
133 unsigned long fdt_size
)
135 void (* __noreturn enter_kernel
)(u64
, u64
, u64
, u64
);
137 enter_kernel
= (void *)entrypoint
+ primary_entry_offset();
138 enter_kernel(fdt_addr
, 0, 0, 0);