xref: /openbmc/linux/drivers/crypto/ccp/tee-dev.c (revision bade7e1fbd34f46462e6eb1db5474832a4144ac2)
133960accSRijo Thomas // SPDX-License-Identifier: MIT
233960accSRijo Thomas /*
333960accSRijo Thomas  * AMD Trusted Execution Environment (TEE) interface
433960accSRijo Thomas  *
533960accSRijo Thomas  * Author: Rijo Thomas <Rijo-john.Thomas@amd.com>
633960accSRijo Thomas  * Author: Devaraj Rangasamy <Devaraj.Rangasamy@amd.com>
733960accSRijo Thomas  *
833960accSRijo Thomas  * Copyright 2019 Advanced Micro Devices, Inc.
933960accSRijo Thomas  */
1033960accSRijo Thomas 
1133960accSRijo Thomas #include <linux/types.h>
1233960accSRijo Thomas #include <linux/mutex.h>
1333960accSRijo Thomas #include <linux/delay.h>
1433960accSRijo Thomas #include <linux/slab.h>
1533960accSRijo Thomas #include <linux/gfp.h>
1633960accSRijo Thomas #include <linux/psp-sev.h>
17632b0b53SRijo Thomas #include <linux/psp-tee.h>
1833960accSRijo Thomas 
1933960accSRijo Thomas #include "psp-dev.h"
2033960accSRijo Thomas #include "tee-dev.h"
2133960accSRijo Thomas 
2233960accSRijo Thomas static bool psp_dead;
2333960accSRijo Thomas 
2433960accSRijo Thomas static int tee_alloc_ring(struct psp_tee_device *tee, int ring_size)
2533960accSRijo Thomas {
2633960accSRijo Thomas 	struct ring_buf_manager *rb_mgr = &tee->rb_mgr;
2733960accSRijo Thomas 	void *start_addr;
2833960accSRijo Thomas 
2933960accSRijo Thomas 	if (!ring_size)
3033960accSRijo Thomas 		return -EINVAL;
3133960accSRijo Thomas 
3233960accSRijo Thomas 	/* We need actual physical address instead of DMA address, since
3333960accSRijo Thomas 	 * Trusted OS running on AMD Secure Processor will map this region
3433960accSRijo Thomas 	 */
3533960accSRijo Thomas 	start_addr = (void *)__get_free_pages(GFP_KERNEL, get_order(ring_size));
3633960accSRijo Thomas 	if (!start_addr)
3733960accSRijo Thomas 		return -ENOMEM;
3833960accSRijo Thomas 
3933960accSRijo Thomas 	rb_mgr->ring_start = start_addr;
4033960accSRijo Thomas 	rb_mgr->ring_size = ring_size;
4133960accSRijo Thomas 	rb_mgr->ring_pa = __psp_pa(start_addr);
42632b0b53SRijo Thomas 	mutex_init(&rb_mgr->mutex);
4333960accSRijo Thomas 
4433960accSRijo Thomas 	return 0;
4533960accSRijo Thomas }
4633960accSRijo Thomas 
4733960accSRijo Thomas static void tee_free_ring(struct psp_tee_device *tee)
4833960accSRijo Thomas {
4933960accSRijo Thomas 	struct ring_buf_manager *rb_mgr = &tee->rb_mgr;
5033960accSRijo Thomas 
5133960accSRijo Thomas 	if (!rb_mgr->ring_start)
5233960accSRijo Thomas 		return;
5333960accSRijo Thomas 
5433960accSRijo Thomas 	free_pages((unsigned long)rb_mgr->ring_start,
5533960accSRijo Thomas 		   get_order(rb_mgr->ring_size));
5633960accSRijo Thomas 
5733960accSRijo Thomas 	rb_mgr->ring_start = NULL;
5833960accSRijo Thomas 	rb_mgr->ring_size = 0;
5933960accSRijo Thomas 	rb_mgr->ring_pa = 0;
60632b0b53SRijo Thomas 	mutex_destroy(&rb_mgr->mutex);
6133960accSRijo Thomas }
6233960accSRijo Thomas 
6333960accSRijo Thomas static int tee_wait_cmd_poll(struct psp_tee_device *tee, unsigned int timeout,
6433960accSRijo Thomas 			     unsigned int *reg)
6533960accSRijo Thomas {
6633960accSRijo Thomas 	/* ~10ms sleep per loop => nloop = timeout * 100 */
6733960accSRijo Thomas 	int nloop = timeout * 100;
6833960accSRijo Thomas 
6933960accSRijo Thomas 	while (--nloop) {
7033960accSRijo Thomas 		*reg = ioread32(tee->io_regs + tee->vdata->cmdresp_reg);
7133960accSRijo Thomas 		if (*reg & PSP_CMDRESP_RESP)
7233960accSRijo Thomas 			return 0;
7333960accSRijo Thomas 
7433960accSRijo Thomas 		usleep_range(10000, 10100);
7533960accSRijo Thomas 	}
7633960accSRijo Thomas 
7733960accSRijo Thomas 	dev_err(tee->dev, "tee: command timed out, disabling PSP\n");
7833960accSRijo Thomas 	psp_dead = true;
7933960accSRijo Thomas 
8033960accSRijo Thomas 	return -ETIMEDOUT;
8133960accSRijo Thomas }
8233960accSRijo Thomas 
8333960accSRijo Thomas static
8433960accSRijo Thomas struct tee_init_ring_cmd *tee_alloc_cmd_buffer(struct psp_tee_device *tee)
8533960accSRijo Thomas {
8633960accSRijo Thomas 	struct tee_init_ring_cmd *cmd;
8733960accSRijo Thomas 
8833960accSRijo Thomas 	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
8933960accSRijo Thomas 	if (!cmd)
9033960accSRijo Thomas 		return NULL;
9133960accSRijo Thomas 
9233960accSRijo Thomas 	cmd->hi_addr = upper_32_bits(tee->rb_mgr.ring_pa);
9333960accSRijo Thomas 	cmd->low_addr = lower_32_bits(tee->rb_mgr.ring_pa);
9433960accSRijo Thomas 	cmd->size = tee->rb_mgr.ring_size;
9533960accSRijo Thomas 
9633960accSRijo Thomas 	dev_dbg(tee->dev, "tee: ring address: high = 0x%x low = 0x%x size = %u\n",
9733960accSRijo Thomas 		cmd->hi_addr, cmd->low_addr, cmd->size);
9833960accSRijo Thomas 
9933960accSRijo Thomas 	return cmd;
10033960accSRijo Thomas }
10133960accSRijo Thomas 
10233960accSRijo Thomas static inline void tee_free_cmd_buffer(struct tee_init_ring_cmd *cmd)
10333960accSRijo Thomas {
10433960accSRijo Thomas 	kfree(cmd);
10533960accSRijo Thomas }
10633960accSRijo Thomas 
10733960accSRijo Thomas static int tee_init_ring(struct psp_tee_device *tee)
10833960accSRijo Thomas {
10933960accSRijo Thomas 	int ring_size = MAX_RING_BUFFER_ENTRIES * sizeof(struct tee_ring_cmd);
11033960accSRijo Thomas 	struct tee_init_ring_cmd *cmd;
11133960accSRijo Thomas 	phys_addr_t cmd_buffer;
11233960accSRijo Thomas 	unsigned int reg;
11333960accSRijo Thomas 	int ret;
11433960accSRijo Thomas 
11533960accSRijo Thomas 	BUILD_BUG_ON(sizeof(struct tee_ring_cmd) != 1024);
11633960accSRijo Thomas 
11733960accSRijo Thomas 	ret = tee_alloc_ring(tee, ring_size);
11833960accSRijo Thomas 	if (ret) {
11933960accSRijo Thomas 		dev_err(tee->dev, "tee: ring allocation failed %d\n", ret);
12033960accSRijo Thomas 		return ret;
12133960accSRijo Thomas 	}
12233960accSRijo Thomas 
12333960accSRijo Thomas 	tee->rb_mgr.wptr = 0;
12433960accSRijo Thomas 
12533960accSRijo Thomas 	cmd = tee_alloc_cmd_buffer(tee);
12633960accSRijo Thomas 	if (!cmd) {
12733960accSRijo Thomas 		tee_free_ring(tee);
12833960accSRijo Thomas 		return -ENOMEM;
12933960accSRijo Thomas 	}
13033960accSRijo Thomas 
13133960accSRijo Thomas 	cmd_buffer = __psp_pa((void *)cmd);
13233960accSRijo Thomas 
13333960accSRijo Thomas 	/* Send command buffer details to Trusted OS by writing to
13433960accSRijo Thomas 	 * CPU-PSP message registers
13533960accSRijo Thomas 	 */
13633960accSRijo Thomas 
13733960accSRijo Thomas 	iowrite32(lower_32_bits(cmd_buffer),
13833960accSRijo Thomas 		  tee->io_regs + tee->vdata->cmdbuff_addr_lo_reg);
13933960accSRijo Thomas 	iowrite32(upper_32_bits(cmd_buffer),
14033960accSRijo Thomas 		  tee->io_regs + tee->vdata->cmdbuff_addr_hi_reg);
14133960accSRijo Thomas 	iowrite32(TEE_RING_INIT_CMD,
14233960accSRijo Thomas 		  tee->io_regs + tee->vdata->cmdresp_reg);
14333960accSRijo Thomas 
14433960accSRijo Thomas 	ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, &reg);
14533960accSRijo Thomas 	if (ret) {
14633960accSRijo Thomas 		dev_err(tee->dev, "tee: ring init command timed out\n");
14733960accSRijo Thomas 		tee_free_ring(tee);
14833960accSRijo Thomas 		goto free_buf;
14933960accSRijo Thomas 	}
15033960accSRijo Thomas 
15133960accSRijo Thomas 	if (reg & PSP_CMDRESP_ERR_MASK) {
15233960accSRijo Thomas 		dev_err(tee->dev, "tee: ring init command failed (%#010x)\n",
15333960accSRijo Thomas 			reg & PSP_CMDRESP_ERR_MASK);
15433960accSRijo Thomas 		tee_free_ring(tee);
15533960accSRijo Thomas 		ret = -EIO;
15633960accSRijo Thomas 	}
15733960accSRijo Thomas 
15833960accSRijo Thomas free_buf:
15933960accSRijo Thomas 	tee_free_cmd_buffer(cmd);
16033960accSRijo Thomas 
16133960accSRijo Thomas 	return ret;
16233960accSRijo Thomas }
16333960accSRijo Thomas 
16433960accSRijo Thomas static void tee_destroy_ring(struct psp_tee_device *tee)
16533960accSRijo Thomas {
16633960accSRijo Thomas 	unsigned int reg;
16733960accSRijo Thomas 	int ret;
16833960accSRijo Thomas 
16933960accSRijo Thomas 	if (!tee->rb_mgr.ring_start)
17033960accSRijo Thomas 		return;
17133960accSRijo Thomas 
17233960accSRijo Thomas 	if (psp_dead)
17333960accSRijo Thomas 		goto free_ring;
17433960accSRijo Thomas 
17533960accSRijo Thomas 	iowrite32(TEE_RING_DESTROY_CMD,
17633960accSRijo Thomas 		  tee->io_regs + tee->vdata->cmdresp_reg);
17733960accSRijo Thomas 
17833960accSRijo Thomas 	ret = tee_wait_cmd_poll(tee, TEE_DEFAULT_TIMEOUT, &reg);
17933960accSRijo Thomas 	if (ret) {
18033960accSRijo Thomas 		dev_err(tee->dev, "tee: ring destroy command timed out\n");
18133960accSRijo Thomas 	} else if (reg & PSP_CMDRESP_ERR_MASK) {
18233960accSRijo Thomas 		dev_err(tee->dev, "tee: ring destroy command failed (%#010x)\n",
18333960accSRijo Thomas 			reg & PSP_CMDRESP_ERR_MASK);
18433960accSRijo Thomas 	}
18533960accSRijo Thomas 
18633960accSRijo Thomas free_ring:
18733960accSRijo Thomas 	tee_free_ring(tee);
18833960accSRijo Thomas }
18933960accSRijo Thomas 
19033960accSRijo Thomas int tee_dev_init(struct psp_device *psp)
19133960accSRijo Thomas {
19233960accSRijo Thomas 	struct device *dev = psp->dev;
19333960accSRijo Thomas 	struct psp_tee_device *tee;
19433960accSRijo Thomas 	int ret;
19533960accSRijo Thomas 
19633960accSRijo Thomas 	ret = -ENOMEM;
19733960accSRijo Thomas 	tee = devm_kzalloc(dev, sizeof(*tee), GFP_KERNEL);
19833960accSRijo Thomas 	if (!tee)
19933960accSRijo Thomas 		goto e_err;
20033960accSRijo Thomas 
20133960accSRijo Thomas 	psp->tee_data = tee;
20233960accSRijo Thomas 
20333960accSRijo Thomas 	tee->dev = dev;
20433960accSRijo Thomas 	tee->psp = psp;
20533960accSRijo Thomas 
20633960accSRijo Thomas 	tee->io_regs = psp->io_regs;
20733960accSRijo Thomas 
20833960accSRijo Thomas 	tee->vdata = (struct tee_vdata *)psp->vdata->tee;
20933960accSRijo Thomas 	if (!tee->vdata) {
21033960accSRijo Thomas 		ret = -ENODEV;
21133960accSRijo Thomas 		dev_err(dev, "tee: missing driver data\n");
21233960accSRijo Thomas 		goto e_err;
21333960accSRijo Thomas 	}
21433960accSRijo Thomas 
21533960accSRijo Thomas 	ret = tee_init_ring(tee);
21633960accSRijo Thomas 	if (ret) {
21733960accSRijo Thomas 		dev_err(dev, "tee: failed to init ring buffer\n");
21833960accSRijo Thomas 		goto e_err;
21933960accSRijo Thomas 	}
22033960accSRijo Thomas 
22133960accSRijo Thomas 	dev_notice(dev, "tee enabled\n");
22233960accSRijo Thomas 
22333960accSRijo Thomas 	return 0;
22433960accSRijo Thomas 
22533960accSRijo Thomas e_err:
22633960accSRijo Thomas 	psp->tee_data = NULL;
22733960accSRijo Thomas 
22833960accSRijo Thomas 	dev_notice(dev, "tee initialization failed\n");
22933960accSRijo Thomas 
23033960accSRijo Thomas 	return ret;
23133960accSRijo Thomas }
23233960accSRijo Thomas 
23333960accSRijo Thomas void tee_dev_destroy(struct psp_device *psp)
23433960accSRijo Thomas {
23533960accSRijo Thomas 	struct psp_tee_device *tee = psp->tee_data;
23633960accSRijo Thomas 
23733960accSRijo Thomas 	if (!tee)
23833960accSRijo Thomas 		return;
23933960accSRijo Thomas 
24033960accSRijo Thomas 	tee_destroy_ring(tee);
24133960accSRijo Thomas }
242632b0b53SRijo Thomas 
243632b0b53SRijo Thomas static int tee_submit_cmd(struct psp_tee_device *tee, enum tee_cmd_id cmd_id,
244632b0b53SRijo Thomas 			  void *buf, size_t len, struct tee_ring_cmd **resp)
245632b0b53SRijo Thomas {
246632b0b53SRijo Thomas 	struct tee_ring_cmd *cmd;
247632b0b53SRijo Thomas 	u32 rptr, wptr;
248632b0b53SRijo Thomas 	int nloop = 1000, ret = 0;
249632b0b53SRijo Thomas 
250632b0b53SRijo Thomas 	*resp = NULL;
251632b0b53SRijo Thomas 
252632b0b53SRijo Thomas 	mutex_lock(&tee->rb_mgr.mutex);
253632b0b53SRijo Thomas 
254632b0b53SRijo Thomas 	wptr = tee->rb_mgr.wptr;
255632b0b53SRijo Thomas 
256632b0b53SRijo Thomas 	/* Check if ring buffer is full */
257632b0b53SRijo Thomas 	do {
258632b0b53SRijo Thomas 		rptr = ioread32(tee->io_regs + tee->vdata->ring_rptr_reg);
259632b0b53SRijo Thomas 
260632b0b53SRijo Thomas 		if (!(wptr + sizeof(struct tee_ring_cmd) == rptr))
261632b0b53SRijo Thomas 			break;
262632b0b53SRijo Thomas 
263632b0b53SRijo Thomas 		dev_info(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n",
264632b0b53SRijo Thomas 			 rptr, wptr);
265632b0b53SRijo Thomas 
266632b0b53SRijo Thomas 		/* Wait if ring buffer is full */
267632b0b53SRijo Thomas 		mutex_unlock(&tee->rb_mgr.mutex);
268632b0b53SRijo Thomas 		schedule_timeout_interruptible(msecs_to_jiffies(10));
269632b0b53SRijo Thomas 		mutex_lock(&tee->rb_mgr.mutex);
270632b0b53SRijo Thomas 
271632b0b53SRijo Thomas 	} while (--nloop);
272632b0b53SRijo Thomas 
273632b0b53SRijo Thomas 	if (!nloop && (wptr + sizeof(struct tee_ring_cmd) == rptr)) {
274632b0b53SRijo Thomas 		dev_err(tee->dev, "tee: ring buffer full. rptr = %u wptr = %u\n",
275632b0b53SRijo Thomas 			rptr, wptr);
276632b0b53SRijo Thomas 		ret = -EBUSY;
277632b0b53SRijo Thomas 		goto unlock;
278632b0b53SRijo Thomas 	}
279632b0b53SRijo Thomas 
280632b0b53SRijo Thomas 	/* Pointer to empty data entry in ring buffer */
281632b0b53SRijo Thomas 	cmd = (struct tee_ring_cmd *)(tee->rb_mgr.ring_start + wptr);
282632b0b53SRijo Thomas 
283632b0b53SRijo Thomas 	/* Write command data into ring buffer */
284632b0b53SRijo Thomas 	cmd->cmd_id = cmd_id;
285632b0b53SRijo Thomas 	cmd->cmd_state = TEE_CMD_STATE_INIT;
286632b0b53SRijo Thomas 	memset(&cmd->buf[0], 0, sizeof(cmd->buf));
287632b0b53SRijo Thomas 	memcpy(&cmd->buf[0], buf, len);
288632b0b53SRijo Thomas 
289632b0b53SRijo Thomas 	/* Update local copy of write pointer */
290632b0b53SRijo Thomas 	tee->rb_mgr.wptr += sizeof(struct tee_ring_cmd);
291632b0b53SRijo Thomas 	if (tee->rb_mgr.wptr >= tee->rb_mgr.ring_size)
292632b0b53SRijo Thomas 		tee->rb_mgr.wptr = 0;
293632b0b53SRijo Thomas 
294632b0b53SRijo Thomas 	/* Trigger interrupt to Trusted OS */
295632b0b53SRijo Thomas 	iowrite32(tee->rb_mgr.wptr, tee->io_regs + tee->vdata->ring_wptr_reg);
296632b0b53SRijo Thomas 
297632b0b53SRijo Thomas 	/* The response is provided by Trusted OS in same
298632b0b53SRijo Thomas 	 * location as submitted data entry within ring buffer.
299632b0b53SRijo Thomas 	 */
300632b0b53SRijo Thomas 	*resp = cmd;
301632b0b53SRijo Thomas 
302632b0b53SRijo Thomas unlock:
303632b0b53SRijo Thomas 	mutex_unlock(&tee->rb_mgr.mutex);
304632b0b53SRijo Thomas 
305632b0b53SRijo Thomas 	return ret;
306632b0b53SRijo Thomas }
307632b0b53SRijo Thomas 
308632b0b53SRijo Thomas static int tee_wait_cmd_completion(struct psp_tee_device *tee,
309632b0b53SRijo Thomas 				   struct tee_ring_cmd *resp,
310632b0b53SRijo Thomas 				   unsigned int timeout)
311632b0b53SRijo Thomas {
312632b0b53SRijo Thomas 	/* ~5ms sleep per loop => nloop = timeout * 200 */
313632b0b53SRijo Thomas 	int nloop = timeout * 200;
314632b0b53SRijo Thomas 
315632b0b53SRijo Thomas 	while (--nloop) {
316632b0b53SRijo Thomas 		if (resp->cmd_state == TEE_CMD_STATE_COMPLETED)
317632b0b53SRijo Thomas 			return 0;
318632b0b53SRijo Thomas 
319632b0b53SRijo Thomas 		usleep_range(5000, 5100);
320632b0b53SRijo Thomas 	}
321632b0b53SRijo Thomas 
322632b0b53SRijo Thomas 	dev_err(tee->dev, "tee: command 0x%x timed out, disabling PSP\n",
323632b0b53SRijo Thomas 		resp->cmd_id);
324632b0b53SRijo Thomas 
325632b0b53SRijo Thomas 	psp_dead = true;
326632b0b53SRijo Thomas 
327632b0b53SRijo Thomas 	return -ETIMEDOUT;
328632b0b53SRijo Thomas }
329632b0b53SRijo Thomas 
330632b0b53SRijo Thomas int psp_tee_process_cmd(enum tee_cmd_id cmd_id, void *buf, size_t len,
331632b0b53SRijo Thomas 			u32 *status)
332632b0b53SRijo Thomas {
333632b0b53SRijo Thomas 	struct psp_device *psp = psp_get_master_device();
334632b0b53SRijo Thomas 	struct psp_tee_device *tee;
335632b0b53SRijo Thomas 	struct tee_ring_cmd *resp;
336632b0b53SRijo Thomas 	int ret;
337632b0b53SRijo Thomas 
338632b0b53SRijo Thomas 	if (!buf || !status || !len || len > sizeof(resp->buf))
339632b0b53SRijo Thomas 		return -EINVAL;
340632b0b53SRijo Thomas 
341632b0b53SRijo Thomas 	*status = 0;
342632b0b53SRijo Thomas 
343632b0b53SRijo Thomas 	if (!psp || !psp->tee_data)
344632b0b53SRijo Thomas 		return -ENODEV;
345632b0b53SRijo Thomas 
346632b0b53SRijo Thomas 	if (psp_dead)
347632b0b53SRijo Thomas 		return -EBUSY;
348632b0b53SRijo Thomas 
349632b0b53SRijo Thomas 	tee = psp->tee_data;
350632b0b53SRijo Thomas 
351632b0b53SRijo Thomas 	ret = tee_submit_cmd(tee, cmd_id, buf, len, &resp);
352632b0b53SRijo Thomas 	if (ret)
353632b0b53SRijo Thomas 		return ret;
354632b0b53SRijo Thomas 
355632b0b53SRijo Thomas 	ret = tee_wait_cmd_completion(tee, resp, TEE_DEFAULT_TIMEOUT);
356632b0b53SRijo Thomas 	if (ret)
357632b0b53SRijo Thomas 		return ret;
358632b0b53SRijo Thomas 
359632b0b53SRijo Thomas 	memcpy(buf, &resp->buf[0], len);
360632b0b53SRijo Thomas 	*status = resp->status;
361632b0b53SRijo Thomas 
362632b0b53SRijo Thomas 	return 0;
363632b0b53SRijo Thomas }
364632b0b53SRijo Thomas EXPORT_SYMBOL(psp_tee_process_cmd);
365*bade7e1fSRijo Thomas 
366*bade7e1fSRijo Thomas int psp_check_tee_status(void)
367*bade7e1fSRijo Thomas {
368*bade7e1fSRijo Thomas 	struct psp_device *psp = psp_get_master_device();
369*bade7e1fSRijo Thomas 
370*bade7e1fSRijo Thomas 	if (!psp || !psp->tee_data)
371*bade7e1fSRijo Thomas 		return -ENODEV;
372*bade7e1fSRijo Thomas 
373*bade7e1fSRijo Thomas 	return 0;
374*bade7e1fSRijo Thomas }
375*bade7e1fSRijo Thomas EXPORT_SYMBOL(psp_check_tee_status);
376