crypto: ccp - provide in-kernel API to submit TEE commands
Extend the functionality of AMD Secure Processor (SP) driver by providing an in-kernel API to submit commands to TEE ring buffer for processing by Trusted OS running on AMD Secure Processor. Following TEE commands are supported by Trusted OS: * TEE_CMD_ID_LOAD_TA : Load Trusted Application (TA) binary into TEE environment * TEE_CMD_ID_UNLOAD_TA : Unload TA binary from TEE environment * TEE_CMD_ID_OPEN_SESSION : Open session with loaded TA * TEE_CMD_ID_CLOSE_SESSION : Close session with loaded TA * TEE_CMD_ID_INVOKE_CMD : Invoke a command with loaded TA * TEE_CMD_ID_MAP_SHARED_MEM : Map shared memory * TEE_CMD_ID_UNMAP_SHARED_MEM : Unmap shared memory Linux AMD-TEE driver will use this API to submit command buffers for processing in Trusted Execution Environment. The AMD-TEE driver shall be introduced in a separate patch. Cc: Jens Wiklander <jens.wiklander@linaro.org> Cc: Tom Lendacky <thomas.lendacky@amd.com> Cc: Ard Biesheuvel <ard.biesheuvel@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> Acked-by: Gary R Hook <gary.hook@amd.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
This commit is contained in:
parent
33960acccf
commit
632b0b5301
|
@ -14,6 +14,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/psp-sev.h>
|
||||
#include <linux/psp-tee.h>
|
||||
|
||||
#include "psp-dev.h"
|
||||
#include "tee-dev.h"
|
||||
|
@ -38,6 +39,7 @@ static int tee_alloc_ring(struct psp_tee_device *tee, int ring_size)
|
|||
rb_mgr->ring_start = start_addr;
|
||||
rb_mgr->ring_size = ring_size;
|
||||
rb_mgr->ring_pa = __psp_pa(start_addr);
|
||||
mutex_init(&rb_mgr->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -55,6 +57,7 @@ static void tee_free_ring(struct psp_tee_device *tee)
|
|||
rb_mgr->ring_start = NULL;
|
||||
rb_mgr->ring_size = 0;
|
||||
rb_mgr->ring_pa = 0;
|
||||
mutex_destroy(&rb_mgr->mutex);
|
||||
}
|
||||
|
||||
static int tee_wait_cmd_poll(struct psp_tee_device *tee, unsigned int timeout,
|
||||
|
@ -236,3 +239,126 @@ void tee_dev_destroy(struct psp_device *psp)
|
|||
|
||||
tee_destroy_ring(tee);
|
||||
}
|
||||
|
||||
static int tee_submit_cmd(struct psp_tee_device *tee, enum tee_cmd_id cmd_id,
|
||||
void *buf, size_t len, struct tee_ring_cmd **resp)
|
||||
{
|
||||
struct tee_ring_cmd *cmd;
|
||||
u32 rptr, wptr;
|
||||
int nloop = 1000, ret = 0;
|
||||
|
||||
*resp = NULL;
|
||||
|
||||
mutex_lock(&tee->rb_mgr.mutex);
|
||||
|
||||
wptr = tee->rb_mgr.wptr;
|
||||
|
||||
/* Check if ring buffer is full */
|
||||
do {
|
||||
rptr = ioread32(tee->io_regs + tee->vdata->ring_rptr_reg);
|
||||
|
||||
if (!(wptr + sizeof(struct tee_ring_cmd) == rptr))
|
||||
break;
|
||||
|
||||
dev_info(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n",
|
||||
rptr, wptr);
|
||||
|
||||
/* Wait if ring buffer is full */
|
||||
mutex_unlock(&tee->rb_mgr.mutex);
|
||||
schedule_timeout_interruptible(msecs_to_jiffies(10));
|
||||
mutex_lock(&tee->rb_mgr.mutex);
|
||||
|
||||
} while (--nloop);
|
||||
|
||||
if (!nloop && (wptr + sizeof(struct tee_ring_cmd) == rptr)) {
|
||||
dev_err(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n",
|
||||
rptr, wptr);
|
||||
ret = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* Pointer to empty data entry in ring buffer */
|
||||
cmd = (struct tee_ring_cmd *)(tee->rb_mgr.ring_start + wptr);
|
||||
|
||||
/* Write command data into ring buffer */
|
||||
cmd->cmd_id = cmd_id;
|
||||
cmd->cmd_state = TEE_CMD_STATE_INIT;
|
||||
memset(&cmd->buf[0], 0, sizeof(cmd->buf));
|
||||
memcpy(&cmd->buf[0], buf, len);
|
||||
|
||||
/* Update local copy of write pointer */
|
||||
tee->rb_mgr.wptr += sizeof(struct tee_ring_cmd);
|
||||
if (tee->rb_mgr.wptr >= tee->rb_mgr.ring_size)
|
||||
tee->rb_mgr.wptr = 0;
|
||||
|
||||
/* Trigger interrupt to Trusted OS */
|
||||
iowrite32(tee->rb_mgr.wptr, tee->io_regs + tee->vdata->ring_wptr_reg);
|
||||
|
||||
/* The response is provided by Trusted OS in same
|
||||
* location as submitted data entry within ring buffer.
|
||||
*/
|
||||
*resp = cmd;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&tee->rb_mgr.mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tee_wait_cmd_completion(struct psp_tee_device *tee,
|
||||
struct tee_ring_cmd *resp,
|
||||
unsigned int timeout)
|
||||
{
|
||||
/* ~5ms sleep per loop => nloop = timeout * 200 */
|
||||
int nloop = timeout * 200;
|
||||
|
||||
while (--nloop) {
|
||||
if (resp->cmd_state == TEE_CMD_STATE_COMPLETED)
|
||||
return 0;
|
||||
|
||||
usleep_range(5000, 5100);
|
||||
}
|
||||
|
||||
dev_err(tee->dev, "tee: command 0x%x timed out, disabling PSP\n",
|
||||
resp->cmd_id);
|
||||
|
||||
psp_dead = true;
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
int psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf, size_t len,
|
||||
u32 *status)
|
||||
{
|
||||
struct psp_device *psp = psp_get_master_device();
|
||||
struct psp_tee_device *tee;
|
||||
struct tee_ring_cmd *resp;
|
||||
int ret;
|
||||
|
||||
if (!buf || !status || !len || len > sizeof(resp->buf))
|
||||
return -EINVAL;
|
||||
|
||||
*status = 0;
|
||||
|
||||
if (!psp || !psp->tee_data)
|
||||
return -ENODEV;
|
||||
|
||||
if (psp_dead)
|
||||
return -EBUSY;
|
||||
|
||||
tee = psp->tee_data;
|
||||
|
||||
ret = tee_submit_cmd(tee, cmd_id, buf, len, &resp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = tee_wait_cmd_completion(tee, resp, TEE_DEFAULT_TIMEOUT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memcpy(buf, &resp->buf[0], len);
|
||||
*status = resp->status;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(psp_tee_process_cmd);
|
||||
|
|
|
@ -54,6 +54,7 @@ struct tee_init_ring_cmd {
|
|||
* @wptr: index to the last written entry in ring buffer
|
||||
*/
|
||||
struct ring_buf_manager {
|
||||
struct mutex mutex; /* synchronizes access to ring buffer */
|
||||
void *ring_start;
|
||||
u32 ring_size;
|
||||
phys_addr_t ring_pa;
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* AMD Trusted Execution Environment (TEE) interface
|
||||
*
|
||||
* Author: Rijo Thomas <Rijo-john.Thomas@amd.com>
|
||||
*
|
||||
* Copyright 2019 Advanced Micro Devices, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PSP_TEE_H_
|
||||
#define __PSP_TEE_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
/* This file defines the Trusted Execution Environment (TEE) interface commands
|
||||
* and the API exported by AMD Secure Processor driver to communicate with
|
||||
* AMD-TEE Trusted OS.
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum tee_cmd_id - TEE Interface Command IDs
|
||||
* @TEE_CMD_ID_LOAD_TA: Load Trusted Application (TA) binary into
|
||||
* TEE environment
|
||||
* @TEE_CMD_ID_UNLOAD_TA: Unload TA binary from TEE environment
|
||||
* @TEE_CMD_ID_OPEN_SESSION: Open session with loaded TA
|
||||
* @TEE_CMD_ID_CLOSE_SESSION: Close session with loaded TA
|
||||
* @TEE_CMD_ID_INVOKE_CMD: Invoke a command with loaded TA
|
||||
* @TEE_CMD_ID_MAP_SHARED_MEM: Map shared memory
|
||||
* @TEE_CMD_ID_UNMAP_SHARED_MEM: Unmap shared memory
|
||||
*/
|
||||
enum tee_cmd_id {
|
||||
TEE_CMD_ID_LOAD_TA = 1,
|
||||
TEE_CMD_ID_UNLOAD_TA,
|
||||
TEE_CMD_ID_OPEN_SESSION,
|
||||
TEE_CMD_ID_CLOSE_SESSION,
|
||||
TEE_CMD_ID_INVOKE_CMD,
|
||||
TEE_CMD_ID_MAP_SHARED_MEM,
|
||||
TEE_CMD_ID_UNMAP_SHARED_MEM,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_CRYPTO_DEV_SP_PSP
|
||||
/**
|
||||
* psp_tee_process_cmd() - Process command in Trusted Execution Environment
|
||||
* @cmd_id: TEE command ID (&enum tee_cmd_id)
|
||||
* @buf: Command buffer for TEE processing. On success, is updated
|
||||
* with the response
|
||||
* @len: Length of command buffer in bytes
|
||||
* @status: On success, holds the TEE command execution status
|
||||
*
|
||||
* This function submits a command to the Trusted OS for processing in the
|
||||
* TEE environment and waits for a response or until the command times out.
|
||||
*
|
||||
* Returns:
|
||||
* 0 if TEE successfully processed the command
|
||||
* -%ENODEV if PSP device not available
|
||||
* -%EINVAL if invalid input
|
||||
* -%ETIMEDOUT if TEE command timed out
|
||||
* -%EBUSY if PSP device is not responsive
|
||||
*/
|
||||
int psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf, size_t len,
|
||||
u32 *status);
|
||||
|
||||
#else /* !CONFIG_CRYPTO_DEV_SP_PSP */
|
||||
|
||||
static inline int psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf,
|
||||
size_t len, u32 *status)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* CONFIG_CRYPTO_DEV_SP_PSP */
|
||||
#endif /* __PSP_TEE_H_ */
|
Loading…
Reference in New Issue