AMD-TEE reference count loaded TAs

-----BEGIN PGP SIGNATURE-----
 
 iQJOBAABCgA4FiEEFV+gSSXZJY9ZyuB5LinzTIcAHJcFAmCSeuwaHGplbnMud2lr
 bGFuZGVyQGxpbmFyby5vcmcACgkQLinzTIcAHJe/rA//QN3OBBD0K2kx8gBD2Lxb
 4oaJEjgJAJPoT8qGLPVZcYDXUkNIjx78fz+IPNVtJamaw9c6jDMXe/wB21QFmruy
 ZcOP0+cfk0ytCcsHAeY9CICjWA7c73fq89VOmT8upv54m1dGSV8Qat5rarJTNJ4T
 7WNybzsUeCOHbxJky4BtnXV/l/9w0gpwrlB47fChGPCvadGeP3LsKkcNIsNWdNQa
 VrYNqXCL2cQIELExeH0ZqaIlQpXFwiJdTseBBL69DwKw/QZuxH2U+Qr1vAUuPKL8
 EzGQnHYcmuzmDsITUAnSnzo8zc9A9yRcR6CTM+wK8Q+n8L8dIWzSjEiQZCisEWzX
 DURJK2oHLhTEovpEhHUEDOmQk892IHIDGAMr5hwXMaALmA+ruGyObMCtAxnFBItw
 hL9FkXcWpXXS0pJZXs60lwBtebC823nVhvZtjA5ek2RSJM8YiQLVP8acDZ/zbt/Q
 AG9ZLuTO2tYUS4qWRW8V7j+gA+CveKbVZH3/RuCBtk1BxupTZ/8EjaQwN5wBkJgP
 ohHog59ZNydCkaJkN9vM/DenG+OAQz6wN6GYGbaeXMV873z/6WSa/pc/WE1dLF/B
 Dpnyafefi9luN1O7vZrbrX+/4CHkeirOYS1kSCxz+PF0RCAXIuWuj6NWJPmyUAnT
 mVOY0V9naDFVYboE5HFdwww=
 =aCPL
 -----END PGP SIGNATURE-----

Merge tag 'amdtee-fixes-for-v5.13' of git://git.linaro.org/people/jens.wiklander/linux-tee into arm/fixes

AMD-TEE reference count loaded TAs

* tag 'amdtee-fixes-for-v5.13' of git://git.linaro.org/people/jens.wiklander/linux-tee:
  tee: amdtee: unload TA only when its refcount becomes 0

Link: https://lore.kernel.org/r/20210505110850.GA3434209@jade
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Arnd Bergmann 2021-05-17 16:06:01 +02:00
commit 8ec51f894b
3 changed files with 106 additions and 16 deletions

View File

@ -21,6 +21,7 @@
#define TEEC_SUCCESS 0x00000000
#define TEEC_ERROR_GENERIC 0xFFFF0000
#define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006
#define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C
#define TEEC_ERROR_COMMUNICATION 0xFFFF000E
#define TEEC_ORIGIN_COMMS 0x00000002
@ -93,6 +94,18 @@ struct amdtee_shm_data {
u32 buf_id;
};
/**
* struct amdtee_ta_data - Keeps track of all TAs loaded in AMD Secure
* Processor
* @ta_handle: Handle to TA loaded in TEE
* @refcount: Reference count for the loaded TA
*/
struct amdtee_ta_data {
struct list_head list_node;
u32 ta_handle;
u32 refcount;
};
#define LOWER_TWO_BYTE_MASK 0x0000FFFF
/**

View File

@ -121,15 +121,69 @@ static int amd_params_to_tee_params(struct tee_param *tee, u32 count,
return ret;
}
static DEFINE_MUTEX(ta_refcount_mutex);
static struct list_head ta_list = LIST_HEAD_INIT(ta_list);
static u32 get_ta_refcount(u32 ta_handle)
{
struct amdtee_ta_data *ta_data;
u32 count = 0;
/* Caller must hold a mutex */
list_for_each_entry(ta_data, &ta_list, list_node)
if (ta_data->ta_handle == ta_handle)
return ++ta_data->refcount;
ta_data = kzalloc(sizeof(*ta_data), GFP_KERNEL);
if (ta_data) {
ta_data->ta_handle = ta_handle;
ta_data->refcount = 1;
count = ta_data->refcount;
list_add(&ta_data->list_node, &ta_list);
}
return count;
}
static u32 put_ta_refcount(u32 ta_handle)
{
struct amdtee_ta_data *ta_data;
u32 count = 0;
/* Caller must hold a mutex */
list_for_each_entry(ta_data, &ta_list, list_node)
if (ta_data->ta_handle == ta_handle) {
count = --ta_data->refcount;
if (count == 0) {
list_del(&ta_data->list_node);
kfree(ta_data);
break;
}
}
return count;
}
int handle_unload_ta(u32 ta_handle)
{
struct tee_cmd_unload_ta cmd = {0};
u32 status;
u32 status, count;
int ret;
if (!ta_handle)
return -EINVAL;
mutex_lock(&ta_refcount_mutex);
count = put_ta_refcount(ta_handle);
if (count) {
pr_debug("unload ta: not unloading %u count %u\n",
ta_handle, count);
ret = -EBUSY;
goto unlock;
}
cmd.ta_handle = ta_handle;
ret = psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA, (void *)&cmd,
@ -137,8 +191,12 @@ int handle_unload_ta(u32 ta_handle)
if (!ret && status != 0) {
pr_err("unload ta: status = 0x%x\n", status);
ret = -EBUSY;
} else {
pr_debug("unloaded ta handle %u\n", ta_handle);
}
unlock:
mutex_unlock(&ta_refcount_mutex);
return ret;
}
@ -340,7 +398,8 @@ int handle_open_session(struct tee_ioctl_open_session_arg *arg, u32 *info,
int handle_load_ta(void *data, u32 size, struct tee_ioctl_open_session_arg *arg)
{
struct tee_cmd_load_ta cmd = {0};
struct tee_cmd_unload_ta unload_cmd = {};
struct tee_cmd_load_ta load_cmd = {};
phys_addr_t blob;
int ret;
@ -353,21 +412,36 @@ int handle_load_ta(void *data, u32 size, struct tee_ioctl_open_session_arg *arg)
return -EINVAL;
}
cmd.hi_addr = upper_32_bits(blob);
cmd.low_addr = lower_32_bits(blob);
cmd.size = size;
load_cmd.hi_addr = upper_32_bits(blob);
load_cmd.low_addr = lower_32_bits(blob);
load_cmd.size = size;
ret = psp_tee_process_cmd(TEE_CMD_ID_LOAD_TA, (void *)&cmd,
sizeof(cmd), &arg->ret);
mutex_lock(&ta_refcount_mutex);
ret = psp_tee_process_cmd(TEE_CMD_ID_LOAD_TA, (void *)&load_cmd,
sizeof(load_cmd), &arg->ret);
if (ret) {
arg->ret_origin = TEEC_ORIGIN_COMMS;
arg->ret = TEEC_ERROR_COMMUNICATION;
} else {
set_session_id(cmd.ta_handle, 0, &arg->session);
} else if (arg->ret == TEEC_SUCCESS) {
ret = get_ta_refcount(load_cmd.ta_handle);
if (!ret) {
arg->ret_origin = TEEC_ORIGIN_COMMS;
arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
/* Unload the TA on error */
unload_cmd.ta_handle = load_cmd.ta_handle;
psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA,
(void *)&unload_cmd,
sizeof(unload_cmd), &ret);
} else {
set_session_id(load_cmd.ta_handle, 0, &arg->session);
}
}
mutex_unlock(&ta_refcount_mutex);
pr_debug("load TA: TA handle = 0x%x, RO = 0x%x, ret = 0x%x\n",
cmd.ta_handle, arg->ret_origin, arg->ret);
load_cmd.ta_handle, arg->ret_origin, arg->ret);
return 0;
}

View File

@ -59,10 +59,9 @@ static void release_session(struct amdtee_session *sess)
continue;
handle_close_session(sess->ta_handle, sess->session_info[i]);
handle_unload_ta(sess->ta_handle);
}
/* Unload Trusted Application once all sessions are closed */
handle_unload_ta(sess->ta_handle);
kfree(sess);
}
@ -224,8 +223,6 @@ static void destroy_session(struct kref *ref)
struct amdtee_session *sess = container_of(ref, struct amdtee_session,
refcount);
/* Unload the TA from TEE */
handle_unload_ta(sess->ta_handle);
mutex_lock(&session_list_mutex);
list_del(&sess->list_node);
mutex_unlock(&session_list_mutex);
@ -238,7 +235,7 @@ int amdtee_open_session(struct tee_context *ctx,
{
struct amdtee_context_data *ctxdata = ctx->data;
struct amdtee_session *sess = NULL;
u32 session_info;
u32 session_info, ta_handle;
size_t ta_size;
int rc, i;
void *ta;
@ -259,11 +256,14 @@ int amdtee_open_session(struct tee_context *ctx,
if (arg->ret != TEEC_SUCCESS)
goto out;
ta_handle = get_ta_handle(arg->session);
mutex_lock(&session_list_mutex);
sess = alloc_session(ctxdata, arg->session);
mutex_unlock(&session_list_mutex);
if (!sess) {
handle_unload_ta(ta_handle);
rc = -ENOMEM;
goto out;
}
@ -277,6 +277,7 @@ int amdtee_open_session(struct tee_context *ctx,
if (i >= TEE_NUM_SESSIONS) {
pr_err("reached maximum session count %d\n", TEE_NUM_SESSIONS);
handle_unload_ta(ta_handle);
kref_put(&sess->refcount, destroy_session);
rc = -ENOMEM;
goto out;
@ -289,12 +290,13 @@ int amdtee_open_session(struct tee_context *ctx,
spin_lock(&sess->lock);
clear_bit(i, sess->sess_mask);
spin_unlock(&sess->lock);
handle_unload_ta(ta_handle);
kref_put(&sess->refcount, destroy_session);
goto out;
}
sess->session_info[i] = session_info;
set_session_id(sess->ta_handle, i, &arg->session);
set_session_id(ta_handle, i, &arg->session);
out:
free_pages((u64)ta, get_order(ta_size));
return rc;
@ -329,6 +331,7 @@ int amdtee_close_session(struct tee_context *ctx, u32 session)
/* Close the session */
handle_close_session(ta_handle, session_info);
handle_unload_ta(ta_handle);
kref_put(&sess->refcount, destroy_session);