Skip to content

Commit

Permalink
crypto: ccp - add timeout support in the SEV command
Browse files Browse the repository at this point in the history
Currently, the CCP driver assumes that the SEV command issued to the PSP
will always return (i.e. it will never hang).  But recently, firmware bugs
have shown that a command can hang.  Since of the SEV commands are used
in probe routines, this can cause boot hangs and/or loss of virtualization
capabilities.

To protect against firmware bugs, add a timeout in the SEV command
execution flow.  If a command does not complete within the specified
timeout then return -ETIMEOUT and stop the driver from executing any
further commands since the state of the SEV firmware is unknown.

Cc: Tom Lendacky <[email protected]>
Cc: Gary Hook <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: [email protected]
Signed-off-by: Brijesh Singh <[email protected]>
Signed-off-by: Herbert Xu <[email protected]>
  • Loading branch information
codomania authored and herbertx committed Sep 13, 2018
1 parent 5736184 commit 3702a05
Showing 1 changed file with 41 additions and 5 deletions.
46 changes: 41 additions & 5 deletions drivers/crypto/ccp/psp-dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ static DEFINE_MUTEX(sev_cmd_mutex);
static struct sev_misc_dev *misc_dev;
static struct psp_device *psp_master;

static int psp_cmd_timeout = 100;
module_param(psp_cmd_timeout, int, 0644);
MODULE_PARM_DESC(psp_cmd_timeout, " default timeout value, in seconds, for PSP commands");

static int psp_probe_timeout = 5;
module_param(psp_probe_timeout, int, 0644);
MODULE_PARM_DESC(psp_probe_timeout, " default timeout value, in seconds, during PSP device probe");

static bool psp_dead;
static int psp_timeout;

static struct psp_device *psp_alloc_struct(struct sp_device *sp)
{
struct device *dev = sp->dev;
Expand Down Expand Up @@ -82,10 +93,19 @@ static irqreturn_t psp_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}

static void sev_wait_cmd_ioc(struct psp_device *psp, unsigned int *reg)
static int sev_wait_cmd_ioc(struct psp_device *psp,
unsigned int *reg, unsigned int timeout)
{
wait_event(psp->sev_int_queue, psp->sev_int_rcvd);
int ret;

ret = wait_event_timeout(psp->sev_int_queue,
psp->sev_int_rcvd, timeout * HZ);
if (!ret)
return -ETIMEDOUT;

*reg = ioread32(psp->io_regs + psp->vdata->cmdresp_reg);

return 0;
}

static int sev_cmd_buffer_len(int cmd)
Expand Down Expand Up @@ -133,12 +153,15 @@ static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret)
if (!psp)
return -ENODEV;

if (psp_dead)
return -EBUSY;

/* Get the physical address of the command buffer */
phys_lsb = data ? lower_32_bits(__psp_pa(data)) : 0;
phys_msb = data ? upper_32_bits(__psp_pa(data)) : 0;

dev_dbg(psp->dev, "sev command id %#x buffer 0x%08x%08x\n",
cmd, phys_msb, phys_lsb);
dev_dbg(psp->dev, "sev command id %#x buffer 0x%08x%08x timeout %us\n",
cmd, phys_msb, phys_lsb, psp_timeout);

print_hex_dump_debug("(in): ", DUMP_PREFIX_OFFSET, 16, 2, data,
sev_cmd_buffer_len(cmd), false);
Expand All @@ -154,7 +177,18 @@ static int __sev_do_cmd_locked(int cmd, void *data, int *psp_ret)
iowrite32(reg, psp->io_regs + psp->vdata->cmdresp_reg);

/* wait for command completion */
sev_wait_cmd_ioc(psp, &reg);
ret = sev_wait_cmd_ioc(psp, &reg, psp_timeout);
if (ret) {
if (psp_ret)
*psp_ret = 0;

dev_err(psp->dev, "sev command %#x timed out, disabling PSP \n", cmd);
psp_dead = true;

return ret;
}

psp_timeout = psp_cmd_timeout;

if (psp_ret)
*psp_ret = reg & PSP_CMDRESP_ERR_MASK;
Expand Down Expand Up @@ -888,6 +922,8 @@ void psp_pci_init(void)

psp_master = sp->psp_data;

psp_timeout = psp_probe_timeout;

if (sev_get_api_version())
goto err;

Expand Down

0 comments on commit 3702a05

Please sign in to comment.