blob: 0e6051f4b251be723f59fbd166ac169f141d4b71 [file] [log] [blame]
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2014, STMicroelectronics International N.V.
*/
#include <kernel/tee_common.h>
#include <kernel/tee_l2cc_mutex.h>
#include <kernel/spinlock.h>
#include <mm/tee_mm.h>
#include <mm/core_memprot.h>
#include <mm/core_mmu.h>
#include <tee_api_defines.h>
#include <trace.h>
/*
* l2cc_mutex_va holds teecore virtual address of TZ L2CC mutex or NULL.
*
* l2cc_mutex_pa holds TZ L2CC mutex physical address. It is relevant only
* if 'l2cc_mutex_va' hold a non-NULL address.
*/
#define MUTEX_SZ sizeof(uint32_t)
static uint32_t *l2cc_mutex_va;
static uint32_t l2cc_mutex_pa;
static uint32_t l2cc_mutex_boot_pa;
static unsigned int *l2cc_mutex;
void tee_l2cc_store_mutex_boot_pa(uint32_t pa)
{
l2cc_mutex_boot_pa = pa;
}
/*
* Allocate public RAM to get a L2CC mutex to shared with NSec.
* Return 0 on success.
*/
static int l2cc_mutex_alloc(void)
{
void *va;
if (l2cc_mutex_va != NULL)
return -1;
l2cc_mutex_pa = l2cc_mutex_boot_pa;
va = phys_to_virt(l2cc_mutex_pa, MEM_AREA_NSEC_SHM);
if (!va)
return -1;
*(uint32_t *)va = 0;
l2cc_mutex_va = va;
return 0;
}
static void l2cc_mutex_set(void *mutex)
{
l2cc_mutex = (unsigned int *)mutex;
}
/*
* tee_xxx_l2cc_mutex(): Handle L2 mutex configuration requests from NSec
*
* Policy:
* - if NSec did not register a L2 mutex, default allocate it in public RAM.
* - if NSec disables L2 mutex, disable the current mutex and unregister it.
*
* Enable L2CC: NSec allows teecore to run safe outer maintance
* with shared mutex.
* Disable L2CC: NSec will run outer maintenance with locking
* shared mutex. teecore cannot run outer maintenance.
* Set L2CC: NSec proposes a Shared Memory locaiotn for the outer
* maintenance shared mutex.
* Get L2CC: NSec requests the outer maintenance shared mutex
* location. If NSec has successufully registered one,
* return its location, otherwise, allocated one in NSec
* and provided NSec the physical location.
*/
TEE_Result tee_enable_l2cc_mutex(void)
{
int ret;
if (!l2cc_mutex_va) {
ret = l2cc_mutex_alloc();
if (ret)
return TEE_ERROR_GENERIC;
}
l2cc_mutex_set(l2cc_mutex_va);
return TEE_SUCCESS;
}
TEE_Result tee_disable_l2cc_mutex(void)
{
l2cc_mutex_va = NULL;
l2cc_mutex_set(NULL);
return TEE_SUCCESS;
}
TEE_Result tee_get_l2cc_mutex(paddr_t *mutex)
{
int ret;
if (!l2cc_mutex_va) {
ret = l2cc_mutex_alloc();
if (ret)
return TEE_ERROR_GENERIC;
}
*mutex = l2cc_mutex_pa;
return TEE_SUCCESS;
}
TEE_Result tee_set_l2cc_mutex(paddr_t *mutex)
{
uint32_t addr;
void *va;
if (l2cc_mutex_va != NULL)
return TEE_ERROR_BAD_PARAMETERS;
addr = *mutex;
if (core_pbuf_is(CORE_MEM_NSEC_SHM, addr, MUTEX_SZ) == false)
return TEE_ERROR_BAD_PARAMETERS;
va = phys_to_virt(addr, MEM_AREA_NSEC_SHM);
if (!va)
return TEE_ERROR_BAD_PARAMETERS;
l2cc_mutex_pa = addr;
l2cc_mutex_va = va;
return TEE_SUCCESS;
}
void tee_l2cc_mutex_lock(void)
{
if (l2cc_mutex)
cpu_spin_lock(l2cc_mutex);
}
void tee_l2cc_mutex_unlock(void)
{
if (l2cc_mutex)
cpu_spin_unlock(l2cc_mutex);
}