Commit dc9dc3d0 authored by Mahesh Rao's avatar Mahesh Rao Committed by Anas Nashif
Browse files

subsystem: sip_svc: Add ARM SiP SVC subsystem



Introduce a new SiP SVC subsystem to provide ARM Silicon Provider based
supervisory call services. SiP SVC service provides the capability to
send SMC/HVC call from kernel running at EL1 to hypervisor/
secure monitor firmware running at EL2/EL3 and also added SiP SVC shell
commands to exercise the service.

Signed-off-by: default avatarMahesh Rao <mahesh.rao@intel.com>
parent 1a7576ce
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -221,6 +221,11 @@ BUILD_ASSERT((CONFIG_ARM_SIP_SVC_EL3_MAX_ALLOWED_TRANSACTIONS > 0),

#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)

SIP_SVC_CONTROLLER_DEFINE(0, DT_PROP(DT_SIP_SMC, method), DEVICE_DT_GET(DT_SIP_SMC),
			  DT_PROP(DT_SIP_SMC, zephyr_num_clients),
			  CONFIG_ARM_SIP_SVC_EL3_MAX_ALLOWED_TRANSACTIONS,
			  CONFIG_ARM_SIP_SVC_EL3_MAILBOX_RESPONSE_SIZE);

DEVICE_DT_DEFINE(DT_SIP_SMC, arm_sip_smc_init, NULL, NULL, NULL, POST_KERNEL,
		 CONFIG_ARM_SIP_SVC_DRIVER_INIT_PRIORITY, &api);

+1 −0
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <zephyr/kernel.h>
#include <zephyr/arch/arm64/arm-smccc.h>
#include <zephyr/drivers/sip_svc/sip_svc_proto.h>
#include <zephyr/sip_svc/sip_svc_controller.h>

#define DEV_API(dev) ((struct svc_driver_api *)(dev)->api)

+188 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2022-2023, Intel Corporation.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef ZEPHYR_INCLUDE_SIP_SVC_H_
#define ZEPHYR_INCLUDE_SIP_SVC_H_

/**
 * @file
 * @brief Public API for ARM SiP services
 *
 * ARM SiP service provides the capability to send the
 * SMC/HVC call from kernel running at EL1 to hypervisor/secure
 * monitor firmware running at EL2/EL3.
 *
 * Only allow one SMC and one HVC per system.
 *
 * The service support multiple clients.
 *
 * The client must open a channel before sending any request and
 * close the channel immediately after complete. The service only
 * allow one channel at one time.
 *
 * The service will return the SMC/HVC return value to the client
 * via callback function.
 *
 * The client state machine
 * - INVALID: Invalid state before registration.
 * - IDLE   : Initial state.
 * - OPEN   : The client will switch from IDLE to OPEN once it
 *            successfully open the channel. On the other hand, it
 *            will switch from OPEN to IDLE state once it successfully
 *            close the channel.
 * - ABORT  : The client has closed the channel, however, there are
 *            incomplete transactions being left over. The service
 *            will only move the client back to IDLE state once all
 *            transactions completed. The client is not allowed to
 *            re-open the channel when in ABORT state/
 */

#include <zephyr/kernel.h>
#include <zephyr/arch/arm64/arm-smccc.h>
#include <zephyr/drivers/sip_svc/sip_svc_proto.h>

#define SIP_SVC_CLIENT_ST_INVALID 0
#define SIP_SVC_CLIENT_ST_IDLE	  1
#define SIP_SVC_CLIENT_ST_OPEN	  2
#define SIP_SVC_CLIENT_ST_ABORT	  3

/** @brief ARM sip service callback function prototype for response after completion
 *
 * On success , response is returned via a callback to the user.
 *
 * @param c_token Client's token
 * @param res pointer to struct sip_svc_response
 */
typedef void (*sip_svc_cb_fn)(uint32_t c_token, struct sip_svc_response *res);

/**
 * @brief Register a client on ARM SiP service
 *
 * On success, the client will be at IDLE state in the service and
 * the service will return a token to the client. The client can then
 * use the token to open the channel on the service and communicate
 * with hypervisor/secure monitor firmware running at EL2/EL3.
 *
 * @param ctrl Pointer to controller instance whose service provides ARM SMC/HVC
 *            SiP services.
 * @param priv_data Pointer to client private data.
 *
 * @retval token_id on success.
 * @retval SIP_SVC_ID_INVALID invalid arguments, failure to allocate a client id and failure to get
 * a lock.
 */
uint32_t sip_svc_register(void *ctrl, void *priv_data);

/**
 * @brief Unregister a client on ARM SiP service
 *
 * On success, detach the client from the service. Unregistration
 * is only allowed when all transactions belong to the client are closed.
 *
 * @param ctrl Pointer to controller instance which provides ARM SiP services.
 * @param c_token Client's token
 *
 * @retval 0 on success.
 * @retval -EINVALinvalid arguments.
 * @retval -ENODATA if client is not registered correctly.
 * @retval -EBUSY if client has pending transactions.
 * @retval -ECANCELED if client is not in IDLE state.
 * @retval -ENOLCK if failure in acquiring mutex.
 */
int sip_svc_unregister(void *ctrl, uint32_t c_token);

/**
 * @brief Client requests to open a channel on ARM SiP service.
 *
 * Client must open a channel before sending any request via
 * SMC/HVC to hypervisor/secure monitor firmware running at EL2/EL3.
 *
 * The service only allows one opened channel at one time and it is protected
 * by mutex.
 *
 * @param ctrl Pointer to controller instance which provides ARM SiP services.
 * @param c_token Client's token
 * @param k_timeout Waiting time if the mutex have been locked.
 *                   When the mutex have been locked:
 *                   - returns non-zero error code immediately if value is K_NO_WAIT
 *                   - wait forever if the value is K_FOREVER
 *                   - otherwise, for the given time
 *
 * @retval 0 on success.
 * @retval -EINVAL invalid arguments.
 * @retval -ETIMEDOUT timeout expiry.
 * @retval -EALREADY client state is already open.
 */
int sip_svc_open(void *ctrl, uint32_t c_token, k_timeout_t k_timeout);

/**
 * @brief Client requests to close the channel on ARM SiP services.
 *
 * Client must close the channel immediately once complete.
 *
 * @param ctrl Pointer to controller instance which provides ARM SiP services.
 * @param c_token Client's token
 * @param pre_close_req pre close request sent to lower layer on channel close.
 *
 * @retval 0 on success, negative errno on failure.
 * @retval -EINVAL invalid arguments.
 * @retval -ENOTSUP error on sending pre_close_request.
 * @retval -EPROTO client is not in OPEN state.
 */
int sip_svc_close(void *ctrl, uint32_t c_token, struct sip_svc_request *pre_close_req);

/**
 * @brief Client requests to send a SMC/HVC call to EL3/EL2
 *
 * Client must open a channel on the device before using this function.
 * This function is non-blocking and can be called from any context. The
 * service will return a Transaction ID to the client if the request
 * is being accepted. Client callback is called when the transaction is
 * completed.
 *
 * @param ctrl Pointer to controller instance which provides ARM SiP services.
 * @param c_token Client's token
 * @param req Address to the user input in struct sip_svc_request format.
 * @param cb Callback. SMC/SVC return value will be passed to client via
 *           context in struct sip_svc_response format in callback.
 *
 * @retval transaction id on success.
 * @retval -EINVAL invalid arguments.
 * @retval -EOPNOTSUPP invalid command id or function id.
 * @retval -ESRCH invalid client state.
 * @retval -ENOMEM failure to allocate memory.
 * @retval -ENOMSG failure to insert into database.
 * @retval -ENOBUF failure to insert into msgq.
 * @retval -ENOLCK failure to get lock.
 * @retval -EHOSTDOWN sip_svc thread not present.
 * @retval -ENOTSUP check for unsupported condition.
 */
int sip_svc_send(void *ctrl, uint32_t c_token, struct sip_svc_request *req, sip_svc_cb_fn cb);

/**
 * @brief Get the address pointer to the client private data.
 *
 * The pointer is provided by client during registration.
 *
 * @param ctrl Pointer to controller instance which provides ARM SiP service.
 * @param c_token Client's token
 *
 * @retval Address pointer to the client private data.
 * @retval NULL invalid arguments and failure to get lock.
 */
void *sip_svc_get_priv_data(void *ctrl, uint32_t c_token);

/**
 * @brief get the ARM SiP service handle
 *
 * @param method Pointer to controller instance which provides ARM SiP service.
 *
 * @retval Valid pointer.
 * @retval NULL invalid arguments and on providing unsupported method name.
 */
void *sip_svc_get_controller(char *method);

#endif /* ZEPHYR_INCLUDE_SIP_SVC_H_ */
+109 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2023, Intel Corporation.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#ifndef ZEPHYR_SIP_SVC_CONTROLLER_H_
#define ZEPHYR_SIP_SVC_CONTROLLER_H_

/**
 * @note This file should only be included by sip_svc driver.
 */

#ifdef CONFIG_ARM_SIP_SVC_SUBSYS

/**
 * @brief Length of SVC conduit name in sip svc subsystem.
 *
 */
#define SIP_SVC_SUBSYS_CONDUIT_NAME_LENGTH (4)

/**
 *  @brief Arm SiP Service client data.
 *
 */
struct sip_svc_client {

	/* Client id internal to sip_svc*/
	uint32_t id;
	/* Client's token id provided back to client during sip_svc_register() */
	uint32_t token;
	/* Client's state */
	uint32_t state;
	/* Total Number of on-going transaction  of the client */
	uint32_t active_trans_cnt;
	/* Private data of each client , Provided during sip_svc_register() */
	void *priv_data;
	/* Transaction id pool for each client */
	struct sip_svc_id_pool *trans_idx_pool;
};

/**
 * @brief Arm SiP Services controller data.
 *
 */
struct sip_svc_controller {

	/* Initialization status*/
	bool init;
	/* Total number of clients*/
	const uint32_t num_clients;
	/* Maximum allowable transactions in the system per controller*/
	const uint32_t max_transactions;
	/* Response size of buffer used for ASYNC transaction*/
	const uint32_t resp_size;
	/* Total Number of active transactions */
	uint32_t active_job_cnt;
	/* Active ASYNC transactions */
	uint32_t active_async_job_cnt;
	/* Supervisory call name , got from dts entry */
	char method[SIP_SVC_SUBSYS_CONDUIT_NAME_LENGTH];
	/* Pointer to driver instance */
	const struct device *dev;
	/* Pointer to client id pool */
	struct sip_svc_id_pool *client_id_pool;
	/* Pointer to database for storing arguments from sip_svc_send() */
	struct sip_svc_id_map *trans_id_map;
	/* Pointer to client array */
	struct sip_svc_client *clients;
	/* Pointer to Buffer used for storing response from lower layers */
	uint8_t *async_resp_data;
	/* Thread id of sip_svc thread */
	k_tid_t tid;

#if CONFIG_ARM_SIP_SVC_SUBSYS_SINGLY_OPEN
	/* Mutex to restrict one client access */
	struct k_mutex open_mutex;
#endif
	/* Mutex for protecting database access */
	struct k_mutex data_mutex;
	/* msgq for sending sip_svc_request to sip_svc thread */
	struct k_msgq req_msgq;
	/* sip_svc thread object */
	struct k_thread thread;
	/* Stack object of sip_svc thread */
	K_KERNEL_STACK_MEMBER(stack, CONFIG_ARM_SIP_SVC_SUBSYS_THREAD_STACK_SIZE);
};

/**
 * @brief Controller define used by sip_svc driver to instantiate each controller.
 * Each sip_svc driver will use this API to instantiate a controller for sip_svc
 * subsystem to consume, for more details check @ref ITERABLE_SECTION_RAM()
 */
#define SIP_SVC_CONTROLLER_DEFINE(inst, conduit_name, sip_dev, sip_num_clients,                    \
				  sip_max_transactions, sip_resp_size)                             \
	static STRUCT_SECTION_ITERABLE(sip_svc_controller, sip_svc_##inst) = {                     \
		.method = conduit_name,                                                            \
		.dev = sip_dev,                                                                    \
		.num_clients = sip_num_clients,                                                    \
		.max_transactions = sip_max_transactions,                                          \
		.resp_size = sip_resp_size,                                                        \
	}

#else
#define SIP_SVC_CONTROLLER_DEFINE(inst, conduit_name, sip_dev, sip_num_clients,                    \
				  sip_max_transactions, sip_resp_size)
#endif

#endif /* ZEPHYR_SIP_SVC_CONTROLLER_H_ */
+1 −0
Original line number Diff line number Diff line
@@ -36,3 +36,4 @@ add_subdirectory_ifdef(CONFIG_SETTINGS settings)
add_subdirectory_ifdef(CONFIG_SHELL shell)
add_subdirectory_ifdef(CONFIG_TIMING_FUNCTIONS timing)
add_subdirectory_ifdef(CONFIG_ZBUS zbus)
add_subdirectory_ifdef(CONFIG_ARM_SIP_SVC_SUBSYS sip_svc)
Loading