| // 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); |
| } |