Skip to content

Commit

Permalink
crypto: ccp - provide in-kernel API to submit TEE commands
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Rijo Thomas authored and Herbert Xu committed Dec 20, 2019
1 parent 33960ac commit 632b0b5
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 0 deletions.
126 changes: 126 additions & 0 deletions drivers/crypto/ccp/tee-dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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;
}
Expand All @@ -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,
Expand Down Expand Up @@ -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);
1 change: 1 addition & 0 deletions drivers/crypto/ccp/tee-dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
73 changes: 73 additions & 0 deletions include/linux/psp-tee.h
Original file line number Diff line number Diff line change
@@ -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_ */

0 comments on commit 632b0b5

Please sign in to comment.