#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include "qcomtee.h"
#define QCOMTEE_ASYNC_VERSION_1_0 0x00010000U
#define QCOMTEE_ASYNC_VERSION_1_1 0x00010001U
#define QCOMTEE_ASYNC_VERSION_1_2 0x00010002U
#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 {
u32 version;
u32 op;
};
#define QCOMTEE_ASYNC_MSG_ZERO sizeof(struct qcomtee_async_msg_hdr)
struct qcomtee_async_release_msg {
struct qcomtee_async_msg_hdr hdr;
u32 counts;
u32 object_ids[] __counted_by(counts);
};
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)) {
offset = 0;
} else {
msg = (struct qcomtee_msg_callback *)oic->out_msg.addr;
offset = qcomtee_msg_buffer_args(struct qcomtee_msg_callback,
qcomtee_msg_args(msg));
qcomtee_msg_for_each_input_buffer(i, msg)
offset += qcomtee_msg_offset_align(msg->args[i].b.size);
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;
}
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);
}
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);
if (async_msg->version == 0)
goto out;
major_ver = QCOMTEE_ASYNC_VERSION_MAJOR(async_msg->version);
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;
}
if (!consumed) {
pr_err("Unable to parse async message for op %u\n",
async_msg->op);
goto out;
}
used += qcomtee_msg_offset_align(consumed);
}
out:
memzero_explicit(async_buffer.addr, async_buffer.size);
}