今天我们来看看TEEC_RegisterSharedMemory去注册一个共享内存的实现原理。TEEC_RegisterSharedMemory函数运行在libteec中,是为了注册一块在CA端的内存作为CA与TA之间的共享内存
TEEC_Result TEEC_RegisterSharedMemory(TEEC_Context *ctx, TEEC_SharedMemory *shm)
{
int fd;
size_t s;
if (!ctx || !shm)
return TEEC_ERROR_BAD_PARAMETERS;
if (!shm->flags || (shm->flags & ~(TEEC_MEM_INPUT | TEEC_MEM_OUTPUT)))
return TEEC_ERROR_BAD_PARAMETERS;
s = shm->size;
if (!s)
s = 8;
if (ctx->reg_mem) { //我的例子中这里为0,因此走else分支
fd = teec_shm_register(ctx->fd, shm->buffer, s, &shm->id);
if (fd < 0)
return TEEC_ERROR_OUT_OF_MEMORY;
shm->registered_fd = fd;
shm->shadow_buffer = NULL;
} else {
fd = teec_shm_alloc(ctx->fd, s, &shm->id);
if (fd < 0)
return TEEC_ERROR_OUT_OF_MEMORY;
shm->shadow_buffer = mmap(NULL, s, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
close(fd);
if (shm->shadow_buffer == (void *)MAP_FAILED) {
shm->id = -1;
return TEEC_ERROR_OUT_OF_MEMORY;
}
shm->registered_fd = -1;
}
shm->alloced_size = s;
shm->buffer_allocated = false;
return TEEC_SUCCESS;
}ctx->reg_mem变量是在初始化context的时候赋值的。
TEEC_Result TEEC_InitializeContext(const char *name, TEEC_Context *ctx)
{
char devname[PATH_MAX];
int fd;
size_t n;
if (!ctx)
return TEEC_ERROR_BAD_PARAMETERS;
for (n = 0; n < TEEC_MAX_DEV_SEQ; n++) { //TEEC_MAX_DEV_SEQ=10,只使用前10个tee设备
uint32_t gen_caps;
snprintf(devname, sizeof(devname), "/dev/tee%zu", n);
fd = teec_open_dev(devname, name, &gen_caps); //打开节点,并取得caps,cap是什么意思后面需要研究
if (fd >= 0) { //如果成功打开节点,则说明找到了合适的节点和对应的驱动,可以将fd返回了
ctx->fd = fd;
ctx->reg_mem = gen_caps & TEE_GEN_CAP_REG_MEM;
return TEEC_SUCCESS;
}
}
return TEEC_ERROR_ITEM_NOT_FOUND;
}gen_caps取到的是kernel驱动中的optee->sec_caps,在我的例子中,这个值在驱动初始化的时候被赋值为OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM。因此ctx->reg_mem = 0。
在else分支中关键函数是teec_shm_alloc,他通过kernel alloc了一块内存,这个内存是可以和TEE侧进行通信的,因为是和TEE的共享内存,具体内容可参考https://blog.csdn.net/orlando19860122/article/details/88430358
static int teec_shm_alloc(int fd, size_t size, int *id)
{
int shm_fd;
struct tee_ioctl_shm_alloc_data data;
memset(&data, 0, sizeof(data));
data.size = size;
shm_fd = ioctl(fd, TEE_IOC_SHM_ALLOC, &data);
if (shm_fd < 0)
return -1;
*id = data.id; //共享内存在这个设备上的编号
return shm_fd; //共享内存对应的文件描述符
}ioctl最终会调用的kernel中的__tee_shm_alloc
static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx,
struct tee_device *teedev,
size_t size, u32 flags)
{
struct tee_shm_pool_mgr *poolm = NULL;
struct tee_shm *shm;
void *ret;
int rc;
if (ctx && ctx->teedev != teedev) {
dev_err(teedev->dev.parent, "ctx and teedev mismatch\n");
return ERR_PTR(-EINVAL);
}
if (!(flags & TEE_SHM_MAPPED)) {
dev_err(teedev->dev.parent,
"only mapped allocations supported\n");
return ERR_PTR(-EINVAL);
}
if ((flags & ~(TEE_SHM_MAPPED | TEE_SHM_DMA_BUF))) {
dev_err(teedev->dev.parent, "invalid shm flags 0x%x", flags);
return ERR_PTR(-EINVAL);
}
if (!tee_device_get(teedev))
return ERR_PTR(-EINVAL);
if (!teedev->pool) {
/* teedev has been detached from driver */
ret = ERR_PTR(-EINVAL);
goto err_dev_put;
}
shm = kzalloc(sizeof(*shm), GFP_KERNEL);
if (!shm) {
ret = ERR_PTR(-ENOMEM);
goto err_dev_put;
}
shm->flags = flags | TEE_SHM_POOL;
shm->teedev = teedev;
shm->ctx = ctx;
if (flags & TEE_SHM_DMA_BUF)
poolm = teedev->pool->dma_buf_mgr;
else
poolm = teedev->pool->private_mgr;
rc = poolm->ops->alloc(poolm, shm, size); //使用驱动初始化的时候分配的内存池来alloc一块内存
if (rc) {
ret = ERR_PTR(rc);
goto err_kfree;
}
mutex_lock(&teedev->mutex);
shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL);
mutex_unlock(&teedev->mutex);
if (shm->id < 0) {
ret = ERR_PTR(shm->id);
goto err_pool_free;
}
if (flags & TEE_SHM_DMA_BUF) {
DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
exp_info.ops = &tee_shm_dma_buf_ops;
exp_info.size = shm->size;
exp_info.flags = O_RDWR;
exp_info.priv = shm;
shm->dmabuf = dma_buf_export(&exp_info);
if (IS_ERR(shm->dmabuf)) {
ret = ERR_CAST(shm->dmabuf);
goto err_rem;
}
}
if (ctx) {
teedev_ctx_get(ctx);
mutex_lock(&teedev->mutex);
list_add_tail(&shm->link, &ctx->list_shm);
mutex_unlock(&teedev->mutex);
}
return shm;
err_rem:
mutex_lock(&teedev->mutex);
idr_remove(&teedev->idr, shm->id);
mutex_unlock(&teedev->mutex);
err_pool_free:
poolm->ops->free(poolm, shm);
err_kfree:
kfree(shm);
err_dev_put:
tee_device_put(teedev);
return ret;
}可以看到关键函数就是使用驱动初始化的时候分配的内存池来alloc一块内存。这块内存对应的物理空间是和TEE共享的,因此这是分配了一块共享内存
版权声明:本文为orlando19860122原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。