18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Author: Yun Liu <liuyun@loongson.cn>
48c2ecf20Sopenharmony_ci *         Huacai Chen <chenhuacai@loongson.cn>
58c2ecf20Sopenharmony_ci * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <asm/efi.h>
98c2ecf20Sopenharmony_ci#include <asm/addrspace.h>
108c2ecf20Sopenharmony_ci#include "efistub.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#define BOOT_HEAP_SIZE 0x400000
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_citypedef void __noreturn (*kernel_entry_t)(bool efi, unsigned long cmdline,
158c2ecf20Sopenharmony_ci					  unsigned long systab, long kdump_reloc_offset);
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ciextern long kernel_entaddr;
188c2ecf20Sopenharmony_ciextern void decompress_kernel(unsigned long boot_heap_start, long kdump_reloc_offset);
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic unsigned char efi_heap[BOOT_HEAP_SIZE];
218c2ecf20Sopenharmony_cistatic efi_guid_t screen_info_guid = LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID;
228c2ecf20Sopenharmony_cistatic kernel_entry_t kernel_entry;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistruct screen_info *alloc_screen_info(void)
258c2ecf20Sopenharmony_ci{
268c2ecf20Sopenharmony_ci	efi_status_t status;
278c2ecf20Sopenharmony_ci	struct screen_info *si;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	status = efi_bs_call(allocate_pool,
308c2ecf20Sopenharmony_ci			EFI_RUNTIME_SERVICES_DATA, sizeof(*si), (void **)&si);
318c2ecf20Sopenharmony_ci	if (status != EFI_SUCCESS)
328c2ecf20Sopenharmony_ci		return NULL;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	memset(si, 0, sizeof(*si));
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	status = efi_bs_call(install_configuration_table, &screen_info_guid, si);
378c2ecf20Sopenharmony_ci	if (status == EFI_SUCCESS)
388c2ecf20Sopenharmony_ci		return si;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	efi_bs_call(free_pool, si);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	return NULL;
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_civoid free_screen_info(struct screen_info *si)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	if (!si)
488c2ecf20Sopenharmony_ci		return;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	efi_bs_call(install_configuration_table, &screen_info_guid, NULL);
518c2ecf20Sopenharmony_ci	efi_bs_call(free_pool, si);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ciefi_status_t check_platform_features(void)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	return EFI_SUCCESS;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ciefi_status_t handle_kernel_image(unsigned long *image_addr,
608c2ecf20Sopenharmony_ci				 unsigned long *image_size,
618c2ecf20Sopenharmony_ci				 unsigned long *reserve_addr,
628c2ecf20Sopenharmony_ci				 unsigned long *reserve_size,
638c2ecf20Sopenharmony_ci				 efi_loaded_image_t *image)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	/* Config Direct Mapping */
668c2ecf20Sopenharmony_ci	csr_write64(CSR_DMW0_INIT, LOONGARCH_CSR_DMWIN0);
678c2ecf20Sopenharmony_ci	csr_write64(CSR_DMW1_INIT, LOONGARCH_CSR_DMWIN1);
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	decompress_kernel((unsigned long)efi_heap, 0);
708c2ecf20Sopenharmony_ci	kernel_entry = (kernel_entry_t)kernel_entaddr;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	return EFI_SUCCESS;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistruct exit_boot_struct {
768c2ecf20Sopenharmony_ci	efi_memory_desc_t	*runtime_map;
778c2ecf20Sopenharmony_ci	int			runtime_entry_count;
788c2ecf20Sopenharmony_ci};
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_cistatic efi_status_t exit_boot_func(struct efi_boot_memmap *map, void *priv)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	struct exit_boot_struct *p = priv;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	/*
858c2ecf20Sopenharmony_ci	 * Update the memory map with virtual addresses. The function will also
868c2ecf20Sopenharmony_ci	 * populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME
878c2ecf20Sopenharmony_ci	 * entries so that we can pass it straight to SetVirtualAddressMap()
888c2ecf20Sopenharmony_ci	 */
898c2ecf20Sopenharmony_ci	efi_get_virtmap(map->map, map->map_size, map->desc_size,
908c2ecf20Sopenharmony_ci			p->runtime_map, &p->runtime_entry_count);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	return EFI_SUCCESS;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ciefi_status_t efi_boot_kernel(void *handle, efi_loaded_image_t *image,
968c2ecf20Sopenharmony_ci			     unsigned long kernel_addr, char *cmdline_ptr)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct exit_boot_struct priv;
998c2ecf20Sopenharmony_ci	unsigned long desc_size;
1008c2ecf20Sopenharmony_ci	efi_status_t status;
1018c2ecf20Sopenharmony_ci	u32 desc_ver;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	status = efi_alloc_virtmap(&priv.runtime_map, &desc_size, &desc_ver);
1048c2ecf20Sopenharmony_ci	if (status != EFI_SUCCESS) {
1058c2ecf20Sopenharmony_ci		efi_err("Unable to retrieve UEFI memory map.\n");
1068c2ecf20Sopenharmony_ci		return status;
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	efi_info("Exiting boot services\n");
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	efi_novamap = false;
1128c2ecf20Sopenharmony_ci	status = efi_exit_boot_services(handle, &priv, exit_boot_func);
1138c2ecf20Sopenharmony_ci	if (status != EFI_SUCCESS)
1148c2ecf20Sopenharmony_ci		return status;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	/* Install the new virtual address map */
1178c2ecf20Sopenharmony_ci	efi_rt_call(set_virtual_address_map,
1188c2ecf20Sopenharmony_ci		    priv.runtime_entry_count * desc_size, desc_size,
1198c2ecf20Sopenharmony_ci		    desc_ver, priv.runtime_map);
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	kernel_entry(true, (unsigned long)cmdline_ptr, (unsigned long)efi_system_table, 0);
1228c2ecf20Sopenharmony_ci}
123