// SPDX-License-Identifier: BSD-2-Clause
/*
 * Copyright (c) 2014, STMicroelectronics International N.V.
 * All rights reserved.
 */

#include "storage.h"
#include "ta_storage.h"

#include <tee_api.h>
#include <tee_api_defines_extensions.h>
#include <trace.h>
#include <user_ta_header_defines.h>

#define ASSERT_PARAM_TYPE(pt) \
do { \
	if ((pt) != param_types) \
		return TEE_ERROR_BAD_PARAMETERS; \
} while (0)

#define VAL2HANDLE(v) (void *)(uintptr_t)(v)

TEE_Result ta_storage_cmd_open(uint32_t command,
				uint32_t param_types, TEE_Param params[4])
{
	TEE_Result res = TEE_ERROR_GENERIC;
	TEE_ObjectHandle o = TEE_HANDLE_NULL;
	void *object_id = NULL;

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_MEMREF_INPUT,
			   TEE_PARAM_TYPE_VALUE_INOUT,
			   TEE_PARAM_TYPE_VALUE_INPUT,
			   TEE_PARAM_TYPE_NONE));

	switch (command) {
	case TA_STORAGE_CMD_OPEN:
		if (params[0].memref.buffer) {
			object_id = TEE_Malloc(params[0].memref.size, 0);
			if (!object_id)
				return TEE_ERROR_OUT_OF_MEMORY;

			TEE_MemMove(object_id, params[0].memref.buffer,
				    params[0].memref.size);
		}
		break;
	case TA_STORAGE_CMD_OPEN_ID_IN_SHM:
		object_id = params[0].memref.buffer;
		break;
	default:
		return TEE_ERROR_NOT_SUPPORTED;
	}

	res = TEE_OpenPersistentObject(params[2].value.a,
					object_id, params[0].memref.size,
					params[1].value.a, &o);

	params[1].value.b = (uintptr_t)o;

	if (command == TA_STORAGE_CMD_OPEN)
		TEE_Free(object_id);

	return res;
}

TEE_Result ta_storage_cmd_create(uint32_t command,
				 uint32_t param_types, TEE_Param params[4])
{
	TEE_Result res = TEE_ERROR_GENERIC;
	TEE_ObjectHandle o = TEE_HANDLE_NULL;
	void *object_id = NULL;
	TEE_ObjectHandle ref_handle = TEE_HANDLE_NULL;

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_MEMREF_INPUT,
			   TEE_PARAM_TYPE_VALUE_INOUT,
			   TEE_PARAM_TYPE_VALUE_INPUT,
			   TEE_PARAM_TYPE_MEMREF_INPUT));

	switch (command) {
	case TA_STORAGE_CMD_CREATE:
		if (params[0].memref.buffer) {
			object_id = TEE_Malloc(params[0].memref.size, 0);
			if (!object_id)
				return TEE_ERROR_OUT_OF_MEMORY;

			TEE_MemMove(object_id, params[0].memref.buffer,
				    params[0].memref.size);
		}
		break;
	case TA_STORAGE_CMD_CREATE_ID_IN_SHM:
		object_id = params[0].memref.buffer;
		break;
	default:
		return TEE_ERROR_NOT_SUPPORTED;
	}

	ref_handle = (TEE_ObjectHandle)(uintptr_t)params[2].value.a;

	res = TEE_CreatePersistentObject(params[2].value.b,
					 object_id, params[0].memref.size,
					 params[1].value.a, ref_handle,
					 params[3].memref.buffer,
					 params[3].memref.size, &o);

	if (command == TA_STORAGE_CMD_CREATE)
		TEE_Free(object_id);

	params[1].value.b = (uintptr_t)o;

	return res;
}

TEE_Result ta_storage_cmd_create_overwrite(uint32_t command,
					   uint32_t param_types,
					   TEE_Param params[4])
{
	TEE_Result res = TEE_ERROR_GENERIC;
	TEE_ObjectHandle o = TEE_HANDLE_NULL;
	void *object_id = NULL;

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_MEMREF_INPUT,
			   TEE_PARAM_TYPE_VALUE_INPUT,
			   TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE));

	switch (command) {
	case TA_STORAGE_CMD_CREATE_OVERWRITE:
		object_id = TEE_Malloc(params[0].memref.size, 0);
		if (!object_id)
			return TEE_ERROR_OUT_OF_MEMORY;

		TEE_MemMove(object_id, params[0].memref.buffer,
			    params[0].memref.size);
		break;
	case TA_STORAGE_CMD_CREATEOVER_ID_IN_SHM:
		object_id = params[0].memref.buffer;
		break;
	default:
		return TEE_ERROR_NOT_SUPPORTED;
	}

	res = TEE_CreatePersistentObject(params[1].value.a,
					 object_id, params[0].memref.size,
					 TEE_DATA_FLAG_OVERWRITE,
					 NULL, NULL, 0, &o);
	TEE_CloseObject(o);

	if (command == TA_STORAGE_CMD_CREATE_OVERWRITE)
		TEE_Free(object_id);

	return res;
}

TEE_Result ta_storage_cmd_close(uint32_t param_types, TEE_Param params[4])
{
	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

	TEE_CloseObject((TEE_ObjectHandle)(uintptr_t)params[0].value.a);

	return TEE_SUCCESS;
}

TEE_Result ta_storage_cmd_read(uint32_t param_types, TEE_Param params[4])
{
	TEE_ObjectHandle o = VAL2HANDLE(params[1].value.a);
	TEE_Result res = TEE_SUCCESS;
	size_t sz = 0;
	void *b0 = NULL;

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_MEMREF_OUTPUT,
			   TEE_PARAM_TYPE_VALUE_INOUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE));

	b0 = TEE_Malloc(params[0].memref.size, 0);
	if (!b0)
		return TEE_ERROR_OUT_OF_MEMORY;

	sz = params[1].value.b;
	res = TEE_ReadObjectData(o, b0, params[0].memref.size, &sz);
	params[1].value.b = sz;
	if (!res)
		TEE_MemMove(params[0].memref.buffer, b0, params[0].memref.size);
	TEE_Free(b0);

	return res;
}

TEE_Result ta_storage_cmd_write(uint32_t param_types, TEE_Param params[4])
{
	TEE_ObjectHandle o = VAL2HANDLE(params[1].value.a);
	TEE_Result res = TEE_SUCCESS;
	void *b0 = NULL;

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_MEMREF_INPUT,
			   TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE));

	b0 = TEE_Malloc(params[0].memref.size, 0);
	if (!b0)
		return TEE_ERROR_OUT_OF_MEMORY;
	TEE_MemMove(b0, params[0].memref.buffer, params[0].memref.size);

	res = TEE_WriteObjectData(o, b0, params[0].memref.size);
	TEE_Free(b0);

	return res;
}

TEE_Result ta_storage_cmd_seek(uint32_t param_types, TEE_Param params[4])
{
	TEE_Result res = TEE_ERROR_GENERIC;
	TEE_ObjectInfo info;
	TEE_ObjectHandle o = VAL2HANDLE(params[0].value.a);
	int32_t offs = 0;

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT,
			   TEE_PARAM_TYPE_VALUE_INOUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE));

	offs = *(int32_t *)&params[0].value.b;
	res = TEE_SeekObjectData(o, offs, params[1].value.a);
	if (res != TEE_SUCCESS)
		return res;
	res = TEE_GetObjectInfo1(o, &info);

	params[1].value.b = info.dataPosition;

	return res;
}

TEE_Result ta_storage_cmd_unlink(uint32_t param_types, TEE_Param params[4])
{
	TEE_ObjectHandle o = VAL2HANDLE(params[0].value.a);

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

	TEE_CloseAndDeletePersistentObject1(o);

	return TEE_SUCCESS;
}

TEE_Result ta_storage_cmd_rename(uint32_t command, uint32_t param_types,
				 TEE_Param params[4])
{
	TEE_ObjectHandle o = VAL2HANDLE(params[0].value.a);
	void *object_id = NULL;
	TEE_Result res = TEE_ERROR_GENERIC;

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT,
			   TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE));

	switch (command) {
	case TA_STORAGE_CMD_RENAME:
		if (params[0].memref.buffer) {
			object_id = TEE_Malloc(params[1].memref.size, 0);
			if (!object_id)
				return TEE_ERROR_OUT_OF_MEMORY;

			TEE_MemMove(object_id, params[1].memref.buffer,
				    params[1].memref.size);
		}
		break;
	case TA_STORAGE_CMD_RENAME_ID_IN_SHM:
		object_id = params[1].memref.buffer;
		break;
	default:
		return TEE_ERROR_NOT_SUPPORTED;
	}

	res = TEE_RenamePersistentObject(o, object_id, params[1].memref.size);

	if (command == TA_STORAGE_CMD_RENAME)
		TEE_Free(object_id);

	return res;
}

TEE_Result ta_storage_cmd_trunc(uint32_t param_types, TEE_Param params[4])
{
	TEE_ObjectHandle o = VAL2HANDLE(params[0].value.a);

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

	return TEE_TruncateObjectData(o, params[0].value.b);
}

TEE_Result ta_storage_cmd_alloc_enum(uint32_t param_types, TEE_Param params[4])
{
	TEE_Result res = TEE_ERROR_GENERIC;
	TEE_ObjectEnumHandle oe = TEE_HANDLE_NULL;

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_OUTPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

	res = TEE_AllocatePersistentObjectEnumerator(&oe);
	params[0].value.a = (uintptr_t)oe;
	return res;
}

TEE_Result ta_storage_cmd_free_enum(uint32_t param_types, TEE_Param params[4])
{
	TEE_ObjectEnumHandle oe = VAL2HANDLE(params[0].value.a);

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

	TEE_FreePersistentObjectEnumerator(oe);
	return TEE_SUCCESS;
}

TEE_Result ta_storage_cmd_reset_enum(uint32_t param_types, TEE_Param params[4])
{
	TEE_ObjectEnumHandle oe = VAL2HANDLE(params[0].value.a);

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

	TEE_ResetPersistentObjectEnumerator(oe);
	return TEE_SUCCESS;
}

TEE_Result ta_storage_cmd_start_enum(uint32_t param_types, TEE_Param params[4])
{
	TEE_ObjectEnumHandle oe = VAL2HANDLE(params[0].value.a);

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

	return TEE_StartPersistentObjectEnumerator(oe, params[0].value.b);
}

TEE_Result ta_storage_cmd_next_enum(uint32_t param_types, TEE_Param params[4])
{
	TEE_ObjectEnumHandle oe = VAL2HANDLE(params[0].value.a);
	TEE_Result res = TEE_SUCCESS;
	TEE_ObjectInfo *obj = NULL;
	void *b2 = NULL;

	if (TEE_PARAM_TYPE_GET(param_types, 0) != TEE_PARAM_TYPE_VALUE_INPUT)
		return TEE_ERROR_BAD_PARAMETERS;
	if (TEE_PARAM_TYPE_GET(param_types, 2) != TEE_PARAM_TYPE_MEMREF_OUTPUT)
		return TEE_ERROR_BAD_PARAMETERS;
	if (TEE_PARAM_TYPE_GET(param_types, 3) != TEE_PARAM_TYPE_NONE)
		return TEE_ERROR_BAD_PARAMETERS;

	if (params[2].memref.size < TEE_OBJECT_ID_MAX_LEN)
		return TEE_ERROR_SHORT_BUFFER;

	if (TEE_PARAM_TYPE_GET(param_types, 1) == TEE_PARAM_TYPE_NONE)
		obj = NULL;
	else if (TEE_PARAM_TYPE_GET(param_types, 1) ==
		 TEE_PARAM_TYPE_MEMREF_OUTPUT) {
		if (params[1].memref.size < sizeof(TEE_ObjectInfo)) {
			params[1].memref.size = sizeof(TEE_ObjectInfo);
			return TEE_ERROR_SHORT_BUFFER;
		}
		params[1].memref.size = sizeof(TEE_ObjectInfo);
		obj = TEE_Malloc(sizeof(TEE_ObjectInfo), 0);
		if (!obj)
			return TEE_ERROR_OUT_OF_MEMORY;
	} else
		return TEE_ERROR_BAD_PARAMETERS;

	b2 = TEE_Malloc(params[2].memref.size, 0);
	if (!b2) {
		res = TEE_ERROR_OUT_OF_MEMORY;
		goto out;
	}

	res = TEE_GetNextPersistentObject(oe, obj, b2, &params[2].memref.size);
	if (res)
		goto out;

	TEE_MemMove(params[2].memref.buffer, b2, params[2].memref.size);
	if (obj)
		TEE_MemMove(params[1].memref.buffer, obj, sizeof(*obj));
out:
	TEE_Free(b2);
	TEE_Free(obj);

	return res;
}

static TEE_Result check_obj(TEE_ObjectInfo *o1, TEE_ObjectInfo *o2)
{
	if ((o1->objectType != o2->objectType) ||
	    (o1->objectSize != o2->objectSize) ||
	    (o1->maxObjectSize != o2->maxObjectSize) ||
	    (o1->objectUsage != o2->objectUsage))
		return TEE_ERROR_GENERIC;
	return TEE_SUCCESS;
}

TEE_Result ta_storage_cmd_key_in_persistent(uint32_t param_types,
					    TEE_Param params[4])
{
	TEE_Result result = TEE_SUCCESS;
	TEE_ObjectHandle transient_key = TEE_HANDLE_NULL;
	TEE_ObjectHandle persistent_key = TEE_HANDLE_NULL;
	TEE_ObjectHandle key = TEE_HANDLE_NULL;
	TEE_OperationHandle encrypt_op = TEE_HANDLE_NULL;
	TEE_ObjectInfo keyInfo;
	TEE_ObjectInfo keyInfo2;
	TEE_ObjectInfo keyInfo3;
	uint32_t alg = TEE_ALG_AES_CBC_NOPAD;
	void *IV = NULL;
	size_t IVlen = 16;
	size_t key_size = 256;
	uint32_t objectID = 1;
	uint32_t flags = TEE_DATA_FLAG_ACCESS_READ |
			 TEE_DATA_FLAG_ACCESS_WRITE |
			 TEE_DATA_FLAG_ACCESS_WRITE_META |
			 TEE_DATA_FLAG_SHARE_READ |
			 TEE_DATA_FLAG_SHARE_WRITE;

	TEE_MemFill(&keyInfo, 0, sizeof(keyInfo));
	TEE_MemFill(&keyInfo2, 0, sizeof(keyInfo2));
	TEE_MemFill(&keyInfo3, 0, sizeof(keyInfo3));

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

	result = TEE_AllocateTransientObject(TEE_TYPE_AES, key_size,
					     &transient_key);
	if (result != TEE_SUCCESS) {
		EMSG("Failed to Allocate transient object handle : 0x%x",
		     result);
		goto cleanup1;
	}

	result = TEE_GenerateKey(transient_key, key_size, NULL, 0);
	if (result != TEE_SUCCESS) {
		EMSG("Failed to generate a transient key: 0x%x", result);
		goto cleanup2;
	}

	TEE_GetObjectInfo1(transient_key, &keyInfo);
	result = TEE_CreatePersistentObject(params[0].value.a,
					    &objectID, sizeof(objectID),
					    flags, transient_key, NULL, 0,
					    &persistent_key);
	if (result != TEE_SUCCESS) {
		EMSG("Failed to create a persistent key: 0x%x", result);
		goto cleanup2;
	}

	TEE_GetObjectInfo1(persistent_key, &keyInfo2);
	result = check_obj(&keyInfo, &keyInfo2);
	if (result != TEE_SUCCESS) {
		EMSG("keyInfo and keyInfo2 are different");
		goto cleanup2;
	}

	TEE_CloseAndDeletePersistentObject1(persistent_key);

	/* Transform the transient object into a persistent object */
	result = TEE_CreatePersistentObject(params[0].value.a,
					    &objectID, sizeof(objectID),
					    flags, transient_key, NULL, 0,
					    NULL);
	if (result != TEE_SUCCESS) {
		EMSG("Failed to create a persistent key: 0x%x", result);
		goto cleanup2;
	}
	persistent_key = transient_key;
	transient_key = TEE_HANDLE_NULL;

	TEE_GetObjectInfo1(persistent_key, &keyInfo2);
	result = check_obj(&keyInfo, &keyInfo2);
	if (result != TEE_SUCCESS) {
		EMSG("keyInfo and keyInfo2 are different");
		goto cleanup2;
	}

	TEE_CloseObject(persistent_key);

	result = TEE_OpenPersistentObject(params[0].value.a,
					  &objectID, sizeof(objectID),
					  flags, &key);
	if (result != TEE_SUCCESS) {
		EMSG("Failed to open persistent key: 0x%x", result);
		goto cleanup2;
	}

	TEE_GetObjectInfo(key, &keyInfo3);
	result = check_obj(&keyInfo3, &keyInfo2);
	if (result != TEE_SUCCESS) {
		EMSG("keyInfo2 and keyInfo3 are different");
		goto cleanup2;
	}

	result = TEE_AllocateOperation(&encrypt_op, alg, TEE_MODE_ENCRYPT,
				       keyInfo3.maxObjectSize);
	if (result != TEE_SUCCESS) {
		EMSG("Failed to allocate an operation: 0x%x", result);
		goto cleanup3;
	}

	result = TEE_SetOperationKey(encrypt_op, key);
	if (result != TEE_SUCCESS) {
		EMSG("Failed to set operation key: 0x%x", result);
		goto cleanup4;
	}

	IV = TEE_Malloc(IVlen, 0);
	if (!IV) {
		EMSG("Out of memory for IV.");
		result = TEE_ERROR_OUT_OF_MEMORY;
		goto cleanup4;
	}

	TEE_CipherInit(encrypt_op, IV, IVlen);
	TEE_Free(IV);

cleanup4:
	TEE_FreeOperation(encrypt_op);
cleanup3:
	TEE_CloseAndDeletePersistentObject1(key);
cleanup2:
	TEE_FreeTransientObject(transient_key);
cleanup1:
	return result;
}

TEE_Result ta_storage_cmd_loop(uint32_t param_types, TEE_Param params[4])
{
	TEE_ObjectHandle object = TEE_HANDLE_NULL;
	TEE_Result res = TEE_ERROR_GENERIC;
	int object_id = 0;
	uint32_t flags =  TEE_DATA_FLAG_OVERWRITE |
			  TEE_DATA_FLAG_ACCESS_WRITE_META;
	int i = 0;

	(void)params;
	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

	for (i = 0; i < 20; i++) {
		DMSG("\n\nLOOP : %d", i);
		object = TEE_HANDLE_NULL;
		object_id = i;
		res = TEE_CreatePersistentObject(params[0].value.a,
						 &object_id, sizeof(int), flags,
						 TEE_HANDLE_NULL, NULL, 0,
						 &object);

		if (res != TEE_SUCCESS) {
			EMSG("FAIL");
			return res;
		}

		res = TEE_CloseAndDeletePersistentObject1(object);
		if (res != TEE_SUCCESS) {
			EMSG("FAIL");
			return res;
		}
	}

	return TEE_SUCCESS;
}

TEE_Result ta_storage_cmd_restrict_usage(uint32_t param_types,
					 TEE_Param params[4])
{
	TEE_ObjectHandle o = TEE_HANDLE_NULL;

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

	o = (TEE_ObjectHandle)(uintptr_t)params[0].value.a;
	TEE_RestrictObjectUsage1(o, params[0].value.b);
	return TEE_SUCCESS;
}

TEE_Result ta_storage_cmd_alloc_obj(uint32_t param_types, TEE_Param params[4])
{
	TEE_Result res = TEE_ERROR_GENERIC;
	TEE_ObjectHandle o = TEE_HANDLE_NULL;

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT,
			   TEE_PARAM_TYPE_VALUE_OUTPUT,
			   TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

	res = TEE_AllocateTransientObject(params[0].value.a, params[0].value.b,
					  &o);
	params[1].value.a = (uint32_t)(uintptr_t)o;
	return res;
}

TEE_Result ta_storage_cmd_free_obj(uint32_t param_types, TEE_Param params[4])
{
	TEE_ObjectHandle o = TEE_HANDLE_NULL;

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

	o = (TEE_ObjectHandle)(uintptr_t)params[0].value.a;
	TEE_FreeTransientObject(o);
	return TEE_SUCCESS;
}

TEE_Result ta_storage_cmd_reset_obj(uint32_t param_types, TEE_Param params[4])
{
	TEE_ObjectHandle o = TEE_HANDLE_NULL;

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE));

	o = (TEE_ObjectHandle)(uintptr_t)params[0].value.a;
	TEE_ResetTransientObject(o);
	return TEE_SUCCESS;
}

TEE_Result ta_storage_cmd_get_obj_info(uint32_t param_types,
					    TEE_Param params[4])
{
	TEE_Result res = TEE_ERROR_GENERIC;
	struct ta_storage_obj_info oi = { };
	TEE_ObjectInfo info = { };
	TEE_ObjectHandle o = VAL2HANDLE(params[0].value.a);

	ASSERT_PARAM_TYPE(TEE_PARAM_TYPES
			  (TEE_PARAM_TYPE_VALUE_INPUT,
			   TEE_PARAM_TYPE_MEMREF_OUTPUT, TEE_PARAM_TYPE_NONE,
			   TEE_PARAM_TYPE_NONE));

	if (params[1].memref.size < sizeof(oi))
		return TEE_ERROR_SHORT_BUFFER;
	res = TEE_GetObjectInfo1(o, &info);
	if (!res) {
		params[1].memref.size = sizeof(oi);
		oi.object_type = info.objectType;
		oi.object_size = info.objectSize;
		oi.max_object_size = info.maxObjectSize;
		oi.object_usage = info.objectUsage;
		oi.data_size = info.dataSize;
		oi.data_position = info.dataPosition;
		oi.handle_flags = info.handleFlags;
		TEE_MemMove(params[1].memref.buffer, &oi, sizeof(oi));
	}

	return res;
}

static TEE_Result clear_storage(uint32_t storage_id)
{
	TEE_ObjectEnumHandle oe = TEE_HANDLE_NULL;
	TEE_Result enum_res = TEE_ERROR_GENERIC;
	TEE_ObjectHandle o = TEE_HANDLE_NULL;
	TEE_Result res = TEE_ERROR_GENERIC;
	TEE_UUID __maybe_unused uuid = TA_UUID;
	TEE_ObjectInfo oi = { };
	size_t obj_id_sz = 0;
	void *obj_id = NULL;
	size_t i = 0;

	IMSG("Clearing TA storage (UUID: %pUl, storage ID: 0x%x)",
	     (void *)&uuid, storage_id);
	res = TEE_AllocatePersistentObjectEnumerator(&oe);
	if (res)
		return res;
	res = TEE_StartPersistentObjectEnumerator(oe, storage_id);
	if (res == TEE_ERROR_ITEM_NOT_FOUND) {
		IMSG("No object found");
		res = TEE_SUCCESS;
		goto out;
	}
	if (res)
		goto out;
	obj_id = TEE_Malloc(TEE_OBJECT_ID_MAX_LEN, 0);
	if (!obj_id) {
		res = TEE_ERROR_OUT_OF_MEMORY;
		goto out;
	}

	while (true) {
		enum_res = TEE_GetNextPersistentObject(oe, &oi, obj_id,
						       &obj_id_sz);
		if (enum_res == TEE_ERROR_ITEM_NOT_FOUND)
			break;
		if (enum_res) {
			res = enum_res;
			break;
		}
		IMSG("Deleting persistent object #%zu", i);
		res = TEE_OpenPersistentObject(storage_id, obj_id, obj_id_sz,
					       TEE_DATA_FLAG_ACCESS_WRITE_META,
					       &o);
		if (res)
			break;
		TEE_CloseAndDeletePersistentObject1(o);
		i++;
	}

out:
	TEE_FreePersistentObjectEnumerator(oe);
	TEE_Free(obj_id);
	return res;
}

TEE_Result ta_storage_cmd_clear_storage(uint32_t param_types,
					TEE_Param params[4])
{
	uint32_t id[] = { TEE_STORAGE_PRIVATE_REE, TEE_STORAGE_PRIVATE_RPMB };
	TEE_Result res = TEE_ERROR_GENERIC;
	size_t i = 0;

	(void)param_types;
	(void)params;

	for (i = 0; i < sizeof(id) / sizeof(id[0]); i++) {
		res = clear_storage(id[i]);
		if (res)
			break;
	}
	return res;
}
