190075Sobrien// SPDX-License-Identifier: GPL-2.0
290075Sobrien/*
390075Sobrien * Copyright (C) 2013, 2014 Linaro Ltd;  <roy.franz@linaro.org>
490075Sobrien *
590075Sobrien * This file implements the EFI boot stub for the arm64 kernel.
690075Sobrien * Adapted from ARM version by Mark Salter <msalter@redhat.com>
790075Sobrien */
8132718Skan
990075Sobrien
10132718Skan#include <linux/efi.h>
11132718Skan#include <asm/efi.h>
12132718Skan#include <asm/image.h>
13132718Skan#include <asm/memory.h>
1490075Sobrien#include <asm/sysreg.h>
15132718Skan
16132718Skan#include "efistub.h"
17132718Skan
18132718Skanstatic bool system_needs_vamap(void)
1990075Sobrien{
20132718Skan	const struct efi_smbios_type4_record *record;
21132718Skan	const u32 __aligned(1) *socid;
22132718Skan	const u8 *version;
23132718Skan
2490075Sobrien	/*
2590075Sobrien	 * Ampere eMAG, Altra, and Altra Max machines crash in SetTime() if
2690075Sobrien	 * SetVirtualAddressMap() has not been called prior. Most Altra systems
2790075Sobrien	 * can be identified by the SMCCC soc ID, which is conveniently exposed
2890075Sobrien	 * via the type 4 SMBIOS records. Otherwise, test the processor version
2990075Sobrien	 * field. eMAG systems all appear to have the processor version field
3090075Sobrien	 * set to "eMAG".
3190075Sobrien	 */
3290075Sobrien	record = (struct efi_smbios_type4_record *)efi_get_smbios_record(4);
3390075Sobrien	if (!record)
3490075Sobrien		return false;
3590075Sobrien
3690075Sobrien	socid = (u32 *)record->processor_id;
3790075Sobrien	switch (*socid & 0xffff000f) {
3890075Sobrien		static char const altra[] = "Ampere(TM) Altra(TM) Processor";
39117395Skan		static char const emag[] = "eMAG";
40117395Skan
4190075Sobrien	default:
4290075Sobrien		version = efi_get_smbios_string(&record->header, 4,
4390075Sobrien						processor_version);
4490075Sobrien		if (!version || (strncmp(version, altra, sizeof(altra) - 1) &&
4590075Sobrien				 strncmp(version, emag, sizeof(emag) - 1)))
4690075Sobrien			break;
47117395Skan
48117395Skan		fallthrough;
49132718Skan
50117395Skan	case 0x0a160001:	// Altra
51117395Skan	case 0x0a160002:	// Altra Max
5290075Sobrien		efi_warn("Working around broken SetVirtualAddressMap()\n");
5390075Sobrien		return true;
5490075Sobrien	}
55117395Skan
56117395Skan	return false;
57117395Skan}
5890075Sobrien
59117395Skanefi_status_t check_platform_features(void)
6090075Sobrien{
6190075Sobrien	u64 tg;
6290075Sobrien
6390075Sobrien	/*
6490075Sobrien	 * If we have 48 bits of VA space for TTBR0 mappings, we can map the
6590075Sobrien	 * UEFI runtime regions 1:1 and so calling SetVirtualAddressMap() is
6690075Sobrien	 * unnecessary.
67117395Skan	 */
6890075Sobrien	if (VA_BITS_MIN >= 48 && !system_needs_vamap())
6990075Sobrien		efi_novamap = true;
7090075Sobrien
71117395Skan	/* UEFI mandates support for 4 KB granularity, no need to check */
72117395Skan	if (IS_ENABLED(CONFIG_ARM64_4K_PAGES))
73117395Skan		return EFI_SUCCESS;
74117395Skan
75117395Skan	tg = (read_cpuid(ID_AA64MMFR0_EL1) >> ID_AA64MMFR0_EL1_TGRAN_SHIFT) & 0xf;
76117395Skan	if (tg < ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MIN || tg > ID_AA64MMFR0_EL1_TGRAN_SUPPORTED_MAX) {
77117395Skan		if (IS_ENABLED(CONFIG_ARM64_64K_PAGES))
78117395Skan			efi_err("This 64 KB granular kernel is not supported by your CPU\n");
7990075Sobrien		else
8090075Sobrien			efi_err("This 16 KB granular kernel is not supported by your CPU\n");
8190075Sobrien		return EFI_UNSUPPORTED;
8290075Sobrien	}
8390075Sobrien	return EFI_SUCCESS;
8490075Sobrien}
8590075Sobrien
8690075Sobrien#ifdef CONFIG_ARM64_WORKAROUND_CLEAN_CACHE
8790075Sobrien#define DCTYPE	"civac"
88117395Skan#else
8990075Sobrien#define DCTYPE	"cvau"
9090075Sobrien#endif
9190075Sobrien
9290075Sobrienu32 __weak code_size;
9390075Sobrien
9490075Sobrienvoid efi_cache_sync_image(unsigned long image_base,
9596263Sobrien			  unsigned long alloc_size)
9696263Sobrien{
9796263Sobrien	u32 ctr = read_cpuid_effective_cachetype();
9890075Sobrien	u64 lsize = 4 << cpuid_feature_extract_unsigned_field(ctr,
9990075Sobrien						CTR_EL0_DminLine_SHIFT);
100117395Skan
10190075Sobrien	/* only perform the cache maintenance if needed for I/D coherency */
10290075Sobrien	if (!(ctr & BIT(CTR_EL0_IDC_SHIFT))) {
10390075Sobrien		unsigned long base = image_base;
10490075Sobrien		unsigned long size = code_size;
10590075Sobrien
10690075Sobrien		do {
10790075Sobrien			asm("dc " DCTYPE ", %0" :: "r"(base));
10890075Sobrien			base += lsize;
109132718Skan			size -= lsize;
11090075Sobrien		} while (size >= lsize);
11190075Sobrien	}
11290075Sobrien
11390075Sobrien	asm("ic ialluis");
11490075Sobrien	dsb(ish);
11590075Sobrien	isb();
11690075Sobrien
117132718Skan	efi_remap_image(image_base, alloc_size, code_size);
118132718Skan}
11990075Sobrien
12090075Sobrienunsigned long __weak primary_entry_offset(void)
12190075Sobrien{
12290075Sobrien	/*
12390075Sobrien	 * By default, we can invoke the kernel via the branch instruction in
12490075Sobrien	 * the image header, so offset #0. This will be overridden by the EFI
12590075Sobrien	 * stub build that is linked into the core kernel, as in that case, the
12690075Sobrien	 * image header may not have been loaded into memory, or may be mapped
12790075Sobrien	 * with non-executable permissions.
12890075Sobrien	 */
12990075Sobrien       return 0;
13090075Sobrien}
13190075Sobrien
13290075Sobrienvoid __noreturn efi_enter_kernel(unsigned long entrypoint,
13390075Sobrien				 unsigned long fdt_addr,
13490075Sobrien				 unsigned long fdt_size)
13590075Sobrien{
13690075Sobrien	void (* __noreturn enter_kernel)(u64, u64, u64, u64);
13790075Sobrien
13890075Sobrien	enter_kernel = (void *)entrypoint + primary_entry_offset();
13990075Sobrien	enter_kernel(fdt_addr, 0, 0, 0);
14090075Sobrien}
14190075Sobrien