blob: 7ccf89003a4e95a71ca3e93754949692818ea213 [file] [log] [blame]
/*
* Copyright (c) 2018-2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <debug.h>
#include <smccc.h>
#include <ffa_helpers.h>
#include <ffa_svc.h>
#define OPTEE_FFA_GET_API_VERSION (0)
#define OPTEE_FFA_GET_OS_VERSION (1)
#define OPTEE_FFA_GET_OS_VERSION_MAJOR (3)
#define OPTEE_FFA_GET_OS_VERSION_MINOR (8)
/*-----------------------------------------------------------------------------
* FFA_RUN
*
* Parameters
* uint32 Function ID (w0): 0x8400006D
* uint32 Target information (w1): Information to identify target SP/VM
* -Bits[31:16]: ID of SP/VM.
* -Bits[15:0]: ID of vCPU of SP/VM to run.
* Other Parameter registers w2-w7/x2-x7: Reserved (MBZ)
*
* On failure, returns FFA_ERROR in w0 and error code in w2:
* -INVALID_PARAMETERS: Unrecognized endpoint or vCPU ID
* -NOT_SUPPORTED: This function is not implemented at this FFA instance
* -DENIED: Callee is not in a state to handle this request
* -BUSY: vCPU is busy and caller must retry later
* -ABORTED: vCPU or VM ran into an unexpected error and has aborted
*/
smc_ret_values ffa_run(uint32_t dest_id, uint32_t vcpu_id)
{
smc_args args = {
FFA_MSG_RUN,
(dest_id << 16) | vcpu_id,
0, 0, 0, 0, 0, 0
};
return tftf_smc(&args);
}
/*-----------------------------------------------------------------------------
* FFA_MSG_SEND_DIRECT_REQ
*
* Parameters
* uint32 Function ID (w0): 0x8400006F / 0xC400006F
* uint32 Source/Destination IDs (w1): Source and destination endpoint IDs
* -Bit[31:16]: Source endpoint ID
* -Bit[15:0]: Destination endpoint ID
* uint32/uint64 (w2/x2) - RFU MBZ
* w3-w7 - Implementation defined
*
* On failure, returns FFA_ERROR in w0 and error code in w2:
* -INVALID_PARAMETERS: Invalid endpoint ID or non-zero reserved register
* -DENIED: Callee is not in a state to handle this request
* -NOT_SUPPORTED: This function is not implemented at this FFA instance
* -BUSY: Message target is busy
* -ABORTED: Message target ran into an unexpected error and has aborted
*/
static smc_ret_values __ffa_msg_send_direct_req32_5(uint32_t source_id,
uint32_t dest_id,
uint32_t arg0,
uint32_t arg1,
uint32_t arg2,
uint32_t arg3,
uint32_t arg4)
{
smc_args args = {
FFA_MSG_SEND_DIRECT_REQ_SMC32,
(source_id << 16) | dest_id,
0,
arg0, arg1, arg2, arg3, arg4
};
return tftf_smc(&args);
}
/* Direct message send helper accepting a single 32b message argument */
smc_ret_values ffa_msg_send_direct_req(uint32_t source_id, uint32_t dest_id,
uint32_t message)
{
return __ffa_msg_send_direct_req32_5(source_id, dest_id,
message, 0, 0, 0, 0);
}
static smc_ret_values __ffa_msg_send_direct_req64_5(uint32_t source_id,
uint32_t dest_id,
uint64_t arg0,
uint64_t arg1,
uint64_t arg2,
uint64_t arg3,
uint64_t arg4)
{
smc_args args = {
FFA_MSG_SEND_DIRECT_REQ_SMC64,
(source_id << 16) | dest_id,
0,
arg0, arg1, arg2, arg3, arg4
};
return tftf_smc(&args);
}
/* Direct message send helper accepting a single 64b message argument */
smc_ret_values ffa_msg_send_direct_req64(uint32_t source_id, uint32_t dest_id,
uint64_t message)
{
return __ffa_msg_send_direct_req64_5(source_id, dest_id,
message, 0, 0, 0, 0);
}
/*
* check_spmc_execution_level
*
* Attempt sending impdef protocol messages to OP-TEE through direct messaging.
* Criteria for detecting OP-TEE presence is that responses match defined
* version values. In the case of SPMC running at S-EL2 (and Cactus instances
* running at S-EL1) the response will not match the pre-defined version IDs.
*
* Returns true if SPMC is probed as being OP-TEE at S-EL1.
*
*/
bool check_spmc_execution_level(void)
{
unsigned int is_optee_spmc_criteria = 0U;
smc_ret_values ret_values;
/*
* Send a first OP-TEE-defined protocol message through
* FFA direct message.
*
*/
ret_values = ffa_msg_send_direct_req(HYP_ID, SP_ID(1),
OPTEE_FFA_GET_API_VERSION);
if ((ret_values.ret3 == FFA_VERSION_MAJOR) &&
(ret_values.ret4 == FFA_VERSION_MINOR)) {
is_optee_spmc_criteria++;
}
/*
* Send a second OP-TEE-defined protocol message through
* FFA direct message.
*
*/
ret_values = ffa_msg_send_direct_req(HYP_ID, SP_ID(1),
OPTEE_FFA_GET_OS_VERSION);
if ((ret_values.ret3 == OPTEE_FFA_GET_OS_VERSION_MAJOR) &&
(ret_values.ret4 == OPTEE_FFA_GET_OS_VERSION_MINOR)) {
is_optee_spmc_criteria++;
}
return (is_optee_spmc_criteria == 2U);
}
/*
* FFA Version ABI helper.
* Version fields:
* -Bits[30:16]: Major version.
* -Bits[15:0]: Minor version.
*/
smc_ret_values ffa_version(uint32_t input_version)
{
smc_args args = {
.fid = FFA_VERSION,
.arg1 = input_version
};
return tftf_smc(&args);
}
smc_ret_values ffa_id_get(void)
{
smc_args args = {
.fid = FFA_ID_GET
};
return tftf_smc(&args);
}
smc_ret_values ffa_msg_wait(void)
{
smc_args args = {
.fid = FFA_MSG_WAIT
};
return tftf_smc(&args);
}
smc_ret_values ffa_msg_send_direct_resp(ffa_vm_id_t source_id,
ffa_vm_id_t dest_id,
uint32_t message)
{
smc_args args = {
.fid = FFA_MSG_SEND_DIRECT_RESP_SMC32,
.arg1 = ((uint32_t)source_id << 16) | dest_id,
.arg3 = message
};
return tftf_smc(&args);
}
smc_ret_values ffa_error(int32_t error_code)
{
smc_args args = {
.fid = FFA_ERROR,
.arg1 = 0,
.arg2 = error_code
};
return tftf_smc(&args);
}
/* Query the higher EL if the requested FF-A feature is implemented. */
smc_ret_values ffa_features(uint32_t feature)
{
smc_args args = {
.fid = FFA_FEATURES,
.arg1 = feature
};
return tftf_smc(&args);
}
/* Get information about VMs or SPs based on UUID */
smc_ret_values ffa_partition_info_get(const uint32_t uuid[4])
{
smc_args args = {
.fid = FFA_PARTITION_INFO_GET,
.arg1 = uuid[0],
.arg2 = uuid[1],
.arg3 = uuid[2],
.arg4 = uuid[3]
};
return tftf_smc(&args);
}
/* Query SPMD that the rx buffer of the partition can be released */
smc_ret_values ffa_rx_release(void)
{
smc_args args = {
.fid = FFA_RX_RELEASE
};
return tftf_smc(&args);
}
/* Map the RXTX buffer */
smc_ret_values ffa_rxtx_map(uintptr_t send, uintptr_t recv, uint32_t pages)
{
smc_args args = {
.fid = FFA_RXTX_MAP_SMC64,
.arg1 = send,
.arg2 = recv,
.arg3 = pages
};
return tftf_smc(&args);
}