mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
tee: add Qualcomm TEE driver
Introduce qcomtee_object, which represents an object in both QTEE and the kernel. QTEE clients can invoke an instance of qcomtee_object to access QTEE services. If this invocation produces a new object in QTEE, an instance of qcomtee_object will be returned. Similarly, QTEE can request services from by issuing a callback request, which invokes an instance of qcomtee_object. Implement initial support for exporting qcomtee_object to userspace and QTEE, enabling the invocation of objects hosted in QTEE and userspace through the TEE subsystem. Tested-by: Neil Armstrong <neil.armstrong@linaro.org> Tested-by: Harshal Dev <quic_hdev@quicinc.com> Acked-by: Sumit Garg <sumit.garg@oss.qualcomm.com> Signed-off-by: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
This commit is contained in:
committed by
Jens Wiklander
parent
bd51393068
commit
d6e290837e
@@ -20856,6 +20856,12 @@ F: Documentation/networking/device_drivers/cellular/qualcomm/rmnet.rst
|
||||
F: drivers/net/ethernet/qualcomm/rmnet/
|
||||
F: include/linux/if_rmnet.h
|
||||
|
||||
QUALCOMM TEE (QCOMTEE) DRIVER
|
||||
M: Amirreza Zarrabi <amirreza.zarrabi@oss.qualcomm.com>
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/tee/qcomtee/
|
||||
|
||||
QUALCOMM TRUST ZONE MEMORY ALLOCATOR
|
||||
M: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
|
||||
L: linux-arm-msm@vger.kernel.org
|
||||
|
||||
@@ -21,5 +21,6 @@ config TEE_DMABUF_HEAPS
|
||||
source "drivers/tee/optee/Kconfig"
|
||||
source "drivers/tee/amdtee/Kconfig"
|
||||
source "drivers/tee/tstee/Kconfig"
|
||||
source "drivers/tee/qcomtee/Kconfig"
|
||||
|
||||
endif
|
||||
|
||||
@@ -7,3 +7,4 @@ tee-objs += tee_shm_pool.o
|
||||
obj-$(CONFIG_OPTEE) += optee/
|
||||
obj-$(CONFIG_AMDTEE) += amdtee/
|
||||
obj-$(CONFIG_ARM_TSTEE) += tstee/
|
||||
obj-$(CONFIG_QCOMTEE) += qcomtee/
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Qualcomm Trusted Execution Environment Configuration
|
||||
config QCOMTEE
|
||||
tristate "Qualcomm TEE Support"
|
||||
depends on !CPU_BIG_ENDIAN
|
||||
select QCOM_SCM
|
||||
select QCOM_TZMEM_MODE_SHMBRIDGE
|
||||
help
|
||||
This option enables the Qualcomm Trusted Execution Environment (QTEE)
|
||||
driver. It provides an API to access services offered by QTEE and
|
||||
its loaded Trusted Applications (TAs). Additionally, it facilitates
|
||||
the export of userspace services provided by supplicants to QTEE.
|
||||
@@ -0,0 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_QCOMTEE) += qcomtee.o
|
||||
qcomtee-objs += async.o
|
||||
qcomtee-objs += call.o
|
||||
qcomtee-objs += core.o
|
||||
qcomtee-objs += shm.o
|
||||
qcomtee-objs += user_obj.o
|
||||
@@ -0,0 +1,182 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include "qcomtee.h"
|
||||
|
||||
#define QCOMTEE_ASYNC_VERSION_1_0 0x00010000U /* Maj: 0x0001, Min: 0x0000. */
|
||||
#define QCOMTEE_ASYNC_VERSION_1_1 0x00010001U /* Maj: 0x0001, Min: 0x0001. */
|
||||
#define QCOMTEE_ASYNC_VERSION_1_2 0x00010002U /* Maj: 0x0001, Min: 0x0002. */
|
||||
#define QCOMTEE_ASYNC_VERSION_CURRENT QCOMTEE_ASYNC_VERSION_1_2
|
||||
|
||||
#define QCOMTEE_ASYNC_VERSION_MAJOR(n) upper_16_bits(n)
|
||||
#define QCOMTEE_ASYNC_VERSION_MINOR(n) lower_16_bits(n)
|
||||
|
||||
#define QCOMTEE_ASYNC_VERSION_CURRENT_MAJOR \
|
||||
QCOMTEE_ASYNC_VERSION_MAJOR(QCOMTEE_ASYNC_VERSION_CURRENT)
|
||||
#define QCOMTEE_ASYNC_VERSION_CURRENT_MINOR \
|
||||
QCOMTEE_ASYNC_VERSION_MINOR(QCOMTEE_ASYNC_VERSION_CURRENT)
|
||||
|
||||
/**
|
||||
* struct qcomtee_async_msg_hdr - Asynchronous message header format.
|
||||
* @version: current async protocol version of the remote endpoint.
|
||||
* @op: async operation.
|
||||
*
|
||||
* @version specifies the endpoint's (QTEE or driver) supported async protocol.
|
||||
* For example, if QTEE sets @version to %QCOMTEE_ASYNC_VERSION_1_1, QTEE
|
||||
* handles operations supported in %QCOMTEE_ASYNC_VERSION_1_1 or
|
||||
* %QCOMTEE_ASYNC_VERSION_1_0. @op determines the message format.
|
||||
*/
|
||||
struct qcomtee_async_msg_hdr {
|
||||
u32 version;
|
||||
u32 op;
|
||||
};
|
||||
|
||||
/* Size of an empty async message. */
|
||||
#define QCOMTEE_ASYNC_MSG_ZERO sizeof(struct qcomtee_async_msg_hdr)
|
||||
|
||||
/**
|
||||
* struct qcomtee_async_release_msg - Release asynchronous message.
|
||||
* @hdr: message header as &struct qcomtee_async_msg_hdr.
|
||||
* @counts: number of objects in @object_ids.
|
||||
* @object_ids: array of object IDs that should be released.
|
||||
*
|
||||
* Available in Maj = 0x0001, Min >= 0x0000.
|
||||
*/
|
||||
struct qcomtee_async_release_msg {
|
||||
struct qcomtee_async_msg_hdr hdr;
|
||||
u32 counts;
|
||||
u32 object_ids[] __counted_by(counts);
|
||||
};
|
||||
|
||||
/**
|
||||
* qcomtee_get_async_buffer() - Get the start of the asynchronous message.
|
||||
* @oic: context used for the current invocation.
|
||||
* @async_buffer: return buffer to extract from or fill in async messages.
|
||||
*
|
||||
* If @oic is used for direct object invocation, the whole outbound buffer
|
||||
* is available for the async message. If @oic is used for a callback request,
|
||||
* the tail of the outbound buffer (after the callback request message) is
|
||||
* available for the async message.
|
||||
*
|
||||
* The start of the async buffer is aligned, see qcomtee_msg_offset_align().
|
||||
*/
|
||||
static void qcomtee_get_async_buffer(struct qcomtee_object_invoke_ctx *oic,
|
||||
struct qcomtee_buffer *async_buffer)
|
||||
{
|
||||
struct qcomtee_msg_callback *msg;
|
||||
unsigned int offset;
|
||||
int i;
|
||||
|
||||
if (!(oic->flags & QCOMTEE_OIC_FLAG_BUSY)) {
|
||||
/* The outbound buffer is empty. Using the whole buffer. */
|
||||
offset = 0;
|
||||
} else {
|
||||
msg = (struct qcomtee_msg_callback *)oic->out_msg.addr;
|
||||
|
||||
/* Start offset in a message for buffer arguments. */
|
||||
offset = qcomtee_msg_buffer_args(struct qcomtee_msg_callback,
|
||||
qcomtee_msg_args(msg));
|
||||
|
||||
/* Add size of IB arguments. */
|
||||
qcomtee_msg_for_each_input_buffer(i, msg)
|
||||
offset += qcomtee_msg_offset_align(msg->args[i].b.size);
|
||||
|
||||
/* Add size of OB arguments. */
|
||||
qcomtee_msg_for_each_output_buffer(i, msg)
|
||||
offset += qcomtee_msg_offset_align(msg->args[i].b.size);
|
||||
}
|
||||
|
||||
async_buffer->addr = oic->out_msg.addr + offset;
|
||||
async_buffer->size = oic->out_msg.size - offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* async_release() - Process QTEE async release requests.
|
||||
* @oic: context used for the current invocation.
|
||||
* @msg: async message for object release.
|
||||
* @size: size of the async buffer available.
|
||||
*
|
||||
* Return: Size of the outbound buffer used when processing @msg.
|
||||
*/
|
||||
static size_t async_release(struct qcomtee_object_invoke_ctx *oic,
|
||||
struct qcomtee_async_msg_hdr *async_msg,
|
||||
size_t size)
|
||||
{
|
||||
struct qcomtee_async_release_msg *msg;
|
||||
struct qcomtee_object *object;
|
||||
int i;
|
||||
|
||||
msg = (struct qcomtee_async_release_msg *)async_msg;
|
||||
|
||||
for (i = 0; i < msg->counts; i++) {
|
||||
object = qcomtee_idx_erase(oic, msg->object_ids[i]);
|
||||
qcomtee_object_put(object);
|
||||
}
|
||||
|
||||
return struct_size(msg, object_ids, msg->counts);
|
||||
}
|
||||
|
||||
/**
|
||||
* qcomtee_fetch_async_reqs() - Fetch and process asynchronous messages.
|
||||
* @oic: context used for the current invocation.
|
||||
*
|
||||
* Calls handlers to process the requested operations in the async message.
|
||||
* Currently, only supports async release requests.
|
||||
*/
|
||||
void qcomtee_fetch_async_reqs(struct qcomtee_object_invoke_ctx *oic)
|
||||
{
|
||||
struct qcomtee_async_msg_hdr *async_msg;
|
||||
struct qcomtee_buffer async_buffer;
|
||||
size_t consumed, used = 0;
|
||||
u16 major_ver;
|
||||
|
||||
qcomtee_get_async_buffer(oic, &async_buffer);
|
||||
|
||||
while (async_buffer.size - used > QCOMTEE_ASYNC_MSG_ZERO) {
|
||||
async_msg = (struct qcomtee_async_msg_hdr *)(async_buffer.addr +
|
||||
used);
|
||||
/*
|
||||
* QTEE assumes that the unused space of the async buffer is
|
||||
* zeroed; so if version is zero, the buffer is unused.
|
||||
*/
|
||||
if (async_msg->version == 0)
|
||||
goto out;
|
||||
|
||||
major_ver = QCOMTEE_ASYNC_VERSION_MAJOR(async_msg->version);
|
||||
/* Major version mismatch is a compatibility break. */
|
||||
if (major_ver != QCOMTEE_ASYNC_VERSION_CURRENT_MAJOR) {
|
||||
pr_err("Async message version mismatch (%u != %u)\n",
|
||||
major_ver, QCOMTEE_ASYNC_VERSION_CURRENT_MAJOR);
|
||||
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (async_msg->op) {
|
||||
case QCOMTEE_MSG_OBJECT_OP_RELEASE:
|
||||
consumed = async_release(oic, async_msg,
|
||||
async_buffer.size - used);
|
||||
break;
|
||||
default:
|
||||
pr_err("Unsupported async message %u\n", async_msg->op);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Supported operation but unable to parse the message. */
|
||||
if (!consumed) {
|
||||
pr_err("Unable to parse async message for op %u\n",
|
||||
async_msg->op);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Next async message. */
|
||||
used += qcomtee_msg_offset_align(consumed);
|
||||
}
|
||||
|
||||
out:
|
||||
/* Reset the async buffer so async requests do not loop to QTEE. */
|
||||
memzero_explicit(async_buffer.addr, async_buffer.size);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,143 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#ifndef QCOMTEE_H
|
||||
#define QCOMTEE_H
|
||||
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/tee_core.h>
|
||||
|
||||
#include "qcomtee_msg.h"
|
||||
#include "qcomtee_object.h"
|
||||
|
||||
/* Flags relating to object reference. */
|
||||
#define QCOMTEE_OBJREF_FLAG_TEE BIT(0)
|
||||
#define QCOMTEE_OBJREF_FLAG_USER BIT(1)
|
||||
|
||||
/**
|
||||
* struct qcomtee - Main service struct.
|
||||
* @teedev: client device.
|
||||
* @pool: shared memory pool.
|
||||
* @ctx: driver private context.
|
||||
* @oic: context to use for the current driver invocation.
|
||||
* @wq: workqueue for QTEE async operations.
|
||||
* @xa_local_objects: array of objects exported to QTEE.
|
||||
* @xa_last_id: next ID to allocate.
|
||||
* @qtee_version: QTEE version.
|
||||
*/
|
||||
struct qcomtee {
|
||||
struct tee_device *teedev;
|
||||
struct tee_shm_pool *pool;
|
||||
struct tee_context *ctx;
|
||||
struct qcomtee_object_invoke_ctx oic;
|
||||
struct workqueue_struct *wq;
|
||||
struct xarray xa_local_objects;
|
||||
u32 xa_last_id;
|
||||
u32 qtee_version;
|
||||
};
|
||||
|
||||
void qcomtee_fetch_async_reqs(struct qcomtee_object_invoke_ctx *oic);
|
||||
struct qcomtee_object *qcomtee_idx_erase(struct qcomtee_object_invoke_ctx *oic,
|
||||
u32 idx);
|
||||
|
||||
struct tee_shm_pool *qcomtee_shm_pool_alloc(void);
|
||||
void qcomtee_msg_buffers_free(struct qcomtee_object_invoke_ctx *oic);
|
||||
int qcomtee_msg_buffers_alloc(struct qcomtee_object_invoke_ctx *oic,
|
||||
struct qcomtee_arg *u);
|
||||
|
||||
/**
|
||||
* qcomtee_object_do_invoke_internal() - Submit an invocation for an object.
|
||||
* @oic: context to use for the current invocation.
|
||||
* @object: object being invoked.
|
||||
* @op: requested operation on the object.
|
||||
* @u: array of arguments for the current invocation.
|
||||
* @result: result returned from QTEE.
|
||||
*
|
||||
* The caller is responsible for keeping track of the refcount for each
|
||||
* object, including @object. On return, the caller loses ownership of all
|
||||
* input objects of type %QCOMTEE_OBJECT_TYPE_CB.
|
||||
*
|
||||
* Return: On success, returns 0; on failure, returns < 0.
|
||||
*/
|
||||
int qcomtee_object_do_invoke_internal(struct qcomtee_object_invoke_ctx *oic,
|
||||
struct qcomtee_object *object, u32 op,
|
||||
struct qcomtee_arg *u, int *result);
|
||||
|
||||
/**
|
||||
* struct qcomtee_context_data - Clients' or supplicants' context.
|
||||
* @qtee_objects_idr: QTEE objects in this context.
|
||||
* @qtee_lock: mutex for @qtee_objects_idr.
|
||||
* @reqs_idr: requests in this context that hold ID.
|
||||
* @reqs_list: FIFO for requests in PROCESSING or QUEUED state.
|
||||
* @reqs_lock: mutex for @reqs_idr, @reqs_list and request states.
|
||||
* @req_c: completion used when the supplicant is waiting for requests.
|
||||
* @released: state of this context.
|
||||
*/
|
||||
struct qcomtee_context_data {
|
||||
struct idr qtee_objects_idr;
|
||||
/* Synchronize access to @qtee_objects_idr. */
|
||||
struct mutex qtee_lock;
|
||||
|
||||
struct idr reqs_idr;
|
||||
struct list_head reqs_list;
|
||||
/* Synchronize access to @reqs_idr, @reqs_list and updating requests states. */
|
||||
struct mutex reqs_lock;
|
||||
|
||||
struct completion req_c;
|
||||
|
||||
bool released;
|
||||
};
|
||||
|
||||
int qcomtee_context_add_qtee_object(struct tee_param *param,
|
||||
struct qcomtee_object *object,
|
||||
struct tee_context *ctx);
|
||||
int qcomtee_context_find_qtee_object(struct qcomtee_object **object,
|
||||
struct tee_param *param,
|
||||
struct tee_context *ctx);
|
||||
void qcomtee_context_del_qtee_object(struct tee_param *param,
|
||||
struct tee_context *ctx);
|
||||
|
||||
int qcomtee_objref_to_arg(struct qcomtee_arg *arg, struct tee_param *param,
|
||||
struct tee_context *ctx);
|
||||
int qcomtee_objref_from_arg(struct tee_param *param, struct qcomtee_arg *arg,
|
||||
struct tee_context *ctx);
|
||||
|
||||
/* OBJECTS: */
|
||||
|
||||
/* (1) User Object API. */
|
||||
|
||||
int is_qcomtee_user_object(struct qcomtee_object *object);
|
||||
void qcomtee_user_object_set_notify(struct qcomtee_object *object, bool notify);
|
||||
void qcomtee_requests_destroy(struct qcomtee_context_data *ctxdata);
|
||||
int qcomtee_user_param_to_object(struct qcomtee_object **object,
|
||||
struct tee_param *param,
|
||||
struct tee_context *ctx);
|
||||
int qcomtee_user_param_from_object(struct tee_param *param,
|
||||
struct qcomtee_object *object,
|
||||
struct tee_context *ctx);
|
||||
|
||||
/**
|
||||
* struct qcomtee_user_object_request_data - Data for user object request.
|
||||
* @id: ID assigned to the request.
|
||||
* @object_id: Object ID being invoked by QTEE.
|
||||
* @op: Requested operation on object.
|
||||
* @np: Number of parameters in the request.
|
||||
*/
|
||||
struct qcomtee_user_object_request_data {
|
||||
int id;
|
||||
u64 object_id;
|
||||
u32 op;
|
||||
int np;
|
||||
};
|
||||
|
||||
int qcomtee_user_object_select(struct tee_context *ctx,
|
||||
struct tee_param *params, int num_params,
|
||||
void __user *uaddr, size_t size,
|
||||
struct qcomtee_user_object_request_data *data);
|
||||
int qcomtee_user_object_submit(struct tee_context *ctx,
|
||||
struct tee_param *params, int num_params,
|
||||
int req_id, int errno);
|
||||
|
||||
#endif /* QCOMTEE_H */
|
||||
@@ -0,0 +1,304 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#ifndef QCOMTEE_MSG_H
|
||||
#define QCOMTEE_MSG_H
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
/**
|
||||
* DOC: ''Qualcomm TEE'' (QTEE) Transport Message
|
||||
*
|
||||
* There are two buffers shared with QTEE: inbound and outbound buffers.
|
||||
* The inbound buffer is used for direct object invocation, and the outbound
|
||||
* buffer is used to make a request from QTEE to the kernel; i.e., a callback
|
||||
* request.
|
||||
*
|
||||
* The unused tail of the outbound buffer is also used for sending and
|
||||
* receiving asynchronous messages. An asynchronous message is independent of
|
||||
* the current object invocation (i.e., contents of the inbound buffer) or
|
||||
* callback request (i.e., the head of the outbound buffer); see
|
||||
* qcomtee_get_async_buffer(). It is used by endpoints (QTEE or kernel) as an
|
||||
* optimization to reduce the number of context switches between the secure and
|
||||
* non-secure worlds.
|
||||
*
|
||||
* For instance, QTEE never sends an explicit callback request to release an
|
||||
* object in the kernel. Instead, it sends asynchronous release messages in the
|
||||
* outbound buffer when QTEE returns from the previous direct object invocation,
|
||||
* or appends asynchronous release messages after the current callback request.
|
||||
*
|
||||
* QTEE supports two types of arguments in a message: buffer and object
|
||||
* arguments. Depending on the direction of data flow, they could be input
|
||||
* buffer (IO) to QTEE, output buffer (OB) from QTEE, input object (IO) to QTEE,
|
||||
* or output object (OO) from QTEE. Object arguments hold object IDs. Buffer
|
||||
* arguments hold (offset, size) pairs into the inbound or outbound buffers.
|
||||
*
|
||||
* QTEE holds an object table for objects it hosts and exposes to the kernel.
|
||||
* An object ID is an index to the object table in QTEE.
|
||||
*
|
||||
* For the direct object invocation message format in the inbound buffer, see
|
||||
* &struct qcomtee_msg_object_invoke. For the callback request message format
|
||||
* in the outbound buffer, see &struct qcomtee_msg_callback. For the message
|
||||
* format for asynchronous messages in the outbound buffer, see
|
||||
* &struct qcomtee_async_msg_hdr.
|
||||
*/
|
||||
|
||||
/**
|
||||
* define QCOMTEE_MSG_OBJECT_NS_BIT - Non-secure bit
|
||||
*
|
||||
* Object ID is a globally unique 32-bit number. IDs referencing objects
|
||||
* in the kernel should have %QCOMTEE_MSG_OBJECT_NS_BIT set.
|
||||
*/
|
||||
#define QCOMTEE_MSG_OBJECT_NS_BIT BIT(31)
|
||||
|
||||
/* Static object IDs recognized by QTEE. */
|
||||
#define QCOMTEE_MSG_OBJECT_NULL (0U)
|
||||
#define QCOMTEE_MSG_OBJECT_ROOT (1U)
|
||||
|
||||
/* Definitions from QTEE as part of the transport protocol. */
|
||||
|
||||
/* qcomtee_msg_arg is an argument as recognized by QTEE. */
|
||||
union qcomtee_msg_arg {
|
||||
struct {
|
||||
u32 offset;
|
||||
u32 size;
|
||||
} b;
|
||||
u32 o;
|
||||
};
|
||||
|
||||
/* BI and BO payloads in QTEE messages should be at 64-bit boundaries. */
|
||||
#define qcomtee_msg_offset_align(o) ALIGN((o), sizeof(u64))
|
||||
|
||||
/* Operations for objects are 32-bit. Transport uses the upper 16 bits. */
|
||||
#define QCOMTEE_MSG_OBJECT_OP_MASK GENMASK(15, 0)
|
||||
|
||||
/* Reserved Operation IDs sent to QTEE: */
|
||||
/* QCOMTEE_MSG_OBJECT_OP_RELEASE - Reduces the refcount and releases the object.
|
||||
* QCOMTEE_MSG_OBJECT_OP_RETAIN - Increases the refcount.
|
||||
*
|
||||
* These operation IDs are valid for all objects.
|
||||
*/
|
||||
|
||||
#define QCOMTEE_MSG_OBJECT_OP_RELEASE (QCOMTEE_MSG_OBJECT_OP_MASK - 0)
|
||||
#define QCOMTEE_MSG_OBJECT_OP_RETAIN (QCOMTEE_MSG_OBJECT_OP_MASK - 1)
|
||||
|
||||
/* Subset of operations supported by QTEE root object. */
|
||||
|
||||
#define QCOMTEE_ROOT_OP_REG_WITH_CREDENTIALS 5
|
||||
#define QCOMTEE_ROOT_OP_NOTIFY_DOMAIN_CHANGE 4
|
||||
#define QCOMTEE_ROOT_OP_ADCI_ACCEPT 8
|
||||
#define QCOMTEE_ROOT_OP_ADCI_SHUTDOWN 9
|
||||
|
||||
/* Subset of operations supported by client_env object. */
|
||||
|
||||
#define QCOMTEE_CLIENT_ENV_OPEN 0
|
||||
|
||||
/* List of available QTEE service UIDs and subset of operations. */
|
||||
|
||||
#define QCOMTEE_FEATURE_VER_UID 2033
|
||||
#define QCOMTEE_FEATURE_VER_OP_GET 0
|
||||
/* Get QTEE version number. */
|
||||
#define QCOMTEE_FEATURE_VER_OP_GET_QTEE_ID 10
|
||||
#define QTEE_VERSION_GET_MAJOR(x) (((x) >> 22) & 0xffU)
|
||||
#define QTEE_VERSION_GET_MINOR(x) (((x) >> 12) & 0xffU)
|
||||
#define QTEE_VERSION_GET_PATCH(x) ((x) >> 0 & 0xfffU)
|
||||
|
||||
/* Response types as returned from qcomtee_object_invoke_ctx_invoke(). */
|
||||
|
||||
/* The message contains a callback request. */
|
||||
#define QCOMTEE_RESULT_INBOUND_REQ_NEEDED 3
|
||||
|
||||
/**
|
||||
* struct qcomtee_msg_object_invoke - Direct object invocation message.
|
||||
* @ctx: object ID hosted in QTEE.
|
||||
* @op: operation for the object.
|
||||
* @counts: number of different types of arguments in @args.
|
||||
* @args: array of arguments.
|
||||
*
|
||||
* @counts consists of 4 * 4-bit fields. Bits 0 - 3 represent the number of
|
||||
* input buffers, bits 4 - 7 represent the number of output buffers,
|
||||
* bits 8 - 11 represent the number of input objects, and bits 12 - 15
|
||||
* represent the number of output objects. The remaining bits should be zero.
|
||||
*
|
||||
* 15 12 11 8 7 4 3 0
|
||||
* +----------------+----------------+----------------+----------------+
|
||||
* | #OO objects | #IO objects | #OB buffers | #IB buffers |
|
||||
* +----------------+----------------+----------------+----------------+
|
||||
*
|
||||
* The maximum number of arguments of each type is defined by
|
||||
* %QCOMTEE_ARGS_PER_TYPE.
|
||||
*/
|
||||
struct qcomtee_msg_object_invoke {
|
||||
u32 cxt;
|
||||
u32 op;
|
||||
u32 counts;
|
||||
union qcomtee_msg_arg args[];
|
||||
};
|
||||
|
||||
/* Bit masks for the four 4-bit nibbles holding the counts. */
|
||||
#define QCOMTEE_MASK_IB GENMASK(3, 0)
|
||||
#define QCOMTEE_MASK_OB GENMASK(7, 4)
|
||||
#define QCOMTEE_MASK_IO GENMASK(11, 8)
|
||||
#define QCOMTEE_MASK_OO GENMASK(15, 12)
|
||||
|
||||
/**
|
||||
* struct qcomtee_msg_callback - Callback request message.
|
||||
* @result: result of operation @op on the object referenced by @cxt.
|
||||
* @cxt: object ID hosted in the kernel.
|
||||
* @op: operation for the object.
|
||||
* @counts: number of different types of arguments in @args.
|
||||
* @args: array of arguments.
|
||||
*
|
||||
* For details of @counts, see &qcomtee_msg_object_invoke.counts.
|
||||
*/
|
||||
struct qcomtee_msg_callback {
|
||||
u32 result;
|
||||
u32 cxt;
|
||||
u32 op;
|
||||
u32 counts;
|
||||
union qcomtee_msg_arg args[];
|
||||
};
|
||||
|
||||
/* Offset in the message for the beginning of the buffer argument's contents. */
|
||||
#define qcomtee_msg_buffer_args(t, n) \
|
||||
qcomtee_msg_offset_align(struct_size_t(t, args, n))
|
||||
/* Pointer to the beginning of a buffer argument's content at an offset. */
|
||||
#define qcomtee_msg_offset_to_ptr(m, off) ((void *)&((char *)(m))[(off)])
|
||||
|
||||
/* Some helpers to manage msg.counts. */
|
||||
|
||||
static inline unsigned int qcomtee_msg_num_ib(u32 counts)
|
||||
{
|
||||
return FIELD_GET(QCOMTEE_MASK_IB, counts);
|
||||
}
|
||||
|
||||
static inline unsigned int qcomtee_msg_num_ob(u32 counts)
|
||||
{
|
||||
return FIELD_GET(QCOMTEE_MASK_OB, counts);
|
||||
}
|
||||
|
||||
static inline unsigned int qcomtee_msg_num_io(u32 counts)
|
||||
{
|
||||
return FIELD_GET(QCOMTEE_MASK_IO, counts);
|
||||
}
|
||||
|
||||
static inline unsigned int qcomtee_msg_num_oo(u32 counts)
|
||||
{
|
||||
return FIELD_GET(QCOMTEE_MASK_OO, counts);
|
||||
}
|
||||
|
||||
static inline unsigned int qcomtee_msg_idx_ib(u32 counts)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned int qcomtee_msg_idx_ob(u32 counts)
|
||||
{
|
||||
return qcomtee_msg_num_ib(counts);
|
||||
}
|
||||
|
||||
static inline unsigned int qcomtee_msg_idx_io(u32 counts)
|
||||
{
|
||||
return qcomtee_msg_idx_ob(counts) + qcomtee_msg_num_ob(counts);
|
||||
}
|
||||
|
||||
static inline unsigned int qcomtee_msg_idx_oo(u32 counts)
|
||||
{
|
||||
return qcomtee_msg_idx_io(counts) + qcomtee_msg_num_io(counts);
|
||||
}
|
||||
|
||||
#define qcomtee_msg_for_each(i, first, num) \
|
||||
for ((i) = (first); (i) < (first) + (num); (i)++)
|
||||
|
||||
#define qcomtee_msg_for_each_input_buffer(i, m) \
|
||||
qcomtee_msg_for_each(i, qcomtee_msg_idx_ib((m)->counts), \
|
||||
qcomtee_msg_num_ib((m)->counts))
|
||||
|
||||
#define qcomtee_msg_for_each_output_buffer(i, m) \
|
||||
qcomtee_msg_for_each(i, qcomtee_msg_idx_ob((m)->counts), \
|
||||
qcomtee_msg_num_ob((m)->counts))
|
||||
|
||||
#define qcomtee_msg_for_each_input_object(i, m) \
|
||||
qcomtee_msg_for_each(i, qcomtee_msg_idx_io((m)->counts), \
|
||||
qcomtee_msg_num_io((m)->counts))
|
||||
|
||||
#define qcomtee_msg_for_each_output_object(i, m) \
|
||||
qcomtee_msg_for_each(i, qcomtee_msg_idx_oo((m)->counts), \
|
||||
qcomtee_msg_num_oo((m)->counts))
|
||||
|
||||
/* Sum of arguments in a message. */
|
||||
#define qcomtee_msg_args(m) \
|
||||
(qcomtee_msg_idx_oo((m)->counts) + qcomtee_msg_num_oo((m)->counts))
|
||||
|
||||
static inline void qcomtee_msg_init(struct qcomtee_msg_object_invoke *msg,
|
||||
u32 cxt, u32 op, int in_buffer,
|
||||
int out_buffer, int in_object,
|
||||
int out_object)
|
||||
{
|
||||
u32 counts = 0;
|
||||
|
||||
counts |= (in_buffer & 0xfU);
|
||||
counts |= ((out_buffer - in_buffer) & 0xfU) << 4;
|
||||
counts |= ((in_object - out_buffer) & 0xfU) << 8;
|
||||
counts |= ((out_object - in_object) & 0xfU) << 12;
|
||||
|
||||
msg->cxt = cxt;
|
||||
msg->op = op;
|
||||
msg->counts = counts;
|
||||
}
|
||||
|
||||
/* Generic error codes. */
|
||||
#define QCOMTEE_MSG_OK 0 /* non-specific success code. */
|
||||
#define QCOMTEE_MSG_ERROR 1 /* non-specific error. */
|
||||
#define QCOMTEE_MSG_ERROR_INVALID 2 /* unsupported/unrecognized request. */
|
||||
#define QCOMTEE_MSG_ERROR_SIZE_IN 3 /* supplied buffer/string too large. */
|
||||
#define QCOMTEE_MSG_ERROR_SIZE_OUT 4 /* supplied output buffer too small. */
|
||||
#define QCOMTEE_MSG_ERROR_USERBASE 10 /* start of user-defined error range. */
|
||||
|
||||
/* Transport layer error codes. */
|
||||
#define QCOMTEE_MSG_ERROR_DEFUNCT -90 /* object no longer exists. */
|
||||
#define QCOMTEE_MSG_ERROR_ABORT -91 /* calling thread must exit. */
|
||||
#define QCOMTEE_MSG_ERROR_BADOBJ -92 /* invalid object context. */
|
||||
#define QCOMTEE_MSG_ERROR_NOSLOTS -93 /* caller's object table full. */
|
||||
#define QCOMTEE_MSG_ERROR_MAXARGS -94 /* too many args. */
|
||||
#define QCOMTEE_MSG_ERROR_MAXDATA -95 /* buffers too large. */
|
||||
#define QCOMTEE_MSG_ERROR_UNAVAIL -96 /* the request could not be processed. */
|
||||
#define QCOMTEE_MSG_ERROR_KMEM -97 /* kernel out of memory. */
|
||||
#define QCOMTEE_MSG_ERROR_REMOTE -98 /* local method sent to remote object. */
|
||||
#define QCOMTEE_MSG_ERROR_BUSY -99 /* Object is busy. */
|
||||
#define QCOMTEE_MSG_ERROR_TIMEOUT -103 /* Call Back Object invocation timed out. */
|
||||
|
||||
static inline void qcomtee_msg_set_result(struct qcomtee_msg_callback *cb_msg,
|
||||
int err)
|
||||
{
|
||||
if (!err) {
|
||||
cb_msg->result = QCOMTEE_MSG_OK;
|
||||
} else if (err < 0) {
|
||||
/* If err < 0, then it is a transport error. */
|
||||
switch (err) {
|
||||
case -ENOMEM:
|
||||
cb_msg->result = QCOMTEE_MSG_ERROR_KMEM;
|
||||
break;
|
||||
case -ENODEV:
|
||||
cb_msg->result = QCOMTEE_MSG_ERROR_DEFUNCT;
|
||||
break;
|
||||
case -ENOSPC:
|
||||
case -EBUSY:
|
||||
cb_msg->result = QCOMTEE_MSG_ERROR_BUSY;
|
||||
break;
|
||||
case -EBADF:
|
||||
case -EINVAL:
|
||||
cb_msg->result = QCOMTEE_MSG_ERROR_UNAVAIL;
|
||||
break;
|
||||
default:
|
||||
cb_msg->result = QCOMTEE_MSG_ERROR;
|
||||
}
|
||||
} else {
|
||||
/* If err > 0, then it is user defined error, pass it as is. */
|
||||
cb_msg->result = err;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* QCOMTEE_MSG_H */
|
||||
@@ -0,0 +1,316 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#ifndef QCOMTEE_OBJECT_H
|
||||
#define QCOMTEE_OBJECT_H
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
struct qcomtee_object;
|
||||
|
||||
/**
|
||||
* DOC: Overview
|
||||
*
|
||||
* qcomtee_object provides object refcounting, ID allocation for objects hosted
|
||||
* in the kernel, and necessary message marshaling for Qualcomm TEE (QTEE).
|
||||
*
|
||||
* To invoke an object in QTEE, the user calls qcomtee_object_do_invoke()
|
||||
* while passing an instance of &struct qcomtee_object and the requested
|
||||
* operation + arguments.
|
||||
*
|
||||
* After boot, QTEE provides a static object %ROOT_QCOMTEE_OBJECT (type of
|
||||
* %QCOMTEE_OBJECT_TYPE_ROOT). The root object is invoked to pass the user's
|
||||
* credentials and obtain other instances of &struct qcomtee_object (type of
|
||||
* %QCOMTEE_OBJECT_TYPE_TEE) that represent services and TAs in QTEE;
|
||||
* see &enum qcomtee_object_type.
|
||||
*
|
||||
* The objects received from QTEE are refcounted. So the owner of these objects
|
||||
* can issue qcomtee_object_get() to increase the refcount and pass objects
|
||||
* to other clients, or issue qcomtee_object_put() to decrease the refcount
|
||||
* and release the resources in QTEE.
|
||||
*
|
||||
* The kernel can host services accessible to QTEE. A driver should embed
|
||||
* an instance of &struct qcomtee_object in the struct it wants to export to
|
||||
* QTEE (this is called a callback object). It issues qcomtee_object_user_init()
|
||||
* to set the dispatch() operation for the callback object and set its type
|
||||
* to %QCOMTEE_OBJECT_TYPE_CB.
|
||||
*
|
||||
* core.c holds an object table for callback objects. An object ID is assigned
|
||||
* to each callback object, which is an index to the object table. QTEE uses
|
||||
* these IDs to reference or invoke callback objects.
|
||||
*
|
||||
* If QTEE invokes a callback object in the kernel, the dispatch() operation is
|
||||
* called in the context of the thread that originally called
|
||||
* qcomtee_object_do_invoke().
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum qcomtee_object_type - Object types.
|
||||
* @QCOMTEE_OBJECT_TYPE_TEE: object hosted on QTEE.
|
||||
* @QCOMTEE_OBJECT_TYPE_CB: object hosted on kernel.
|
||||
* @QCOMTEE_OBJECT_TYPE_ROOT: 'primordial' object.
|
||||
* @QCOMTEE_OBJECT_TYPE_NULL: NULL object.
|
||||
*
|
||||
* The primordial object is used for bootstrapping the IPC connection between
|
||||
* the kernel and QTEE. It is invoked by the kernel when it wants to get a
|
||||
* 'client env'.
|
||||
*/
|
||||
enum qcomtee_object_type {
|
||||
QCOMTEE_OBJECT_TYPE_TEE,
|
||||
QCOMTEE_OBJECT_TYPE_CB,
|
||||
QCOMTEE_OBJECT_TYPE_ROOT,
|
||||
QCOMTEE_OBJECT_TYPE_NULL,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum qcomtee_arg_type - Type of QTEE argument.
|
||||
* @QCOMTEE_ARG_TYPE_INV: invalid type.
|
||||
* @QCOMTEE_ARG_TYPE_OB: output buffer (OB).
|
||||
* @QCOMTEE_ARG_TYPE_OO: output object (OO).
|
||||
* @QCOMTEE_ARG_TYPE_IB: input buffer (IB).
|
||||
* @QCOMTEE_ARG_TYPE_IO: input object (IO).
|
||||
*
|
||||
* Use the invalid type to specify the end of the argument array.
|
||||
*/
|
||||
enum qcomtee_arg_type {
|
||||
QCOMTEE_ARG_TYPE_INV = 0,
|
||||
QCOMTEE_ARG_TYPE_OB,
|
||||
QCOMTEE_ARG_TYPE_OO,
|
||||
QCOMTEE_ARG_TYPE_IB,
|
||||
QCOMTEE_ARG_TYPE_IO,
|
||||
QCOMTEE_ARG_TYPE_NR,
|
||||
};
|
||||
|
||||
/**
|
||||
* define QCOMTEE_ARGS_PER_TYPE - Maximum arguments of a specific type.
|
||||
*
|
||||
* The QTEE transport protocol limits the maximum number of arguments of
|
||||
* a specific type (i.e., IB, OB, IO, and OO).
|
||||
*/
|
||||
#define QCOMTEE_ARGS_PER_TYPE 16
|
||||
|
||||
/* Maximum arguments that can fit in a QTEE message, ignoring the type. */
|
||||
#define QCOMTEE_ARGS_MAX (QCOMTEE_ARGS_PER_TYPE * (QCOMTEE_ARG_TYPE_NR - 1))
|
||||
|
||||
struct qcomtee_buffer {
|
||||
union {
|
||||
void *addr;
|
||||
void __user *uaddr;
|
||||
};
|
||||
size_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qcomtee_arg - Argument for QTEE object invocation.
|
||||
* @type: type of argument as &enum qcomtee_arg_type.
|
||||
* @flags: extra flags.
|
||||
* @b: address and size if the type of argument is a buffer.
|
||||
* @o: object instance if the type of argument is an object.
|
||||
*
|
||||
* &qcomtee_arg.flags only accepts %QCOMTEE_ARG_FLAGS_UADDR for now, which
|
||||
* states that &qcomtee_arg.b contains a userspace address in uaddr.
|
||||
*/
|
||||
struct qcomtee_arg {
|
||||
enum qcomtee_arg_type type;
|
||||
/* 'b.uaddr' holds a __user address. */
|
||||
#define QCOMTEE_ARG_FLAGS_UADDR BIT(0)
|
||||
unsigned int flags;
|
||||
union {
|
||||
struct qcomtee_buffer b;
|
||||
struct qcomtee_object *o;
|
||||
};
|
||||
};
|
||||
|
||||
static inline int qcomtee_args_len(struct qcomtee_arg *args)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (args[i].type != QCOMTEE_ARG_TYPE_INV)
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Context is busy (callback is in progress). */
|
||||
#define QCOMTEE_OIC_FLAG_BUSY BIT(1)
|
||||
/* Context needs to notify the current object. */
|
||||
#define QCOMTEE_OIC_FLAG_NOTIFY BIT(2)
|
||||
/* Context has shared state with QTEE. */
|
||||
#define QCOMTEE_OIC_FLAG_SHARED BIT(3)
|
||||
|
||||
/**
|
||||
* struct qcomtee_object_invoke_ctx - QTEE context for object invocation.
|
||||
* @ctx: TEE context for this invocation.
|
||||
* @flags: flags for the invocation context.
|
||||
* @errno: error code for the invocation.
|
||||
* @object: current object invoked in this callback context.
|
||||
* @u: array of arguments for the current invocation (+1 for ending arg).
|
||||
* @in_msg: inbound buffer shared with QTEE.
|
||||
* @out_msg: outbound buffer shared with QTEE.
|
||||
* @in_shm: TEE shm allocated for inbound buffer.
|
||||
* @out_shm: TEE shm allocated for outbound buffer.
|
||||
* @data: extra data attached to this context.
|
||||
*/
|
||||
struct qcomtee_object_invoke_ctx {
|
||||
struct tee_context *ctx;
|
||||
unsigned long flags;
|
||||
int errno;
|
||||
|
||||
struct qcomtee_object *object;
|
||||
struct qcomtee_arg u[QCOMTEE_ARGS_MAX + 1];
|
||||
|
||||
struct qcomtee_buffer in_msg;
|
||||
struct qcomtee_buffer out_msg;
|
||||
struct tee_shm *in_shm;
|
||||
struct tee_shm *out_shm;
|
||||
|
||||
void *data;
|
||||
};
|
||||
|
||||
static inline struct qcomtee_object_invoke_ctx *
|
||||
qcomtee_object_invoke_ctx_alloc(struct tee_context *ctx)
|
||||
{
|
||||
struct qcomtee_object_invoke_ctx *oic;
|
||||
|
||||
oic = kzalloc(sizeof(*oic), GFP_KERNEL);
|
||||
if (oic)
|
||||
oic->ctx = ctx;
|
||||
return oic;
|
||||
}
|
||||
|
||||
/**
|
||||
* qcomtee_object_do_invoke() - Submit an invocation for an object.
|
||||
* @oic: context to use for the current invocation.
|
||||
* @object: object being invoked.
|
||||
* @op: requested operation on the object.
|
||||
* @u: array of arguments for the current invocation.
|
||||
* @result: result returned from QTEE.
|
||||
*
|
||||
* The caller is responsible for keeping track of the refcount for each object,
|
||||
* including @object. On return, the caller loses ownership of all input
|
||||
* objects of type %QCOMTEE_OBJECT_TYPE_CB.
|
||||
*
|
||||
* @object can be of %QCOMTEE_OBJECT_TYPE_ROOT or %QCOMTEE_OBJECT_TYPE_TEE.
|
||||
*
|
||||
* Return: On success, returns 0; on failure, returns < 0.
|
||||
*/
|
||||
int qcomtee_object_do_invoke(struct qcomtee_object_invoke_ctx *oic,
|
||||
struct qcomtee_object *object, u32 op,
|
||||
struct qcomtee_arg *u, int *result);
|
||||
|
||||
/**
|
||||
* struct qcomtee_object_operations - Callback object operations.
|
||||
* @release: release the object if QTEE is not using it.
|
||||
* @dispatch: dispatch the operation requested by QTEE.
|
||||
* @notify: report the status of any pending response submitted by @dispatch.
|
||||
*/
|
||||
struct qcomtee_object_operations {
|
||||
void (*release)(struct qcomtee_object *object);
|
||||
int (*dispatch)(struct qcomtee_object_invoke_ctx *oic,
|
||||
struct qcomtee_object *object, u32 op,
|
||||
struct qcomtee_arg *args);
|
||||
void (*notify)(struct qcomtee_object_invoke_ctx *oic,
|
||||
struct qcomtee_object *object, int err);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct qcomtee_object - QTEE or kernel object.
|
||||
* @name: object name.
|
||||
* @refcount: reference counter.
|
||||
* @object_type: object type as &enum qcomtee_object_type.
|
||||
* @info: extra information for the object.
|
||||
* @ops: callback operations for objects of type %QCOMTEE_OBJECT_TYPE_CB.
|
||||
* @work: work for async operations on the object.
|
||||
*
|
||||
* @work is used for releasing objects of %QCOMTEE_OBJECT_TYPE_TEE type.
|
||||
*/
|
||||
struct qcomtee_object {
|
||||
const char *name;
|
||||
struct kref refcount;
|
||||
|
||||
enum qcomtee_object_type object_type;
|
||||
struct object_info {
|
||||
unsigned long qtee_id;
|
||||
/* TEE context for QTEE object async requests. */
|
||||
struct tee_context *qcomtee_async_ctx;
|
||||
} info;
|
||||
|
||||
struct qcomtee_object_operations *ops;
|
||||
struct work_struct work;
|
||||
};
|
||||
|
||||
/* Static instances of qcomtee_object objects. */
|
||||
#define NULL_QCOMTEE_OBJECT ((struct qcomtee_object *)(0))
|
||||
extern struct qcomtee_object qcomtee_object_root;
|
||||
#define ROOT_QCOMTEE_OBJECT (&qcomtee_object_root)
|
||||
|
||||
static inline enum qcomtee_object_type
|
||||
typeof_qcomtee_object(struct qcomtee_object *object)
|
||||
{
|
||||
if (object == NULL_QCOMTEE_OBJECT)
|
||||
return QCOMTEE_OBJECT_TYPE_NULL;
|
||||
return object->object_type;
|
||||
}
|
||||
|
||||
static inline const char *qcomtee_object_name(struct qcomtee_object *object)
|
||||
{
|
||||
if (object == NULL_QCOMTEE_OBJECT)
|
||||
return "null";
|
||||
|
||||
if (!object->name)
|
||||
return "no-name";
|
||||
return object->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* qcomtee_object_user_init() - Initialize an object for the user.
|
||||
* @object: object to initialize.
|
||||
* @ot: type of object as &enum qcomtee_object_type.
|
||||
* @ops: instance of callbacks.
|
||||
* @fmt: name assigned to the object.
|
||||
*
|
||||
* Return: On success, returns 0; on failure, returns < 0.
|
||||
*/
|
||||
int qcomtee_object_user_init(struct qcomtee_object *object,
|
||||
enum qcomtee_object_type ot,
|
||||
struct qcomtee_object_operations *ops,
|
||||
const char *fmt, ...) __printf(4, 5);
|
||||
|
||||
/* Object release is RCU protected. */
|
||||
int qcomtee_object_get(struct qcomtee_object *object);
|
||||
void qcomtee_object_put(struct qcomtee_object *object);
|
||||
|
||||
#define qcomtee_arg_for_each(i, args) \
|
||||
for (i = 0; args[i].type != QCOMTEE_ARG_TYPE_INV; i++)
|
||||
|
||||
/* Next argument of type @type after index @i. */
|
||||
int qcomtee_next_arg_type(struct qcomtee_arg *u, int i,
|
||||
enum qcomtee_arg_type type);
|
||||
|
||||
/* Iterate over argument of given type. */
|
||||
#define qcomtee_arg_for_each_type(i, args, at) \
|
||||
for (i = qcomtee_next_arg_type(args, 0, at); \
|
||||
args[i].type != QCOMTEE_ARG_TYPE_INV; \
|
||||
i = qcomtee_next_arg_type(args, i + 1, at))
|
||||
|
||||
#define qcomtee_arg_for_each_input_buffer(i, args) \
|
||||
qcomtee_arg_for_each_type(i, args, QCOMTEE_ARG_TYPE_IB)
|
||||
#define qcomtee_arg_for_each_output_buffer(i, args) \
|
||||
qcomtee_arg_for_each_type(i, args, QCOMTEE_ARG_TYPE_OB)
|
||||
#define qcomtee_arg_for_each_input_object(i, args) \
|
||||
qcomtee_arg_for_each_type(i, args, QCOMTEE_ARG_TYPE_IO)
|
||||
#define qcomtee_arg_for_each_output_object(i, args) \
|
||||
qcomtee_arg_for_each_type(i, args, QCOMTEE_ARG_TYPE_OO)
|
||||
|
||||
struct qcomtee_object *
|
||||
qcomtee_object_get_client_env(struct qcomtee_object_invoke_ctx *oic);
|
||||
|
||||
struct qcomtee_object *
|
||||
qcomtee_object_get_service(struct qcomtee_object_invoke_ctx *oic,
|
||||
struct qcomtee_object *client_env, u32 uid);
|
||||
|
||||
#endif /* QCOMTEE_OBJECT_H */
|
||||
@@ -0,0 +1,153 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/firmware/qcom/qcom_tzmem.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include "qcomtee.h"
|
||||
|
||||
/**
|
||||
* define MAX_OUTBOUND_BUFFER_SIZE - Maximum size of outbound buffers.
|
||||
*
|
||||
* The size of outbound buffer depends on QTEE callback requests.
|
||||
*/
|
||||
#define MAX_OUTBOUND_BUFFER_SIZE SZ_4K
|
||||
|
||||
/**
|
||||
* define MAX_INBOUND_BUFFER_SIZE - Maximum size of the inbound buffer.
|
||||
*
|
||||
* The size of the inbound buffer depends on the user's requests,
|
||||
* specifically the number of IB and OB arguments. If an invocation
|
||||
* requires a size larger than %MAX_INBOUND_BUFFER_SIZE, the user should
|
||||
* consider using another form of shared memory with QTEE.
|
||||
*/
|
||||
#define MAX_INBOUND_BUFFER_SIZE SZ_4M
|
||||
|
||||
/**
|
||||
* qcomtee_msg_buffers_alloc() - Allocate inbound and outbound buffers.
|
||||
* @oic: context to use for the current invocation.
|
||||
* @u: array of arguments for the current invocation.
|
||||
*
|
||||
* It calculates the size of inbound and outbound buffers based on the
|
||||
* arguments in @u. It allocates the buffers from the teedev pool.
|
||||
*
|
||||
* Return: On success, returns 0. On error, returns < 0.
|
||||
*/
|
||||
int qcomtee_msg_buffers_alloc(struct qcomtee_object_invoke_ctx *oic,
|
||||
struct qcomtee_arg *u)
|
||||
{
|
||||
struct tee_context *ctx = oic->ctx;
|
||||
struct tee_shm *shm;
|
||||
size_t size;
|
||||
int i;
|
||||
|
||||
/* Start offset in a message for buffer arguments. */
|
||||
size = qcomtee_msg_buffer_args(struct qcomtee_msg_object_invoke,
|
||||
qcomtee_args_len(u));
|
||||
if (size > MAX_INBOUND_BUFFER_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
/* Add size of IB arguments. */
|
||||
qcomtee_arg_for_each_input_buffer(i, u) {
|
||||
size = size_add(size, qcomtee_msg_offset_align(u[i].b.size));
|
||||
if (size > MAX_INBOUND_BUFFER_SIZE)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Add size of OB arguments. */
|
||||
qcomtee_arg_for_each_output_buffer(i, u) {
|
||||
size = size_add(size, qcomtee_msg_offset_align(u[i].b.size));
|
||||
if (size > MAX_INBOUND_BUFFER_SIZE)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
shm = tee_shm_alloc_priv_buf(ctx, size);
|
||||
if (IS_ERR(shm))
|
||||
return PTR_ERR(shm);
|
||||
|
||||
/* Allocate inbound buffer. */
|
||||
oic->in_shm = shm;
|
||||
shm = tee_shm_alloc_priv_buf(ctx, MAX_OUTBOUND_BUFFER_SIZE);
|
||||
if (IS_ERR(shm)) {
|
||||
tee_shm_free(oic->in_shm);
|
||||
|
||||
return PTR_ERR(shm);
|
||||
}
|
||||
/* Allocate outbound buffer. */
|
||||
oic->out_shm = shm;
|
||||
|
||||
oic->in_msg.addr = tee_shm_get_va(oic->in_shm, 0);
|
||||
oic->in_msg.size = tee_shm_get_size(oic->in_shm);
|
||||
oic->out_msg.addr = tee_shm_get_va(oic->out_shm, 0);
|
||||
oic->out_msg.size = tee_shm_get_size(oic->out_shm);
|
||||
/* QTEE assume unused buffers are zeroed. */
|
||||
memzero_explicit(oic->in_msg.addr, oic->in_msg.size);
|
||||
memzero_explicit(oic->out_msg.addr, oic->out_msg.size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qcomtee_msg_buffers_free(struct qcomtee_object_invoke_ctx *oic)
|
||||
{
|
||||
tee_shm_free(oic->in_shm);
|
||||
tee_shm_free(oic->out_shm);
|
||||
}
|
||||
|
||||
/* Dynamic shared memory pool based on tee_dyn_shm_alloc_helper(). */
|
||||
|
||||
static int qcomtee_shm_register(struct tee_context *ctx, struct tee_shm *shm,
|
||||
struct page **pages, size_t num_pages,
|
||||
unsigned long start)
|
||||
{
|
||||
return qcom_tzmem_shm_bridge_create(shm->paddr, shm->size,
|
||||
&shm->sec_world_id);
|
||||
}
|
||||
|
||||
static int qcomtee_shm_unregister(struct tee_context *ctx, struct tee_shm *shm)
|
||||
{
|
||||
qcom_tzmem_shm_bridge_delete(shm->sec_world_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pool_op_alloc(struct tee_shm_pool *pool, struct tee_shm *shm,
|
||||
size_t size, size_t align)
|
||||
{
|
||||
if (!(shm->flags & TEE_SHM_PRIV))
|
||||
return -ENOMEM;
|
||||
|
||||
return tee_dyn_shm_alloc_helper(shm, size, align, qcomtee_shm_register);
|
||||
}
|
||||
|
||||
static void pool_op_free(struct tee_shm_pool *pool, struct tee_shm *shm)
|
||||
{
|
||||
tee_dyn_shm_free_helper(shm, qcomtee_shm_unregister);
|
||||
}
|
||||
|
||||
static void pool_op_destroy_pool(struct tee_shm_pool *pool)
|
||||
{
|
||||
kfree(pool);
|
||||
}
|
||||
|
||||
static const struct tee_shm_pool_ops pool_ops = {
|
||||
.alloc = pool_op_alloc,
|
||||
.free = pool_op_free,
|
||||
.destroy_pool = pool_op_destroy_pool,
|
||||
};
|
||||
|
||||
struct tee_shm_pool *qcomtee_shm_pool_alloc(void)
|
||||
{
|
||||
struct tee_shm_pool *pool;
|
||||
|
||||
pool = kzalloc(sizeof(*pool), GFP_KERNEL);
|
||||
if (!pool)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pool->ops = &pool_ops;
|
||||
|
||||
return pool;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -59,6 +59,7 @@
|
||||
#define TEE_IMPL_ID_OPTEE 1
|
||||
#define TEE_IMPL_ID_AMDTEE 2
|
||||
#define TEE_IMPL_ID_TSTEE 3
|
||||
#define TEE_IMPL_ID_QTEE 4
|
||||
|
||||
/*
|
||||
* OP-TEE specific capabilities
|
||||
|
||||
Reference in New Issue
Block a user