/*
 * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <arch_helpers.h>
#include <cactus_test_cmds.h>
#include <plat_topology.h>
#include <platform.h>
#include <power_management.h>
#include <test_helpers.h>
#include <tftf_lib.h>

static struct mailbox_buffers test_mb = {.send = NULL, .recv = NULL};

int is_sys_suspend_state_ready(void)
{
	int aff_info;
	unsigned int target_node;
	u_register_t target_mpid;
	u_register_t current_mpid = read_mpidr_el1() & MPID_MASK;

	for_each_cpu(target_node) {
		target_mpid = tftf_get_mpidr_from_node(target_node);

		/* Skip current CPU, as it is powered on */
		if (target_mpid == current_mpid)
			continue;

		aff_info = tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0);
		if (aff_info != PSCI_STATE_OFF)
			return 0;
	}

	return 1;
}

void psci_system_reset(void)
{
	smc_args args = { SMC_PSCI_SYSTEM_RESET };
	smc_ret_values ret;

	ret = tftf_smc(&args);

	/* The PSCI SYSTEM_RESET call is not supposed to return */
	tftf_testcase_printf("System didn't reboot properly (%d)\n",
			(unsigned int)ret.ret0);
}

int psci_mem_protect(int val)
{
	smc_args args = { SMC_PSCI_MEM_PROTECT};
	smc_ret_values ret;

	args.arg1 = val;
	ret = tftf_smc(&args);

	return ret.ret0;
}

int psci_mem_protect_check(uintptr_t addr, size_t size)
{
	smc_args args = { SMC_PSCI_MEM_PROTECT_CHECK };
	smc_ret_values ret;

	args.arg1 = addr;
	args.arg2 = size;
	ret = tftf_smc(&args);
	return ret.ret0;
}

/*
 * This function returns an address that can be used as
 * sentinel for mem_protect functions. The logic behind
 * it is that it has to search one region that doesn't intersect
 * with the memory used by TFTF.
 */
unsigned char *psci_mem_prot_get_sentinel(void)
{
	const mem_region_t *ranges, *rp, *lim;
	int nranges;
	IMPORT_SYM(uintptr_t, __TFTF_BASE__, tftf_base);
	IMPORT_SYM(uintptr_t, __TFTF_END__, tftf_end);
	uintptr_t p = 0;

	ranges = plat_get_prot_regions(&nranges);
	if (!ranges)
		return NULL;

	lim = &ranges[nranges];
	for (rp = ranges ; rp < lim; rp++) {
		p = rp->addr;
		if (p < tftf_base || p > tftf_end)
			break;
		p = p + (rp->size - 1);
		if (p < tftf_base || p > tftf_end)
			break;
	}

	return (rp == lim) ? NULL : (unsigned char *) p;
}

/*
 * This function maps the memory region before the
 * test and unmap it after the test is run
 */
test_result_t map_test_unmap(const map_args_unmap_t *args,
			     test_function_arg_t test)
{
	int mmap_ret;
	test_result_t test_ret;

	mmap_ret = mmap_add_dynamic_region(args->addr, args->addr,
					   args->size, args->attr);

	if (mmap_ret != 0) {
		tftf_testcase_printf("Couldn't map memory (ret = %d)\n",
				     mmap_ret);
		return TEST_RESULT_FAIL;
	}

	test_ret = (*test)(args->arg);

	mmap_ret = mmap_remove_dynamic_region(args->addr, args->size);
	if (mmap_ret != 0) {
		tftf_testcase_printf("Couldn't unmap memory (ret = %d)\n",
				     mmap_ret);
		return TEST_RESULT_FAIL;
	}

	return test_ret;
}

void set_tftf_mailbox(const struct mailbox_buffers *mb)
{
	if (mb != NULL) {
		test_mb = *mb;
	}
}

bool get_tftf_mailbox(struct mailbox_buffers *mb)
{
	if ((test_mb.recv != NULL) && (test_mb.send != NULL)) {
		*mb = test_mb;
		return true;
	}
	return false;
}

test_result_t check_spmc_testing_set_up(
	uint32_t ffa_version_major, uint32_t ffa_version_minor,
	const struct ffa_uuid *ffa_uuids, size_t ffa_uuids_size)
{
	struct  mailbox_buffers mb;

	if (ffa_uuids == NULL) {
		ERROR("Invalid parameter ffa_uuids!\n");
		return TEST_RESULT_FAIL;
	}

	SKIP_TEST_IF_FFA_VERSION_LESS_THAN(ffa_version_major,
					   ffa_version_minor);

	/**********************************************************************
	 * If OP-TEE is SPMC skip the current test.
	 **********************************************************************/
	if (check_spmc_execution_level()) {
		VERBOSE("OPTEE as SPMC at S-EL1. Skipping test!\n");
		return TEST_RESULT_SKIPPED;
	}

	GET_TFTF_MAILBOX(mb);

	for (unsigned int i = 0U; i < ffa_uuids_size; i++)
		SKIP_TEST_IF_FFA_ENDPOINT_NOT_DEPLOYED(*mb, ffa_uuids[i]);

	return TEST_RESULT_SUCCESS;
}

test_result_t spm_run_multi_core_test(uintptr_t cpu_on_handler,
				      event_t *cpu_done)
{
	unsigned int lead_mpid = read_mpidr_el1() & MPID_MASK;
	unsigned int core_pos, cpu_node, mpidr;
	int32_t ret;

	VERBOSE("Powering on all cpus.\n");

	for (unsigned int i = 0U; i < PLATFORM_CORE_COUNT; i++) {
		tftf_init_event(&cpu_done[i]);
	}

	for_each_cpu(cpu_node) {
		mpidr = tftf_get_mpidr_from_node(cpu_node);
		if (mpidr == lead_mpid) {
			continue;
		}

		ret = tftf_cpu_on(mpidr, cpu_on_handler, 0U);
		if (ret != 0) {
			ERROR("tftf_cpu_on mpidr 0x%x returns %d\n",
			      mpidr, ret);
		}
	}

	VERBOSE("Waiting secondary CPUs to turn off ...\n");

	for_each_cpu(cpu_node) {
		mpidr = tftf_get_mpidr_from_node(cpu_node);
		if (mpidr == lead_mpid) {
			continue;
		}

		core_pos = platform_get_core_pos(mpidr);
		tftf_wait_for_event(&cpu_done[core_pos]);
	}

	VERBOSE("Done exiting.\n");

	return TEST_RESULT_SUCCESS;
}

bool spm_core_sp_init(ffa_id_t sp_id)
{
	/*
	 * Secure Partitions secondary ECs need one round of ffa_run to reach
	 * the message loop.
	 */
	if (sp_id != SP_ID(1)) {
		uint32_t core_pos = get_current_core_id();
		smc_ret_values ret = ffa_run(sp_id, core_pos);

		if (ffa_func_id(ret) != FFA_MSG_WAIT) {
			ERROR("Failed to run SP%x on core %u\n",
			      sp_id, core_pos);
			return false;
		}
	}

	return true;
}

bool spm_set_managed_exit_int(ffa_id_t sp_id, bool enable)
{
	smc_ret_values ret;

	ret = cactus_interrupt_cmd(HYP_ID, sp_id, MANAGED_EXIT_INTERRUPT_ID,
				   enable, INTERRUPT_TYPE_FIQ);

	if (!is_ffa_direct_response(ret) ||
	    cactus_get_response(ret) != CACTUS_SUCCESS) {
		ERROR("Failed to enable Managed exit interrupt\n");
		return false;
	}

	return true;
}

/*
 * Initializes the Mailbox for other SPM related tests that need to use
 * RXTX buffers.
 */
bool mailbox_init(struct mailbox_buffers mb)
{
	smc_ret_values ret;

	ffa_rxtx_unmap();
	CONFIGURE_AND_MAP_MAILBOX(mb, PAGE_SIZE, ret);
	if (ffa_func_id(ret) != FFA_SUCCESS_SMC32) {
		ERROR("Failed to map RXTX buffers %x!\n", ffa_error_code(ret));
		return false;
	}
	set_tftf_mailbox(&mb);
	return true;
}

