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:
Rijo Thomas 2019-12-04 11:49:03 +05:30 committed by Herbert Xu
parent 33960acccf
commit 632b0b5301
3 changed files with 200 additions and 0 deletions

View file

@ -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);

View file

@ -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;

73
include/linux/psp-tee.h Normal file
View file

@ -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_ */