blob: 9524c96d6b55c7624e6d20835b500c03346e0604 [file] [log] [blame]
/********************************************************************************
* Marvell GPL License Option
*
* If you received this File from Marvell, you may opt to use, redistribute and/or
* modify this File in accordance with the terms and conditions of the General
* Public License Version 2, June 1991 (the "GPL License"), a copy of which is
* available along with the File in the license.txt file or by writing to the Free
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or
* on the worldwide web at http://www.gnu.org/licenses/gpl.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
* WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
* DISCLAIMED. The GPL License provides additional details about this warranty
* disclaimer.
******************************************************************************/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/moduleparam.h>
#include <linux/hardirq.h>
#include "config.h"
#include "tz_driver.h"
#include "tz_nw_ioctl.h"
#include "tz_nw_api.h"
#include "tz_nw_comm.h"
#include "tz_client_api.h"
#include "tz_boot_cmd.h"
#define TZC_DEV_ID (1)
#ifdef CONFIG_DEBUG
#define tz_debug(fmt, args...) printk(KERN_DEBUG "TZ %s(%i, %s): " fmt "\n", \
__func__, current->pid, current->comm, ## args)
#else
#define tz_debug(...)
#endif
#define tz_error(fmt, args...) printk(KERN_ERR "TZ ERROR %s(%i, %s): " fmt "\n", \
__func__, current->pid, current->comm, ## args)
#define tz_info(fmt, args...) printk(KERN_INFO "TZ %s(%i, %s): " fmt "\n", \
__func__, current->pid, current->comm, ## args)
void *tzc_malloc(uint32_t size)
{
if (!size) return NULL;
return kmalloc(size, GFP_KERNEL);
}
void tzc_free(void *ptr)
{
if (ptr) kfree(ptr);
}
unsigned long tzc_strtoul(const char *nptr, char **endptr, int base)
{
return simple_strtoul(nptr, endptr, base);
}
char *tzc_strdup(const char *str)
{
if (!str)
return NULL;
return kstrdup(str, GFP_KERNEL);
}
int tzc_open(const char *dev)
{
return TZC_DEV_ID;
}
void tzc_close(int tzc)
{
}
void *tzc_alloc_shm(int tzc, size_t size, void **pa)
{
void *va;
int ret;
/*if in_interrupt or irqs_disabled,can't alloc shared memory*/
if (in_interrupt() || irqs_disabled()) {
*pa = NULL;
return NULL;
}
ret = tzd_kernel_alloc_mem(&va, pa, size);
if (ret) {
*pa = NULL;
return NULL;
}
return va;
}
void tzc_free_shm(int tzc, void *va, void *pa, size_t size)
{
tzd_kernel_free_mem(pa);
}
int tz_invoke_command(int tzc, int task_id, uint32_t cmd_id,
uint32_t param, uint32_t *origin,
tz_cmd_handler callback, void *userdata, void *call_info)
{
uint32_t call_id = param;
struct tz_nw_comm cc;
struct tz_nw_task_client *tc = tz_nw_task_client_get(task_id);
int ret;
cc.call.task_id = task_id;
cc.call.cmd_id = cmd_id;
cc.call.param = param;
while (1) {
ret = tz_nw_comm_invoke_command(tc, &cc, call_id, call_info);
if (ret != TZ_PENDING)
break;
tz_debug("user callback cmd=%d, param=0x%08x\n",
cc.callback.cmd_id, cc.callback.param);
if (callback) {
cc.callback.result = callback(userdata,
cc.callback.cmd_id,
cc.callback.param,
&cc.callback.origin);
} else {
cc.callback.result = TZ_ERROR_NOT_SUPPORTED;
cc.callback.origin = TZ_ORIGIN_UNTRUSTED_APP;
}
}
if (ret != 0) {
cc.call.origin = TZ_ORIGIN_API;
cc.call.result = TZ_ERROR_COMMUNICATION;
}
if (origin)
*origin = cc.call.origin;
return cc.call.result;
}
int tzc_invoke_command(int tzc, int task_id, uint32_t cmd_id,
uint32_t param, uint32_t *origin,
tz_cmd_handler callback, void *userdata)
{
void *kernel_dev_file = tzd_get_kernel_dev_file();
return tz_invoke_command(tzc, task_id, cmd_id, param,
origin, callback, userdata, kernel_dev_file);
}
/*
* mutex function in kernel.
*
* need think about how to support different cases in kernel:
* - call in normal cases
* - call when irq is disabled
* - call in isr
*/
void *tzc_mutex_create(void)
{
struct mutex *lock;
lock = kmalloc(sizeof(*lock), GFP_KERNEL);
if (!lock)
return NULL;
mutex_init(lock);
return lock;
}
int tzc_mutex_destroy(void *lock)
{
if (lock)
kfree(lock);
return TZ_SUCCESS;
}
int tzc_mutex_lock(void *lock)
{
if (lock && !in_atomic()) {
/* if it's interrupted by signal, then try again */
while (-EINTR == mutex_lock_interruptible(lock));
}
return TZ_SUCCESS;
}
int tzc_mutex_trylock(void *lock)
{
if (lock && !in_atomic())
mutex_trylock(lock);
return TZ_SUCCESS;
}
int tzc_mutex_unlock(void *lock)
{
if (lock && !in_atomic())
mutex_unlock(lock);
return TZ_SUCCESS;
}
#ifdef CONFIG_TEE
struct tee_comm *tzc_acquire_tee_comm_channel(int tzc)
{
void *pa = NULL;
struct tee_comm *tc = (struct tee_comm *)tzc_alloc_shm(tzc,
sizeof(struct tee_comm), &pa);
if (tc) {
tc->pa = (uint32_t)((unsigned long)pa);
tc->va = (uint32_t)((unsigned long)tc);
}
return tc;
}
void tzc_release_tee_comm_channel(int tzc, struct tee_comm *tc)
{
tzc_free_shm(tzc, (void *)((unsigned long)tc->va),
(void *)((unsigned long)tc->pa), sizeof(*tc));
}
#endif /* CONFIG_TEE */
void *tzc_get_mem_info(int tzc, void *va, uint32_t *attr)
{
int ret;
struct tz_mem_info info;
info.va = va;
ret = tz_get_meminfo(&info);
if (ret != 0) {
*attr = 0;
return NULL;
}
*attr = info.attr;
return info.pa;
}
int tzc_fast_memmove(int tzc, void *dst_phy_addr, void *src_phy_addr, size_t size)
{
int ret = TZ_SUCCESS;
unsigned long func_id = SMC_FUNC_TOS_MEM_MOVE;
unsigned long result;
result = __smc(func_id, dst_phy_addr, src_phy_addr, size);
if (SMC_FUNC_ID_UNKNOWN == result) {
tz_error("can't support fast memmove");
ret = TZ_ERROR_NOT_SUPPORTED;
} else if (0 != result) {
tz_error("access denied");
ret = TZ_ERROR_ACCESS_DENIED;
}
return ret;
}
static int tzc_fast_secure_cache_op(int tzc, void *phy_addr, size_t size,
unsigned long func_id)
{
int ret = TZ_SUCCESS;
unsigned long result;
result = __smc(func_id, phy_addr, size);
if (SMC_FUNC_ID_UNKNOWN == result) {
tz_error("can't support fast memmove");
ret = TZ_ERROR_NOT_SUPPORTED;
} else if (0 != result) {
tz_error("access denied");
ret = TZ_ERROR_ACCESS_DENIED;
}
return ret;
}
int tzc_fast_secure_cache_clean(int tzc, void *phy_addr, size_t size)
{
return tzc_fast_secure_cache_op(tzc, phy_addr, size,
SMC_FUNC_TOS_SECURE_CACHE_CLEAN);
}
int tzc_fast_secure_cache_invalidate(int tzc, void *phy_addr, size_t size)
{
return tzc_fast_secure_cache_op(tzc, phy_addr, size,
SMC_FUNC_TOS_SECURE_CACHE_INVALIDATE);
}
int tzc_fast_secure_cache_flush(int tzc, void *phy_addr, size_t size)
{
return tzc_fast_secure_cache_op(tzc, phy_addr, size,
SMC_FUNC_TOS_SECURE_CACHE_CLEAN_INVALIDATE);
}
int tzc_create_instance(int tzc, unsigned long param, uint32_t *origin)
{
int ret;
struct tz_instance_param create_param;
create_param.param = param;
ret = tzd_kernel_create_instance(&create_param);
*origin = create_param.origin;
return create_param.result;
}
int tzc_destroy_instance(int tzc, unsigned long param, uint32_t *origin)
{
int ret;
struct tz_instance_param destroy_param;
destroy_param.param = param;
ret = tzd_kernel_destroy_instance(&destroy_param);
*origin = destroy_param.origin;
return destroy_param.result;
}
int tzc_open_session(int tzc, unsigned long param, uint32_t taskId,
uint32_t *origin)
{
int ret;
struct tz_session_param open_param;
open_param.param = param;
open_param.task_id = taskId;
ret = tzd_kernel_open_session(&open_param);
*origin = open_param.origin;
return open_param.result;
}
int tzc_close_session(int tzc, unsigned long param, uint32_t taskId,
uint32_t *origin)
{
int ret;
struct tz_session_param close_param;
close_param.param = param;
close_param.task_id = taskId;
ret = tzd_kernel_close_session(&close_param);
*origin = close_param.origin;
return close_param.result;
}