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/slab.h>
|
||||||
#include <linux/gfp.h>
|
#include <linux/gfp.h>
|
||||||
#include <linux/psp-sev.h>
|
#include <linux/psp-sev.h>
|
||||||
|
#include <linux/psp-tee.h>
|
||||||
|
|
||||||
#include "psp-dev.h"
|
#include "psp-dev.h"
|
||||||
#include "tee-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_start = start_addr;
|
||||||
rb_mgr->ring_size = ring_size;
|
rb_mgr->ring_size = ring_size;
|
||||||
rb_mgr->ring_pa = __psp_pa(start_addr);
|
rb_mgr->ring_pa = __psp_pa(start_addr);
|
||||||
|
mutex_init(&rb_mgr->mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -55,6 +57,7 @@ static void tee_free_ring(struct psp_tee_device *tee)
|
|||||||
rb_mgr->ring_start = NULL;
|
rb_mgr->ring_start = NULL;
|
||||||
rb_mgr->ring_size = 0;
|
rb_mgr->ring_size = 0;
|
||||||
rb_mgr->ring_pa = 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,
|
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);
|
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
|
* @wptr: index to the last written entry in ring buffer
|
||||||
*/
|
*/
|
||||||
struct ring_buf_manager {
|
struct ring_buf_manager {
|
||||||
|
struct mutex mutex; /* synchronizes access to ring buffer */
|
||||||
void *ring_start;
|
void *ring_start;
|
||||||
u32 ring_size;
|
u32 ring_size;
|
||||||
phys_addr_t ring_pa;
|
phys_addr_t ring_pa;
|
||||||
|
73
include/linux/psp-tee.h
Normal file
73
include/linux/psp-tee.h
Normal 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_ */
|
Loading…
Reference in New Issue
Block a user