File Index
Files and directories
Sign in
FILE

async.c

File preview with syntax highlighting.

linux-6.19.14/drivers/tee/qcomtee/async.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
  4 */
  5
  6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  7
  8#include "qcomtee.h"
  9
 10#define QCOMTEE_ASYNC_VERSION_1_0 0x00010000U /* Maj: 0x0001, Min: 0x0000. */
 11#define QCOMTEE_ASYNC_VERSION_1_1 0x00010001U /* Maj: 0x0001, Min: 0x0001. */
 12#define QCOMTEE_ASYNC_VERSION_1_2 0x00010002U /* Maj: 0x0001, Min: 0x0002. */
 13#define QCOMTEE_ASYNC_VERSION_CURRENT QCOMTEE_ASYNC_VERSION_1_2
 14
 15#define QCOMTEE_ASYNC_VERSION_MAJOR(n) upper_16_bits(n)
 16#define QCOMTEE_ASYNC_VERSION_MINOR(n) lower_16_bits(n)
 17
 18#define QCOMTEE_ASYNC_VERSION_CURRENT_MAJOR \
 19	QCOMTEE_ASYNC_VERSION_MAJOR(QCOMTEE_ASYNC_VERSION_CURRENT)
 20#define QCOMTEE_ASYNC_VERSION_CURRENT_MINOR \
 21	QCOMTEE_ASYNC_VERSION_MINOR(QCOMTEE_ASYNC_VERSION_CURRENT)
 22
 23/**
 24 * struct qcomtee_async_msg_hdr - Asynchronous message header format.
 25 * @version: current async protocol version of the remote endpoint.
 26 * @op: async operation.
 27 *
 28 * @version specifies the endpoint's (QTEE or driver) supported async protocol.
 29 * For example, if QTEE sets @version to %QCOMTEE_ASYNC_VERSION_1_1, QTEE
 30 * handles operations supported in %QCOMTEE_ASYNC_VERSION_1_1 or
 31 * %QCOMTEE_ASYNC_VERSION_1_0. @op determines the message format.
 32 */
 33struct qcomtee_async_msg_hdr {
 34	u32 version;
 35	u32 op;
 36};
 37
 38/* Size of an empty async message. */
 39#define QCOMTEE_ASYNC_MSG_ZERO sizeof(struct qcomtee_async_msg_hdr)
 40
 41/**
 42 * struct qcomtee_async_release_msg - Release asynchronous message.
 43 * @hdr: message header as &struct qcomtee_async_msg_hdr.
 44 * @counts: number of objects in @object_ids.
 45 * @object_ids: array of object IDs that should be released.
 46 *
 47 * Available in Maj = 0x0001, Min >= 0x0000.
 48 */
 49struct qcomtee_async_release_msg {
 50	struct qcomtee_async_msg_hdr hdr;
 51	u32 counts;
 52	u32 object_ids[] __counted_by(counts);
 53};
 54
 55/**
 56 * qcomtee_get_async_buffer() - Get the start of the asynchronous message.
 57 * @oic: context used for the current invocation.
 58 * @async_buffer: return buffer to extract from or fill in async messages.
 59 *
 60 * If @oic is used for direct object invocation, the whole outbound buffer
 61 * is available for the async message. If @oic is used for a callback request,
 62 * the tail of the outbound buffer (after the callback request message) is
 63 * available for the async message.
 64 *
 65 * The start of the async buffer is aligned, see qcomtee_msg_offset_align().
 66 */
 67static void qcomtee_get_async_buffer(struct qcomtee_object_invoke_ctx *oic,
 68				     struct qcomtee_buffer *async_buffer)
 69{
 70	struct qcomtee_msg_callback *msg;
 71	unsigned int offset;
 72	int i;
 73
 74	if (!(oic->flags & QCOMTEE_OIC_FLAG_BUSY)) {
 75		/* The outbound buffer is empty. Using the whole buffer. */
 76		offset = 0;
 77	} else {
 78		msg = (struct qcomtee_msg_callback *)oic->out_msg.addr;
 79
 80		/* Start offset in a message for buffer arguments. */
 81		offset = qcomtee_msg_buffer_args(struct qcomtee_msg_callback,
 82						 qcomtee_msg_args(msg));
 83
 84		/* Add size of IB arguments. */
 85		qcomtee_msg_for_each_input_buffer(i, msg)
 86			offset += qcomtee_msg_offset_align(msg->args[i].b.size);
 87
 88		/* Add size of OB arguments. */
 89		qcomtee_msg_for_each_output_buffer(i, msg)
 90			offset += qcomtee_msg_offset_align(msg->args[i].b.size);
 91	}
 92
 93	async_buffer->addr = oic->out_msg.addr + offset;
 94	async_buffer->size = oic->out_msg.size - offset;
 95}
 96
 97/**
 98 * async_release() - Process QTEE async release requests.
 99 * @oic: context used for the current invocation.
100 * @msg: async message for object release.
101 * @size: size of the async buffer available.
102 *
103 * Return: Size of the outbound buffer used when processing @msg.
104 */
105static size_t async_release(struct qcomtee_object_invoke_ctx *oic,
106			    struct qcomtee_async_msg_hdr *async_msg,
107			    size_t size)
108{
109	struct qcomtee_async_release_msg *msg;
110	struct qcomtee_object *object;
111	int i;
112
113	msg = (struct qcomtee_async_release_msg *)async_msg;
114
115	for (i = 0; i < msg->counts; i++) {
116		object = qcomtee_idx_erase(oic, msg->object_ids[i]);
117		qcomtee_object_put(object);
118	}
119
120	return struct_size(msg, object_ids, msg->counts);
121}
122
123/**
124 * qcomtee_fetch_async_reqs() - Fetch and process asynchronous messages.
125 * @oic: context used for the current invocation.
126 *
127 * Calls handlers to process the requested operations in the async message.
128 * Currently, only supports async release requests.
129 */
130void qcomtee_fetch_async_reqs(struct qcomtee_object_invoke_ctx *oic)
131{
132	struct qcomtee_async_msg_hdr *async_msg;
133	struct qcomtee_buffer async_buffer;
134	size_t consumed, used = 0;
135	u16 major_ver;
136
137	qcomtee_get_async_buffer(oic, &async_buffer);
138
139	while (async_buffer.size - used > QCOMTEE_ASYNC_MSG_ZERO) {
140		async_msg = (struct qcomtee_async_msg_hdr *)(async_buffer.addr +
141							     used);
142		/*
143		 * QTEE assumes that the unused space of the async buffer is
144		 * zeroed; so if version is zero, the buffer is unused.
145		 */
146		if (async_msg->version == 0)
147			goto out;
148
149		major_ver = QCOMTEE_ASYNC_VERSION_MAJOR(async_msg->version);
150		/* Major version mismatch is a compatibility break. */
151		if (major_ver != QCOMTEE_ASYNC_VERSION_CURRENT_MAJOR) {
152			pr_err("Async message version mismatch (%u != %u)\n",
153			       major_ver, QCOMTEE_ASYNC_VERSION_CURRENT_MAJOR);
154
155			goto out;
156		}
157
158		switch (async_msg->op) {
159		case QCOMTEE_MSG_OBJECT_OP_RELEASE:
160			consumed = async_release(oic, async_msg,
161						 async_buffer.size - used);
162			break;
163		default:
164			pr_err("Unsupported async message %u\n", async_msg->op);
165			goto out;
166		}
167
168		/* Supported operation but unable to parse the message. */
169		if (!consumed) {
170			pr_err("Unable to parse async message for op %u\n",
171			       async_msg->op);
172			goto out;
173		}
174
175		/* Next async message. */
176		used += qcomtee_msg_offset_align(consumed);
177	}
178
179out:
180	/* Reset the async buffer so async requests do not loop to QTEE. */
181	memzero_explicit(async_buffer.addr, async_buffer.size);
182}
~/ Read-only file preview.