Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(take 2) NS Interrupt notification over async notif #5793

Closed
wants to merge 9 commits into from
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
etienne-lms marked this conversation as resolved.
Show resolved Hide 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);
etienne-lms marked this conversation as resolved.
Show resolved Hide 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);
etienne-lms marked this conversation as resolved.
Show resolved Hide 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;
jenswi-linaro marked this conversation as resolved.
Show resolved Hide 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