/*
 * Copyright (c) 2015 Google, Inc
 *
 * SPDX-License-Identifier:	GPL-2.0+
 *
 * EFI information obtained here:
 * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES
 *
 * This file implements U-Boot running as an EFI application.
 */

#include <common.h>
#include <debug_uart.h>
#include <errno.h>
#include <linux/err.h>
#include <linux/types.h>
#include <efi.h>
#include <efi_api.h>

DECLARE_GLOBAL_DATA_PTR;

static struct efi_priv *global_priv;

struct efi_system_table *efi_get_sys_table(void)
{
	return global_priv->sys_table;
}

unsigned long efi_get_ram_base(void)
{
	return global_priv->ram_base;
}

static efi_status_t setup_memory(struct efi_priv *priv)
{
	struct efi_boot_services *boot = priv->boot;
	efi_physical_addr_t addr;
	efi_status_t ret;
	int pages;

	/*
	 * Use global_data_ptr instead of gd since it is an assignment. There
	 * are very few assignments to global_data in U-Boot and this makes
	 * it easier to find them.
	 */
	global_data_ptr = efi_malloc(priv, sizeof(struct global_data), &ret);
	if (!global_data_ptr)
		return ret;
	memset(gd, '\0', sizeof(*gd));

	gd->malloc_base = (ulong)efi_malloc(priv, CONFIG_SYS_MALLOC_F_LEN,
					    &ret);
	if (!gd->malloc_base)
		return ret;
	pages = CONFIG_EFI_RAM_SIZE >> 12;

	/*
	 * Don't allocate any memory above 4GB. U-Boot is a 32-bit application
	 * so we want it to load below 4GB.
	 */
	addr = 1ULL << 32;
	ret = boot->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
				   priv->image_data_type, pages, &addr);
	if (ret) {
		printf("(using pool %lx) ", ret);
		priv->ram_base = (ulong)efi_malloc(priv, CONFIG_EFI_RAM_SIZE,
						   &ret);
		if (!priv->ram_base)
			return ret;
		priv->use_pool_for_malloc = true;
	} else {
		priv->ram_base = addr;
	}
	gd->ram_size = pages << 12;

	return 0;
}

static void free_memory(struct efi_priv *priv)
{
	struct efi_boot_services *boot = priv->boot;

	if (priv->use_pool_for_malloc)
		efi_free(priv, (void *)priv->ram_base);
	else
		boot->free_pages(priv->ram_base, gd->ram_size >> 12);

	efi_free(priv, (void *)gd->malloc_base);
	efi_free(priv, gd);
	global_data_ptr = NULL;
}

/**
 * efi_main() - Start an EFI image
 *
 * This function is called by our EFI start-up code. It handles running
 * U-Boot. If it returns, EFI will continue. Another way to get back to EFI
 * is via reset_cpu().
 */
efi_status_t efi_main(efi_handle_t image, struct efi_system_table *sys_table)
{
	struct efi_priv local_priv, *priv = &local_priv;
	efi_status_t ret;

	/* Set up access to EFI data structures */
	efi_init(priv, "App", image, sys_table);

	global_priv = priv;

	/*
	 * Set up the EFI debug UART so that printf() works. This is
	 * implemented in the EFI serial driver, serial_efi.c. The application
	 * can use printf() freely.
	 */
	debug_uart_init();

	ret = setup_memory(priv);
	if (ret) {
		printf("Failed to set up memory: ret=%lx\n", ret);
		return ret;
	}

	printf("starting\n");

	board_init_f(GD_FLG_SKIP_RELOC);
	board_init_r(NULL, 0);
	free_memory(priv);

	return EFI_SUCCESS;
}

void reset_cpu(ulong addr)
{
	struct efi_priv *priv = global_priv;

	free_memory(priv);
	printf("U-Boot EFI exiting\n");
	priv->boot->exit(priv->parent_image, EFI_SUCCESS, 0, NULL);
}
