mirror of
https://github.com/armbian/linux-cix.git
synced 2026-01-06 12:30:45 -08:00
tee: add AMD-TEE driver
Adds AMD-TEE driver. * targets AMD APUs which has AMD Secure Processor with software-based Trusted Execution Environment (TEE) support * registers with TEE subsystem * defines tee_driver_ops function callbacks * kernel allocated memory is used as shared memory between normal world and secure world. * acts as REE (Rich Execution Environment) communication agent, which uses the services of AMD Secure Processor driver to submit commands for processing in TEE environment Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Tom Lendacky <thomas.lendacky@amd.com> Acked-by: Jens Wiklander <jens.wiklander@linaro.org> Co-developed-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com> Signed-off-by: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com> Signed-off-by: Rijo Thomas <Rijo-john.Thomas@amd.com> Reviewed-by: Gary R Hook <gary.hook@amd.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
@@ -14,7 +14,7 @@ if TEE
|
||||
menu "TEE drivers"
|
||||
|
||||
source "drivers/tee/optee/Kconfig"
|
||||
|
||||
source "drivers/tee/amdtee/Kconfig"
|
||||
endmenu
|
||||
|
||||
endif
|
||||
|
||||
@@ -4,3 +4,4 @@ tee-objs += tee_core.o
|
||||
tee-objs += tee_shm.o
|
||||
tee-objs += tee_shm_pool.o
|
||||
obj-$(CONFIG_OPTEE) += optee/
|
||||
obj-$(CONFIG_AMDTEE) += amdtee/
|
||||
|
||||
8
drivers/tee/amdtee/Kconfig
Normal file
8
drivers/tee/amdtee/Kconfig
Normal file
@@ -0,0 +1,8 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
# AMD-TEE Trusted Execution Environment Configuration
|
||||
config AMDTEE
|
||||
tristate "AMD-TEE"
|
||||
default m
|
||||
depends on CRYPTO_DEV_SP_PSP
|
||||
help
|
||||
This implements AMD's Trusted Execution Environment (TEE) driver.
|
||||
5
drivers/tee/amdtee/Makefile
Normal file
5
drivers/tee/amdtee/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
obj-$(CONFIG_AMDTEE) += amdtee.o
|
||||
amdtee-objs += core.o
|
||||
amdtee-objs += call.o
|
||||
amdtee-objs += shm_pool.o
|
||||
183
drivers/tee/amdtee/amdtee_if.h
Normal file
183
drivers/tee/amdtee/amdtee_if.h
Normal file
@@ -0,0 +1,183 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
/*
|
||||
* Copyright 2019 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file has definitions related to Host and AMD-TEE Trusted OS interface.
|
||||
* These definitions must match the definitions on the TEE side.
|
||||
*/
|
||||
|
||||
#ifndef AMDTEE_IF_H
|
||||
#define AMDTEE_IF_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*****************************************************************************
|
||||
** TEE Param
|
||||
******************************************************************************/
|
||||
#define TEE_MAX_PARAMS 4
|
||||
|
||||
/**
|
||||
* struct memref - memory reference structure
|
||||
* @buf_id: buffer ID of the buffer mapped by TEE_CMD_ID_MAP_SHARED_MEM
|
||||
* @offset: offset in bytes from beginning of the buffer
|
||||
* @size: data size in bytes
|
||||
*/
|
||||
struct memref {
|
||||
u32 buf_id;
|
||||
u32 offset;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
struct value {
|
||||
u32 a;
|
||||
u32 b;
|
||||
};
|
||||
|
||||
/*
|
||||
* Parameters passed to open_session or invoke_command
|
||||
*/
|
||||
union tee_op_param {
|
||||
struct memref mref;
|
||||
struct value val;
|
||||
};
|
||||
|
||||
struct tee_operation {
|
||||
u32 param_types;
|
||||
union tee_op_param params[TEE_MAX_PARAMS];
|
||||
};
|
||||
|
||||
/* Must be same as in GP TEE specification */
|
||||
#define TEE_OP_PARAM_TYPE_NONE 0
|
||||
#define TEE_OP_PARAM_TYPE_VALUE_INPUT 1
|
||||
#define TEE_OP_PARAM_TYPE_VALUE_OUTPUT 2
|
||||
#define TEE_OP_PARAM_TYPE_VALUE_INOUT 3
|
||||
#define TEE_OP_PARAM_TYPE_INVALID 4
|
||||
#define TEE_OP_PARAM_TYPE_MEMREF_INPUT 5
|
||||
#define TEE_OP_PARAM_TYPE_MEMREF_OUTPUT 6
|
||||
#define TEE_OP_PARAM_TYPE_MEMREF_INOUT 7
|
||||
|
||||
#define TEE_PARAM_TYPE_GET(t, i) (((t) >> ((i) * 4)) & 0xF)
|
||||
#define TEE_PARAM_TYPES(t0, t1, t2, t3) \
|
||||
((t0) | ((t1) << 4) | ((t2) << 8) | ((t3) << 12))
|
||||
|
||||
/*****************************************************************************
|
||||
** TEE Commands
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* The shared memory between rich world and secure world may be physically
|
||||
* non-contiguous. Below structures are meant to describe a shared memory region
|
||||
* via scatter/gather (sg) list
|
||||
*/
|
||||
|
||||
/**
|
||||
* struct tee_sg_desc - sg descriptor for a physically contiguous buffer
|
||||
* @low_addr: [in] bits[31:0] of buffer's physical address. Must be 4KB aligned
|
||||
* @hi_addr: [in] bits[63:32] of the buffer's physical address
|
||||
* @size: [in] size in bytes (must be multiple of 4KB)
|
||||
*/
|
||||
struct tee_sg_desc {
|
||||
u32 low_addr;
|
||||
u32 hi_addr;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tee_sg_list - structure describing a scatter/gather list
|
||||
* @count: [in] number of sg descriptors
|
||||
* @size: [in] total size of all buffers in the list. Must be multiple of 4KB
|
||||
* @buf: [in] list of sg buffer descriptors
|
||||
*/
|
||||
#define TEE_MAX_SG_DESC 64
|
||||
struct tee_sg_list {
|
||||
u32 count;
|
||||
u32 size;
|
||||
struct tee_sg_desc buf[TEE_MAX_SG_DESC];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tee_cmd_map_shared_mem - command to map shared memory
|
||||
* @buf_id: [out] return buffer ID value
|
||||
* @sg_list: [in] list describing memory to be mapped
|
||||
*/
|
||||
struct tee_cmd_map_shared_mem {
|
||||
u32 buf_id;
|
||||
struct tee_sg_list sg_list;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tee_cmd_unmap_shared_mem - command to unmap shared memory
|
||||
* @buf_id: [in] buffer ID of memory to be unmapped
|
||||
*/
|
||||
struct tee_cmd_unmap_shared_mem {
|
||||
u32 buf_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tee_cmd_load_ta - load Trusted Application (TA) binary into TEE
|
||||
* @low_addr: [in] bits [31:0] of the physical address of the TA binary
|
||||
* @hi_addr: [in] bits [63:32] of the physical address of the TA binary
|
||||
* @size: [in] size of TA binary in bytes
|
||||
* @ta_handle: [out] return handle of the loaded TA
|
||||
*/
|
||||
struct tee_cmd_load_ta {
|
||||
u32 low_addr;
|
||||
u32 hi_addr;
|
||||
u32 size;
|
||||
u32 ta_handle;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tee_cmd_unload_ta - command to unload TA binary from TEE environment
|
||||
* @ta_handle: [in] handle of the loaded TA to be unloaded
|
||||
*/
|
||||
struct tee_cmd_unload_ta {
|
||||
u32 ta_handle;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tee_cmd_open_session - command to call TA_OpenSessionEntryPoint in TA
|
||||
* @ta_handle: [in] handle of the loaded TA
|
||||
* @session_info: [out] pointer to TA allocated session data
|
||||
* @op: [in/out] operation parameters
|
||||
* @return_origin: [out] origin of return code after TEE processing
|
||||
*/
|
||||
struct tee_cmd_open_session {
|
||||
u32 ta_handle;
|
||||
u32 session_info;
|
||||
struct tee_operation op;
|
||||
u32 return_origin;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tee_cmd_close_session - command to call TA_CloseSessionEntryPoint()
|
||||
* in TA
|
||||
* @ta_handle: [in] handle of the loaded TA
|
||||
* @session_info: [in] pointer to TA allocated session data
|
||||
*/
|
||||
struct tee_cmd_close_session {
|
||||
u32 ta_handle;
|
||||
u32 session_info;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tee_cmd_invoke_cmd - command to call TA_InvokeCommandEntryPoint() in
|
||||
* TA
|
||||
* @ta_handle: [in] handle of the loaded TA
|
||||
* @cmd_id: [in] TA command ID
|
||||
* @session_info: [in] pointer to TA allocated session data
|
||||
* @op: [in/out] operation parameters
|
||||
* @return_origin: [out] origin of return code after TEE processing
|
||||
*/
|
||||
struct tee_cmd_invoke_cmd {
|
||||
u32 ta_handle;
|
||||
u32 cmd_id;
|
||||
u32 session_info;
|
||||
struct tee_operation op;
|
||||
u32 return_origin;
|
||||
};
|
||||
|
||||
#endif /*AMDTEE_IF_H*/
|
||||
159
drivers/tee/amdtee/amdtee_private.h
Normal file
159
drivers/tee/amdtee/amdtee_private.h
Normal file
@@ -0,0 +1,159 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
/*
|
||||
* Copyright 2019 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#ifndef AMDTEE_PRIVATE_H
|
||||
#define AMDTEE_PRIVATE_H
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/tee_drv.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/types.h>
|
||||
#include "amdtee_if.h"
|
||||
|
||||
#define DRIVER_NAME "amdtee"
|
||||
#define DRIVER_AUTHOR "AMD-TEE Linux driver team"
|
||||
|
||||
/* Some GlobalPlatform error codes used in this driver */
|
||||
#define TEEC_SUCCESS 0x00000000
|
||||
#define TEEC_ERROR_GENERIC 0xFFFF0000
|
||||
#define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006
|
||||
#define TEEC_ERROR_COMMUNICATION 0xFFFF000E
|
||||
|
||||
#define TEEC_ORIGIN_COMMS 0x00000002
|
||||
|
||||
/* Maximum number of sessions which can be opened with a Trusted Application */
|
||||
#define TEE_NUM_SESSIONS 32
|
||||
|
||||
#define TA_LOAD_PATH "/amdtee"
|
||||
#define TA_PATH_MAX 60
|
||||
|
||||
/**
|
||||
* struct amdtee - main service struct
|
||||
* @teedev: client device
|
||||
* @pool: shared memory pool
|
||||
*/
|
||||
struct amdtee {
|
||||
struct tee_device *teedev;
|
||||
struct tee_shm_pool *pool;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct amdtee_session - Trusted Application (TA) session related information.
|
||||
* @ta_handle: handle to Trusted Application (TA) loaded in TEE environment
|
||||
* @refcount: counter to keep track of sessions opened for the TA instance
|
||||
* @session_info: an array pointing to TA allocated session data.
|
||||
* @sess_mask: session usage bit-mask. If a particular bit is set, then the
|
||||
* corresponding @session_info entry is in use or valid.
|
||||
*
|
||||
* Session structure is updated on open_session and this information is used for
|
||||
* subsequent operations with the Trusted Application.
|
||||
*/
|
||||
struct amdtee_session {
|
||||
struct list_head list_node;
|
||||
u32 ta_handle;
|
||||
struct kref refcount;
|
||||
u32 session_info[TEE_NUM_SESSIONS];
|
||||
DECLARE_BITMAP(sess_mask, TEE_NUM_SESSIONS);
|
||||
spinlock_t lock; /* synchronizes access to @sess_mask */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct amdtee_context_data - AMD-TEE driver context data
|
||||
* @sess_list: Keeps track of sessions opened in current TEE context
|
||||
*/
|
||||
struct amdtee_context_data {
|
||||
struct list_head sess_list;
|
||||
};
|
||||
|
||||
struct amdtee_driver_data {
|
||||
struct amdtee *amdtee;
|
||||
};
|
||||
|
||||
struct shmem_desc {
|
||||
void *kaddr;
|
||||
u64 size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct amdtee_shm_data - Shared memory data
|
||||
* @kaddr: Kernel virtual address of shared memory
|
||||
* @buf_id: Buffer id of memory mapped by TEE_CMD_ID_MAP_SHARED_MEM
|
||||
*/
|
||||
struct amdtee_shm_data {
|
||||
struct list_head shm_node;
|
||||
void *kaddr;
|
||||
u32 buf_id;
|
||||
};
|
||||
|
||||
struct amdtee_shm_context {
|
||||
struct list_head shmdata_list;
|
||||
};
|
||||
|
||||
#define LOWER_TWO_BYTE_MASK 0x0000FFFF
|
||||
|
||||
/**
|
||||
* set_session_id() - Sets the session identifier.
|
||||
* @ta_handle: [in] handle of the loaded Trusted Application (TA)
|
||||
* @session_index: [in] Session index. Range: 0 to (TEE_NUM_SESSIONS - 1).
|
||||
* @session: [out] Pointer to session id
|
||||
*
|
||||
* Lower two bytes of the session identifier represents the TA handle and the
|
||||
* upper two bytes is session index.
|
||||
*/
|
||||
static inline void set_session_id(u32 ta_handle, u32 session_index,
|
||||
u32 *session)
|
||||
{
|
||||
*session = (session_index << 16) | (LOWER_TWO_BYTE_MASK & ta_handle);
|
||||
}
|
||||
|
||||
static inline u32 get_ta_handle(u32 session)
|
||||
{
|
||||
return session & LOWER_TWO_BYTE_MASK;
|
||||
}
|
||||
|
||||
static inline u32 get_session_index(u32 session)
|
||||
{
|
||||
return (session >> 16) & LOWER_TWO_BYTE_MASK;
|
||||
}
|
||||
|
||||
int amdtee_open_session(struct tee_context *ctx,
|
||||
struct tee_ioctl_open_session_arg *arg,
|
||||
struct tee_param *param);
|
||||
|
||||
int amdtee_close_session(struct tee_context *ctx, u32 session);
|
||||
|
||||
int amdtee_invoke_func(struct tee_context *ctx,
|
||||
struct tee_ioctl_invoke_arg *arg,
|
||||
struct tee_param *param);
|
||||
|
||||
int amdtee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session);
|
||||
|
||||
int amdtee_map_shmem(struct tee_shm *shm);
|
||||
|
||||
void amdtee_unmap_shmem(struct tee_shm *shm);
|
||||
|
||||
int handle_load_ta(void *data, u32 size,
|
||||
struct tee_ioctl_open_session_arg *arg);
|
||||
|
||||
int handle_unload_ta(u32 ta_handle);
|
||||
|
||||
int handle_open_session(struct tee_ioctl_open_session_arg *arg, u32 *info,
|
||||
struct tee_param *p);
|
||||
|
||||
int handle_close_session(u32 ta_handle, u32 info);
|
||||
|
||||
int handle_map_shmem(u32 count, struct shmem_desc *start, u32 *buf_id);
|
||||
|
||||
void handle_unmap_shmem(u32 buf_id);
|
||||
|
||||
int handle_invoke_cmd(struct tee_ioctl_invoke_arg *arg, u32 sinfo,
|
||||
struct tee_param *p);
|
||||
|
||||
struct tee_shm_pool *amdtee_config_shm(void);
|
||||
|
||||
u32 get_buffer_id(struct tee_shm *shm);
|
||||
#endif /*AMDTEE_PRIVATE_H*/
|
||||
373
drivers/tee/amdtee/call.c
Normal file
373
drivers/tee/amdtee/call.c
Normal file
@@ -0,0 +1,373 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright 2019 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/tee.h>
|
||||
#include <linux/tee_drv.h>
|
||||
#include <linux/psp-tee.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/psp-sev.h>
|
||||
#include "amdtee_if.h"
|
||||
#include "amdtee_private.h"
|
||||
|
||||
static int tee_params_to_amd_params(struct tee_param *tee, u32 count,
|
||||
struct tee_operation *amd)
|
||||
{
|
||||
int i, ret = 0;
|
||||
u32 type;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (!tee || !amd || count > TEE_MAX_PARAMS)
|
||||
return -EINVAL;
|
||||
|
||||
amd->param_types = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
/* AMD TEE does not support meta parameter */
|
||||
if (tee[i].attr > TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT)
|
||||
return -EINVAL;
|
||||
|
||||
amd->param_types |= ((tee[i].attr & 0xF) << i * 4);
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
type = TEE_PARAM_TYPE_GET(amd->param_types, i);
|
||||
pr_debug("%s: type[%d] = 0x%x\n", __func__, i, type);
|
||||
|
||||
if (type == TEE_OP_PARAM_TYPE_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
if (type == TEE_OP_PARAM_TYPE_NONE)
|
||||
continue;
|
||||
|
||||
/* It is assumed that all values are within 2^32-1 */
|
||||
if (type > TEE_OP_PARAM_TYPE_VALUE_INOUT) {
|
||||
u32 buf_id = get_buffer_id(tee[i].u.memref.shm);
|
||||
|
||||
amd->params[i].mref.buf_id = buf_id;
|
||||
amd->params[i].mref.offset = tee[i].u.memref.shm_offs;
|
||||
amd->params[i].mref.size = tee[i].u.memref.size;
|
||||
pr_debug("%s: bufid[%d] = 0x%x, offset[%d] = 0x%x, size[%d] = 0x%x\n",
|
||||
__func__,
|
||||
i, amd->params[i].mref.buf_id,
|
||||
i, amd->params[i].mref.offset,
|
||||
i, amd->params[i].mref.size);
|
||||
} else {
|
||||
if (tee[i].u.value.c)
|
||||
pr_warn("%s: Discarding value c", __func__);
|
||||
|
||||
amd->params[i].val.a = tee[i].u.value.a;
|
||||
amd->params[i].val.b = tee[i].u.value.b;
|
||||
pr_debug("%s: a[%d] = 0x%x, b[%d] = 0x%x\n", __func__,
|
||||
i, amd->params[i].val.a,
|
||||
i, amd->params[i].val.b);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amd_params_to_tee_params(struct tee_param *tee, u32 count,
|
||||
struct tee_operation *amd)
|
||||
{
|
||||
int i, ret = 0;
|
||||
u32 type;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (!tee || !amd || count > TEE_MAX_PARAMS)
|
||||
return -EINVAL;
|
||||
|
||||
/* Assumes amd->param_types is valid */
|
||||
for (i = 0; i < count; i++) {
|
||||
type = TEE_PARAM_TYPE_GET(amd->param_types, i);
|
||||
pr_debug("%s: type[%d] = 0x%x\n", __func__, i, type);
|
||||
|
||||
if (type == TEE_OP_PARAM_TYPE_INVALID ||
|
||||
type > TEE_OP_PARAM_TYPE_MEMREF_INOUT)
|
||||
return -EINVAL;
|
||||
|
||||
if (type == TEE_OP_PARAM_TYPE_NONE ||
|
||||
type == TEE_OP_PARAM_TYPE_VALUE_INPUT ||
|
||||
type == TEE_OP_PARAM_TYPE_MEMREF_INPUT)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* It is assumed that buf_id remains unchanged for
|
||||
* both open_session and invoke_cmd call
|
||||
*/
|
||||
if (type > TEE_OP_PARAM_TYPE_MEMREF_INPUT) {
|
||||
tee[i].u.memref.shm_offs = amd->params[i].mref.offset;
|
||||
tee[i].u.memref.size = amd->params[i].mref.size;
|
||||
pr_debug("%s: bufid[%d] = 0x%x, offset[%d] = 0x%x, size[%d] = 0x%x\n",
|
||||
__func__,
|
||||
i, amd->params[i].mref.buf_id,
|
||||
i, amd->params[i].mref.offset,
|
||||
i, amd->params[i].mref.size);
|
||||
} else {
|
||||
/* field 'c' not supported by AMD TEE */
|
||||
tee[i].u.value.a = amd->params[i].val.a;
|
||||
tee[i].u.value.b = amd->params[i].val.b;
|
||||
tee[i].u.value.c = 0;
|
||||
pr_debug("%s: a[%d] = 0x%x, b[%d] = 0x%x\n",
|
||||
__func__,
|
||||
i, amd->params[i].val.a,
|
||||
i, amd->params[i].val.b);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int handle_unload_ta(u32 ta_handle)
|
||||
{
|
||||
struct tee_cmd_unload_ta cmd = {0};
|
||||
int ret = 0;
|
||||
u32 status;
|
||||
|
||||
if (!ta_handle)
|
||||
return -EINVAL;
|
||||
|
||||
cmd.ta_handle = ta_handle;
|
||||
|
||||
ret = psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA, (void *)&cmd,
|
||||
sizeof(cmd), &status);
|
||||
if (!ret && status != 0) {
|
||||
pr_err("unload ta: status = 0x%x\n", status);
|
||||
ret = -EBUSY;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int handle_close_session(u32 ta_handle, u32 info)
|
||||
{
|
||||
struct tee_cmd_close_session cmd = {0};
|
||||
int ret = 0;
|
||||
u32 status;
|
||||
|
||||
if (ta_handle == 0)
|
||||
return -EINVAL;
|
||||
|
||||
cmd.ta_handle = ta_handle;
|
||||
cmd.session_info = info;
|
||||
|
||||
ret = psp_tee_process_cmd(TEE_CMD_ID_CLOSE_SESSION, (void *)&cmd,
|
||||
sizeof(cmd), &status);
|
||||
if (!ret && status != 0) {
|
||||
pr_err("close session: status = 0x%x\n", status);
|
||||
ret = -EBUSY;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void handle_unmap_shmem(u32 buf_id)
|
||||
{
|
||||
struct tee_cmd_unmap_shared_mem cmd = {0};
|
||||
int ret = 0;
|
||||
u32 status;
|
||||
|
||||
cmd.buf_id = buf_id;
|
||||
|
||||
ret = psp_tee_process_cmd(TEE_CMD_ID_UNMAP_SHARED_MEM, (void *)&cmd,
|
||||
sizeof(cmd), &status);
|
||||
if (!ret)
|
||||
pr_debug("unmap shared memory: buf_id %u status = 0x%x\n",
|
||||
buf_id, status);
|
||||
}
|
||||
|
||||
int handle_invoke_cmd(struct tee_ioctl_invoke_arg *arg, u32 sinfo,
|
||||
struct tee_param *p)
|
||||
{
|
||||
struct tee_cmd_invoke_cmd cmd = {0};
|
||||
int ret = 0;
|
||||
|
||||
if (!arg || (!p && arg->num_params))
|
||||
return -EINVAL;
|
||||
|
||||
arg->ret_origin = TEEC_ORIGIN_COMMS;
|
||||
|
||||
if (arg->session == 0) {
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tee_params_to_amd_params(p, arg->num_params, &cmd.op);
|
||||
if (ret) {
|
||||
pr_err("invalid Params. Abort invoke command\n");
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
cmd.ta_handle = get_ta_handle(arg->session);
|
||||
cmd.cmd_id = arg->func;
|
||||
cmd.session_info = sinfo;
|
||||
|
||||
ret = psp_tee_process_cmd(TEE_CMD_ID_INVOKE_CMD, (void *)&cmd,
|
||||
sizeof(cmd), &arg->ret);
|
||||
if (ret) {
|
||||
arg->ret = TEEC_ERROR_COMMUNICATION;
|
||||
} else {
|
||||
ret = amd_params_to_tee_params(p, arg->num_params, &cmd.op);
|
||||
if (unlikely(ret)) {
|
||||
pr_err("invoke command: failed to copy output\n");
|
||||
arg->ret = TEEC_ERROR_GENERIC;
|
||||
return ret;
|
||||
}
|
||||
arg->ret_origin = cmd.return_origin;
|
||||
pr_debug("invoke command: RO = 0x%x ret = 0x%x\n",
|
||||
arg->ret_origin, arg->ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int handle_map_shmem(u32 count, struct shmem_desc *start, u32 *buf_id)
|
||||
{
|
||||
struct tee_cmd_map_shared_mem *cmd;
|
||||
phys_addr_t paddr;
|
||||
int ret = 0, i;
|
||||
u32 status;
|
||||
|
||||
if (!count || !start || !buf_id)
|
||||
return -EINVAL;
|
||||
|
||||
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Size must be page aligned */
|
||||
for (i = 0; i < count ; i++) {
|
||||
if (!start[i].kaddr || (start[i].size & (PAGE_SIZE - 1))) {
|
||||
ret = -EINVAL;
|
||||
goto free_cmd;
|
||||
}
|
||||
|
||||
if ((u64)start[i].kaddr & (PAGE_SIZE - 1)) {
|
||||
pr_err("map shared memory: page unaligned. addr 0x%llx",
|
||||
(u64)start[i].kaddr);
|
||||
ret = -EINVAL;
|
||||
goto free_cmd;
|
||||
}
|
||||
}
|
||||
|
||||
cmd->sg_list.count = count;
|
||||
|
||||
/* Create buffer list */
|
||||
for (i = 0; i < count ; i++) {
|
||||
paddr = __psp_pa(start[i].kaddr);
|
||||
cmd->sg_list.buf[i].hi_addr = upper_32_bits(paddr);
|
||||
cmd->sg_list.buf[i].low_addr = lower_32_bits(paddr);
|
||||
cmd->sg_list.buf[i].size = start[i].size;
|
||||
cmd->sg_list.size += cmd->sg_list.buf[i].size;
|
||||
|
||||
pr_debug("buf[%d]:hi addr = 0x%x\n", i,
|
||||
cmd->sg_list.buf[i].hi_addr);
|
||||
pr_debug("buf[%d]:low addr = 0x%x\n", i,
|
||||
cmd->sg_list.buf[i].low_addr);
|
||||
pr_debug("buf[%d]:size = 0x%x\n", i, cmd->sg_list.buf[i].size);
|
||||
pr_debug("list size = 0x%x\n", cmd->sg_list.size);
|
||||
}
|
||||
|
||||
*buf_id = 0;
|
||||
|
||||
ret = psp_tee_process_cmd(TEE_CMD_ID_MAP_SHARED_MEM, (void *)cmd,
|
||||
sizeof(*cmd), &status);
|
||||
if (!ret && !status) {
|
||||
*buf_id = cmd->buf_id;
|
||||
pr_debug("mapped buffer ID = 0x%x\n", *buf_id);
|
||||
} else {
|
||||
pr_err("map shared memory: status = 0x%x\n", status);
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
|
||||
free_cmd:
|
||||
kfree(cmd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int handle_open_session(struct tee_ioctl_open_session_arg *arg, u32 *info,
|
||||
struct tee_param *p)
|
||||
{
|
||||
struct tee_cmd_open_session cmd = {0};
|
||||
int ret = 0;
|
||||
|
||||
if (!arg || !info || (!p && arg->num_params))
|
||||
return -EINVAL;
|
||||
|
||||
arg->ret_origin = TEEC_ORIGIN_COMMS;
|
||||
|
||||
if (arg->session == 0) {
|
||||
arg->ret = TEEC_ERROR_GENERIC;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = tee_params_to_amd_params(p, arg->num_params, &cmd.op);
|
||||
if (ret) {
|
||||
pr_err("invalid Params. Abort open session\n");
|
||||
arg->ret = TEEC_ERROR_BAD_PARAMETERS;
|
||||
return ret;
|
||||
}
|
||||
|
||||
cmd.ta_handle = get_ta_handle(arg->session);
|
||||
*info = 0;
|
||||
|
||||
ret = psp_tee_process_cmd(TEE_CMD_ID_OPEN_SESSION, (void *)&cmd,
|
||||
sizeof(cmd), &arg->ret);
|
||||
if (ret) {
|
||||
arg->ret = TEEC_ERROR_COMMUNICATION;
|
||||
} else {
|
||||
ret = amd_params_to_tee_params(p, arg->num_params, &cmd.op);
|
||||
if (unlikely(ret)) {
|
||||
pr_err("open session: failed to copy output\n");
|
||||
arg->ret = TEEC_ERROR_GENERIC;
|
||||
return ret;
|
||||
}
|
||||
arg->ret_origin = cmd.return_origin;
|
||||
*info = cmd.session_info;
|
||||
pr_debug("open session: session info = 0x%x\n", *info);
|
||||
}
|
||||
|
||||
pr_debug("open session: ret = 0x%x RO = 0x%x\n", arg->ret,
|
||||
arg->ret_origin);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int handle_load_ta(void *data, u32 size, struct tee_ioctl_open_session_arg *arg)
|
||||
{
|
||||
struct tee_cmd_load_ta cmd = {0};
|
||||
phys_addr_t blob;
|
||||
int ret = 0;
|
||||
|
||||
if (size == 0 || !data || !arg)
|
||||
return -EINVAL;
|
||||
|
||||
blob = __psp_pa(data);
|
||||
if (blob & (PAGE_SIZE - 1)) {
|
||||
pr_err("load TA: page unaligned. blob 0x%llx", blob);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmd.hi_addr = upper_32_bits(blob);
|
||||
cmd.low_addr = lower_32_bits(blob);
|
||||
cmd.size = size;
|
||||
|
||||
ret = psp_tee_process_cmd(TEE_CMD_ID_LOAD_TA, (void *)&cmd,
|
||||
sizeof(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);
|
||||
}
|
||||
|
||||
pr_debug("load TA: TA handle = 0x%x, RO = 0x%x, ret = 0x%x\n",
|
||||
cmd.ta_handle, arg->ret_origin, arg->ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
510
drivers/tee/amdtee/core.c
Normal file
510
drivers/tee/amdtee/core.c
Normal file
File diff suppressed because it is too large
Load Diff
93
drivers/tee/amdtee/shm_pool.c
Normal file
93
drivers/tee/amdtee/shm_pool.c
Normal file
@@ -0,0 +1,93 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright 2019 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tee_drv.h>
|
||||
#include <linux/psp-sev.h>
|
||||
#include "amdtee_private.h"
|
||||
|
||||
static int pool_op_alloc(struct tee_shm_pool_mgr *poolm, struct tee_shm *shm,
|
||||
size_t size)
|
||||
{
|
||||
unsigned int order = get_order(size);
|
||||
unsigned long va;
|
||||
int rc;
|
||||
|
||||
va = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
|
||||
if (!va)
|
||||
return -ENOMEM;
|
||||
|
||||
shm->kaddr = (void *)va;
|
||||
shm->paddr = __psp_pa((void *)va);
|
||||
shm->size = PAGE_SIZE << order;
|
||||
|
||||
/* Map the allocated memory in to TEE */
|
||||
rc = amdtee_map_shmem(shm);
|
||||
if (rc) {
|
||||
free_pages(va, order);
|
||||
shm->kaddr = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pool_op_free(struct tee_shm_pool_mgr *poolm, struct tee_shm *shm)
|
||||
{
|
||||
/* Unmap the shared memory from TEE */
|
||||
amdtee_unmap_shmem(shm);
|
||||
free_pages((unsigned long)shm->kaddr, get_order(shm->size));
|
||||
shm->kaddr = NULL;
|
||||
}
|
||||
|
||||
static void pool_op_destroy_poolmgr(struct tee_shm_pool_mgr *poolm)
|
||||
{
|
||||
kfree(poolm);
|
||||
}
|
||||
|
||||
static const struct tee_shm_pool_mgr_ops pool_ops = {
|
||||
.alloc = pool_op_alloc,
|
||||
.free = pool_op_free,
|
||||
.destroy_poolmgr = pool_op_destroy_poolmgr,
|
||||
};
|
||||
|
||||
static struct tee_shm_pool_mgr *pool_mem_mgr_alloc(void)
|
||||
{
|
||||
struct tee_shm_pool_mgr *mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
|
||||
|
||||
if (!mgr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mgr->ops = &pool_ops;
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
struct tee_shm_pool *amdtee_config_shm(void)
|
||||
{
|
||||
struct tee_shm_pool_mgr *priv_mgr;
|
||||
struct tee_shm_pool_mgr *dmabuf_mgr;
|
||||
void *rc;
|
||||
|
||||
rc = pool_mem_mgr_alloc();
|
||||
if (IS_ERR(rc))
|
||||
return rc;
|
||||
priv_mgr = rc;
|
||||
|
||||
rc = pool_mem_mgr_alloc();
|
||||
if (IS_ERR(rc)) {
|
||||
tee_shm_pool_mgr_destroy(priv_mgr);
|
||||
return rc;
|
||||
}
|
||||
dmabuf_mgr = rc;
|
||||
|
||||
rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
|
||||
if (IS_ERR(rc)) {
|
||||
tee_shm_pool_mgr_destroy(priv_mgr);
|
||||
tee_shm_pool_mgr_destroy(dmabuf_mgr);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -56,6 +56,7 @@
|
||||
* TEE Implementation ID
|
||||
*/
|
||||
#define TEE_IMPL_ID_OPTEE 1
|
||||
#define TEE_IMPL_ID_AMDTEE 2
|
||||
|
||||
/*
|
||||
* OP-TEE specific capabilities
|
||||
|
||||
Reference in New Issue
Block a user