Skip to content
135 changes: 132 additions & 3 deletions core/arch/arm/include/sm/optee_smc.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (c) 2015-2021, Linaro Limited
* Copyright (c) 2015-2023, Linaro Limited
*/
#ifndef OPTEE_SMC_H
#define OPTEE_SMC_H
Expand Down Expand Up @@ -289,7 +289,11 @@
* a3 Bit[7:0]: Number of parameters needed for RPC to be supplied
* as the second MSG arg struct for
* OPTEE_SMC_CALL_WITH_ARG
* Bit[31:8]: Reserved (MBZ)
* Bit[23:8]: The maximum interrupt number being notified. Interrupts
* notified by OP-TEE are identified by a number from 0 to
* that max value. Values for each interrupt number are
* platform specific bindings.
* Bit[31:24]: Reserved (MBZ)
* a3-7 Preserved
*
* Error return register usage:
Expand All @@ -316,6 +320,11 @@
#define OPTEE_SMC_SEC_CAP_ASYNC_NOTIF BIT(5)
/* Secure world supports pre-allocating RPC arg struct */
#define OPTEE_SMC_SEC_CAP_RPC_ARG BIT(6)
/* Secure world supports interrupt notification to normal world */
#define OPTEE_SMC_SEC_CAP_ITR_NOTIF BIT(7)

#define OPTEE_SMC_SEC_CAP_ITR_NOTIF_MAX_MASK GENMASK_32(23, 8)
#define OPTEE_SMC_SEC_CAP_ITR_NOTIF_MAX_SHIFT 8

#define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES U(9)
#define OPTEE_SMC_EXCHANGE_CAPABILITIES \
Expand Down Expand Up @@ -530,7 +539,7 @@
* a0 OPTEE_SMC_RETURN_OK
* a1 value
* a2 Bit[0]: OPTEE_SMC_ASYNC_NOTIF_VALUE_VALID if the value in a1 is
* valid, else 0 if no values where pending
* valid, else 0 if no values were pending
* a2 Bit[1]: OPTEE_SMC_ASYNC_NOTIF_VALUE_PENDING if another value is
* pending, else 0.
* Bit[31:2]: MBZ
Expand Down Expand Up @@ -559,6 +568,126 @@
/* See OPTEE_SMC_CALL_WITH_REGD_ARG above */
#define OPTEE_SMC_FUNCID_CALL_WITH_REGD_ARG U(19)

/*
* Retrieve up to 5 pending interrupt events notified by OP-TEE world,
* whether bottom half is to be scheduled and if there are pending
* async event for waiting threads, all this since the last call of
* this function.
*
* Interrupts notified by OP-TEE are identified by a number from 0 to
* the interrupt number max value for that platform. Values for each
* interrupt number are platform specific bindings.
*
* OP-TEE keeps a record of all posted interrupt notification events.
* When the async notif interrupt is received by normal world,
* this function should be called until all pended interrupt events
* have been retrieved. When an interrupt event is retrieved, it is
* cleared from the record in OP-TEE world. When do bottom half event
* is retrieved (async value 0), it is also cleared from its related
* record in OP-TEE world.
*
* It is expected that this function is called from an interrupt handler
* in normal world.
*
* Call requests usage:
* a0 SMC Function ID, OPTEE_SMC_GET_NOTIF_ITR
* a1-6 Not used
* a7 Hypervisor Client ID register
*
* Normal return register usage:
* a0 OPTEE_SMC_RETURN_OK
* a1 Bit[7:0]: Number of pending interrupt carried in a1..a5
Comment thread
etienne-lms marked this conversation as resolved.
* Bit[8]: OPTEE_SMC_NOTIF_ITR_PENDING if other interrupt(s) are pending
* Bit[9]: OPTEE_SMC_NOTIF_ASYNC_PENDING if a threaded event is pending
* excluding bottom half notification that is retrieved in Bit[10].
* Bit[10]: OPTEE_SMC_NOTIF_DO_BOTTOM_HALF if retrieved bottom half notif
* Bit[15:11]: Reserved for future use, MBZ
* Bit[31:16]: Pending interrupt number if a1 & 0xFF >= 1
* a2 Bit[15:0]: Pending interrupt number if a1 & 0xFF >= 2
* Bit[31:16]: Pending interrupt number if a1 & 0xFF >= 3
* a3 Bit[15:0]: Pending interrupt number if a1 & 0xFF >= 4
* Bit[31:16]: Pending interrupt number if a1 & 0xFF == 5
* a4-7 Preserved
*
* Not supported return register usage:
* a0 OPTEE_SMC_RETURN_ENOTAVAIL
* a1-7 Preserved
*/
#define OPTEE_SMC_NOTIF_ITR_COUNT_MASK GENMASK_32(7, 0)
#define OPTEE_SMC_NOTIF_ITR_PENDING BIT(8)
#define OPTEE_SMC_NOTIF_VALUE_PENDING BIT(9)
#define OPTEE_SMC_NOTIF_DO_BOTTOM_HALF BIT(10)

#define OPTEE_SMC_FUNCID_GET_NOTIF_ITR 20
#define OPTEE_SMC_GET_NOTIF_ITR \
OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_NOTIF_ITR)

/*
* Mask/unmask an interrupt notification
*
* Call requests usage:
* a0 SMC Function ID, OPTEE_SMC_NOTIF_ITR_SET_MASK
* a1 Interrupt number identifier value
* a2 1 to mask, 0 to unmask the interrupt notification
* a3-6 Reserved for future use, MBZ
* a7 Hypervisor Client ID register
*
* Normal return register usage:
* a0 OPTEE_SMC_RETURN_OK
* a1-7 Preserved
*
* Invalid command with provided arguments return usage:
* a0 OPTEE_SMC_RETURN_EBADCMD
* a1-7 Preserved
*/
#define OPTEE_SMC_FUNCID_NOTIF_ITR_SET_MASK 21
#define OPTEE_SMC_NOTIF_ITR_SET_MASK \
OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_NOTIF_ITR_SET_MASK)

/*
* Enable/disable an interrupt notification
*
* Call requests usage:
* a0 SMC Function ID, OPTEE_SMC_NOTIF_ITR_SET_STATE
* a1 Interrupt number identifier value
* a2 1 to enable, 0 to disable the interrupt notification
* a3-6 Reserved for future use, MBZ
* a7 Hypervisor Client ID register
*
* Normal return register usage:
* a0 OPTEE_SMC_RETURN_OK
* a1-7 Preserved
*
* Invalid command with provided arguments return usage:
* a0 OPTEE_SMC_RETURN_EBADCMD
* a1-7 Preserved
*/
#define OPTEE_SMC_FUNCID_NOTIF_ITR_SET_STATE 22
#define OPTEE_SMC_NOTIF_ITR_SET_STATE \
OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_NOTIF_ITR_SET_STATE)

/*
* Enable/disable the wake up from low power feature of an interrupt event
*
* Call requests usage:
* a0 SMC Function ID, OPTEE_SMC_NOTIF_ITR_SET_WAKEUP
* a1 Interrupt number identifier value
* a2 1 to enable, 0 to disable the interrupt wake up capability
* a3-6 Reserved for future use, MBZ
* a7 Hypervisor Client ID register
*
* Normal return register usage:
* a0 OPTEE_SMC_RETURN_OK
* a1-7 Preserved
*
* Invalid command with provided arguments return usage:
* a0 OPTEE_SMC_RETURN_EBADCMD
* a1-7 Preserved
*/
#define OPTEE_SMC_FUNCID_NOTIF_ITR_SET_WAKEUP 23
#define OPTEE_SMC_NOTIF_ITR_SET_WAKEUP \
OPTEE_SMC_STD_CALL_VAL(OPTEE_SMC_FUNCID_NOTIF_ITR_SET_WAKEUP)

/*
* Resume from RPC (for example after processing a foreign interrupt)
*
Expand Down
26 changes: 26 additions & 0 deletions core/arch/arm/kernel/thread_optee_smc.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,28 @@ static uint32_t std_entry_with_regd_arg(uint64_t cookie, size_t offset)
return rv;
}

static uint32_t std_entry_notif_itr_set_state(uint32_t a1, uint32_t a2)
{
uint32_t itr_num = a1;
bool do_enable = a2;

if (a2 > 1 || notif_itr_set_state(itr_num, do_enable))
return OPTEE_SMC_RETURN_EBADCMD;

return OPTEE_SMC_RETURN_OK;
}

static uint32_t std_entry_notif_itr_set_wakeup(uint32_t a1, uint32_t a2)
{
uint32_t itr_num = a1;
bool do_enable = a2;

if (a2 > 1 || notif_itr_set_wakeup(itr_num, do_enable))
return OPTEE_SMC_RETURN_EBADCMD;

return OPTEE_SMC_RETURN_OK;
}

static uint32_t std_smc_entry(uint32_t a0, uint32_t a1, uint32_t a2,
uint32_t a3 __unused)
{
Expand All @@ -280,6 +302,10 @@ static uint32_t std_smc_entry(uint32_t a0, uint32_t a1, uint32_t a2,
with_rpc_arg);
case OPTEE_SMC_CALL_WITH_REGD_ARG:
return std_entry_with_regd_arg(reg_pair_to_64(a1, a2), a3);
case OPTEE_SMC_NOTIF_ITR_SET_STATE:
return std_entry_notif_itr_set_state(a1, a2);
Comment thread
etienne-lms marked this conversation as resolved.
case OPTEE_SMC_NOTIF_ITR_SET_WAKEUP:
return std_entry_notif_itr_set_wakeup(a1, a2);
default:
EMSG("Unknown SMC 0x%"PRIx32, a0);
return OPTEE_SMC_RETURN_EBADCMD;
Expand Down
4 changes: 4 additions & 0 deletions core/arch/arm/plat-stm32mp1/conf.mk
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ $(call force,CFG_STM32_SHARED_IO,y)

ifeq ($(CFG_STM32MP13),y)
$(call force,CFG_BOOT_SECONDARY_REQUEST,n)
$(call force,CFG_CORE_ASYNC_NOTIF,y)
$(call force,CFG_CORE_ASYNC_NOTIF_GIC_INTID,31)
$(call force,CFG_CORE_ITR_NOTIF,y)
$(call force,CFG_CORE_ITR_NOTIF_MAX,7)
$(call force,CFG_CORE_RESERVED_SHM,n)
$(call force,CFG_DRIVERS_CLK_FIXED,y)
$(call force,CFG_SECONDARY_INIT_CNTFRQ,n)
Expand Down
5 changes: 5 additions & 0 deletions core/arch/arm/plat-vexpress/conf.mk
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,17 @@ CFG_DTB_MAX_SIZE ?= 0x100000
ifeq ($(CFG_SCMI_SCPFW),y)
$(call force,CFG_SCMI_SCPFW_PRODUCT,optee-fvp)
endif
CFG_CORE_ASYNC_NOTIF ?= y
CFG_CORE_ASYNC_NOTIF_GIC_INTID ?= 219
endif

ifneq (,$(filter $(PLATFORM_FLAVOR),qemu_virt qemu_armv8a))
CFG_DT_DRIVER_EMBEDDED_TEST ?= y
ifeq ($(CFG_DT_DRIVER_EMBEDDED_TEST),y)
$(call force,CFG_EMBED_DTB_SOURCE_FILE,embedded_dtb_test.dts,Mandated for DT tests)
# Default enable CFG_CORE_ITR_NOTIF for test purpose as denoted by max value 0
CFG_CORE_ITR_NOTIF ?= $(CFG_CORE_ASYNC_NOTIF)
CFG_CORE_ITR_NOTIF_MAX ?= 0
endif
endif

Expand Down
85 changes: 84 additions & 1 deletion core/arch/arm/tee/entry_fast.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2015-2021, Linaro Limited
* Copyright (c) 2015-2023, Linaro Limited
* Copyright (c) 2014, STMicroelectronics International N.V.
*/

#include <assert.h>
#include <config.h>
#include <kernel/boot.h>
#include <kernel/misc.h>
Expand All @@ -13,6 +14,7 @@
#include <mm/core_mmu.h>
#include <optee_msg.h>
#include <sm/optee_smc.h>
#include <stdint.h>
#include <tee/entry_fast.h>

#ifdef CFG_CORE_RESERVED_SHM
Expand Down Expand Up @@ -66,6 +68,14 @@ static void tee_entry_exchange_capabilities(struct thread_smc_args *args)
{
bool res_shm_en = IS_ENABLED(CFG_CORE_RESERVED_SHM);
bool dyn_shm_en __maybe_unused = false;
unsigned int notif_itr_max_number = 0;

static_assert(THREAD_RPC_MAX_NUM_PARAMS <= UINT8_MAX);
Comment thread
etienne-lms marked this conversation as resolved.
#ifdef CFG_CORE_ITR_NOTIF
static_assert(NOTIF_ITR_VALUE_MAX <= UINT16_MAX);

notif_itr_max_number = NOTIF_ITR_VALUE_MAX;
#endif

/*
* Currently we ignore OPTEE_SMC_NSEC_CAP_UNIPROCESSOR.
Expand Down Expand Up @@ -116,6 +126,14 @@ static void tee_entry_exchange_capabilities(struct thread_smc_args *args)

args->a1 |= OPTEE_SMC_SEC_CAP_RPC_ARG;
args->a3 = THREAD_RPC_MAX_NUM_PARAMS;

if (IS_ENABLED(CFG_CORE_ITR_NOTIF)) {
args->a1 |= OPTEE_SMC_SEC_CAP_ITR_NOTIF;
args->a3 |= notif_itr_max_number <<
OPTEE_SMC_SEC_CAP_ITR_NOTIF_MAX_SHIFT;
}
IMSG("Interrupt notifications are %sabled",
args->a1 & OPTEE_SMC_SEC_CAP_ITR_NOTIF ? "en" : "dis");
}

static void tee_entry_disable_shm_cache(struct thread_smc_args *args)
Expand Down Expand Up @@ -217,6 +235,57 @@ static void get_async_notif_value(struct thread_smc_args *args)
args->a2 |= OPTEE_SMC_ASYNC_NOTIF_PENDING;
}

static void get_pending_notif(struct thread_smc_args *args)
{
bool do_bottom_half = false;
bool value_pending = false;
bool itr_pending = false;
uint16_t itr[5] = { 0 };
size_t count = ARRAY_SIZE(itr);

notif_get_pending(&do_bottom_half, &value_pending, itr, &count);

assert(count <= ARRAY_SIZE(itr) + 1);
if (count == ARRAY_SIZE(itr) + 1) {
count = ARRAY_SIZE(itr);
itr_pending = true;
}

args->a0 = OPTEE_SMC_RETURN_OK;
args->a1 = count | SHIFT_U32((uint32_t)itr[0], 16);
args->a2 = itr[1] | SHIFT_U32((uint32_t)itr[2], 16);
args->a3 = itr[3] | SHIFT_U32((uint32_t)itr[4], 16);

if (itr_pending)
args->a1 |= OPTEE_SMC_NOTIF_ITR_PENDING;
if (value_pending)
args->a1 |= OPTEE_SMC_NOTIF_VALUE_PENDING;
if (do_bottom_half)
args->a1 |= OPTEE_SMC_NOTIF_DO_BOTTOM_HALF;

count = args->a1 & OPTEE_SMC_NOTIF_ITR_COUNT_MASK;
FMSG("Pending notif: do bottom half %u, async events %u, %zu it: %"
PRId16" %"PRId16" %"PRId16" %"PRId16" %"PRId16", pending %u",
do_bottom_half, value_pending, count, itr[0], itr[1], itr[2],
itr[3], itr[4], itr_pending);
}

static void set_itr_notif_mask(struct thread_smc_args *args __maybe_unused)
{
#ifdef CFG_CORE_ITR_NOTIF
uint32_t itr_num = args->a1;
bool masked = args->a2;
Comment thread
jenswikl marked this conversation as resolved.

if (args->a2 > 1 || itr_num > NOTIF_ITR_VALUE_MAX) {
args->a0 = OPTEE_SMC_RETURN_EBADCMD;
return;
}

notif_itr_set_mask(itr_num, masked);
args->a0 = OPTEE_SMC_RETURN_OK;
#endif
}

/*
* If tee_entry_fast() is overridden, it's still supposed to call this
* function.
Expand Down Expand Up @@ -291,6 +360,20 @@ void __tee_entry_fast(struct thread_smc_args *args)
args->a0 = OPTEE_SMC_RETURN_UNKNOWN_FUNCTION;
break;

case OPTEE_SMC_GET_NOTIF_ITR:
if (IS_ENABLED(CFG_CORE_ITR_NOTIF))
get_pending_notif(args);
else
args->a0 = OPTEE_SMC_RETURN_UNKNOWN_FUNCTION;
break;

case OPTEE_SMC_NOTIF_ITR_SET_MASK:
if (IS_ENABLED(CFG_CORE_ITR_NOTIF))
set_itr_notif_mask(args);
else
args->a0 = OPTEE_SMC_RETURN_UNKNOWN_FUNCTION;
break;

default:
args->a0 = OPTEE_SMC_RETURN_UNKNOWN_FUNCTION;
break;
Expand Down
Loading