xref: /openbmc/linux/drivers/char/tpm/tpm-interface.c (revision b2d6e6de005edf5f2f46b7abacb69a0a1ce75c23)
19deb0eb7SJason Gunthorpe /*
29deb0eb7SJason Gunthorpe  * Copyright (C) 2004 IBM Corporation
3afb5abc2SJarkko Sakkinen  * Copyright (C) 2014 Intel Corporation
49deb0eb7SJason Gunthorpe  *
59deb0eb7SJason Gunthorpe  * Authors:
69deb0eb7SJason Gunthorpe  * Leendert van Doorn <leendert@watson.ibm.com>
79deb0eb7SJason Gunthorpe  * Dave Safford <safford@watson.ibm.com>
89deb0eb7SJason Gunthorpe  * Reiner Sailer <sailer@watson.ibm.com>
99deb0eb7SJason Gunthorpe  * Kylene Hall <kjhall@us.ibm.com>
109deb0eb7SJason Gunthorpe  *
119deb0eb7SJason Gunthorpe  * Maintained by: <tpmdd-devel@lists.sourceforge.net>
129deb0eb7SJason Gunthorpe  *
139deb0eb7SJason Gunthorpe  * Device driver for TCG/TCPA TPM (trusted platform module).
149deb0eb7SJason Gunthorpe  * Specifications at www.trustedcomputinggroup.org
159deb0eb7SJason Gunthorpe  *
169deb0eb7SJason Gunthorpe  * This program is free software; you can redistribute it and/or
179deb0eb7SJason Gunthorpe  * modify it under the terms of the GNU General Public License as
189deb0eb7SJason Gunthorpe  * published by the Free Software Foundation, version 2 of the
199deb0eb7SJason Gunthorpe  * License.
209deb0eb7SJason Gunthorpe  *
219deb0eb7SJason Gunthorpe  * Note, the TPM chip is not interrupt driven (only polling)
229deb0eb7SJason Gunthorpe  * and can have very long timeouts (minutes!). Hence the unusual
239deb0eb7SJason Gunthorpe  * calls to msleep.
249deb0eb7SJason Gunthorpe  *
259deb0eb7SJason Gunthorpe  */
269deb0eb7SJason Gunthorpe 
279deb0eb7SJason Gunthorpe #include <linux/poll.h>
289deb0eb7SJason Gunthorpe #include <linux/slab.h>
299deb0eb7SJason Gunthorpe #include <linux/mutex.h>
309deb0eb7SJason Gunthorpe #include <linux/spinlock.h>
319deb0eb7SJason Gunthorpe #include <linux/freezer.h>
32fd3ec366SThiebaud Weksteen #include <linux/tpm_eventlog.h>
339deb0eb7SJason Gunthorpe 
349deb0eb7SJason Gunthorpe #include "tpm.h"
359deb0eb7SJason Gunthorpe 
369deb0eb7SJason Gunthorpe #define TSC_MAX_ORDINAL 12
379deb0eb7SJason Gunthorpe #define TPM_PROTECTED_COMMAND 0x00
389deb0eb7SJason Gunthorpe #define TPM_CONNECTION_COMMAND 0x40
399deb0eb7SJason Gunthorpe 
409deb0eb7SJason Gunthorpe /*
419deb0eb7SJason Gunthorpe  * Bug workaround - some TPM's don't flush the most
429deb0eb7SJason Gunthorpe  * recently changed pcr on suspend, so force the flush
439deb0eb7SJason Gunthorpe  * with an extend to the selected _unused_ non-volatile pcr.
449deb0eb7SJason Gunthorpe  */
459deb0eb7SJason Gunthorpe static int tpm_suspend_pcr;
469deb0eb7SJason Gunthorpe module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644);
479deb0eb7SJason Gunthorpe MODULE_PARM_DESC(suspend_pcr,
4839f5712bSDmitry Torokhov 		 "PCR to use for dummy writes to facilitate flush on suspend.");
499deb0eb7SJason Gunthorpe 
50095531f8SJavier Martinez Canillas static int tpm_validate_command(struct tpm_chip *chip,
51745b361eSJarkko Sakkinen 				 struct tpm_space *space,
52745b361eSJarkko Sakkinen 				 const u8 *cmd,
5358472f5cSJarkko Sakkinen 				 size_t len)
5458472f5cSJarkko Sakkinen {
5558472f5cSJarkko Sakkinen 	const struct tpm_input_header *header = (const void *)cmd;
5658472f5cSJarkko Sakkinen 	int i;
5758472f5cSJarkko Sakkinen 	u32 cc;
5858472f5cSJarkko Sakkinen 	u32 attrs;
5958472f5cSJarkko Sakkinen 	unsigned int nr_handles;
6058472f5cSJarkko Sakkinen 
6158472f5cSJarkko Sakkinen 	if (len < TPM_HEADER_SIZE)
62095531f8SJavier Martinez Canillas 		return -EINVAL;
6358472f5cSJarkko Sakkinen 
64745b361eSJarkko Sakkinen 	if (!space)
65095531f8SJavier Martinez Canillas 		return 0;
66745b361eSJarkko Sakkinen 
6758472f5cSJarkko Sakkinen 	if (chip->flags & TPM_CHIP_FLAG_TPM2 && chip->nr_commands) {
6858472f5cSJarkko Sakkinen 		cc = be32_to_cpu(header->ordinal);
6958472f5cSJarkko Sakkinen 
7058472f5cSJarkko Sakkinen 		i = tpm2_find_cc(chip, cc);
7158472f5cSJarkko Sakkinen 		if (i < 0) {
7258472f5cSJarkko Sakkinen 			dev_dbg(&chip->dev, "0x%04X is an invalid command\n",
7358472f5cSJarkko Sakkinen 				cc);
74095531f8SJavier Martinez Canillas 			return -EOPNOTSUPP;
7558472f5cSJarkko Sakkinen 		}
7658472f5cSJarkko Sakkinen 
7758472f5cSJarkko Sakkinen 		attrs = chip->cc_attrs_tbl[i];
7858472f5cSJarkko Sakkinen 		nr_handles =
7958472f5cSJarkko Sakkinen 			4 * ((attrs >> TPM2_CC_ATTR_CHANDLES) & GENMASK(2, 0));
8058472f5cSJarkko Sakkinen 		if (len < TPM_HEADER_SIZE + 4 * nr_handles)
8158472f5cSJarkko Sakkinen 			goto err_len;
8258472f5cSJarkko Sakkinen 	}
8358472f5cSJarkko Sakkinen 
84095531f8SJavier Martinez Canillas 	return 0;
8558472f5cSJarkko Sakkinen err_len:
8658472f5cSJarkko Sakkinen 	dev_dbg(&chip->dev,
8758472f5cSJarkko Sakkinen 		"%s: insufficient command length %zu", __func__, len);
88095531f8SJavier Martinez Canillas 	return -EINVAL;
8958472f5cSJarkko Sakkinen }
9058472f5cSJarkko Sakkinen 
91627448e8STomas Winkler static int tpm_request_locality(struct tpm_chip *chip, unsigned int flags)
92888d867dSTomas Winkler {
93888d867dSTomas Winkler 	int rc;
94888d867dSTomas Winkler 
9558bac8ccSJarkko Sakkinen 	if (flags & TPM_TRANSMIT_NESTED)
96627448e8STomas Winkler 		return 0;
97627448e8STomas Winkler 
98888d867dSTomas Winkler 	if (!chip->ops->request_locality)
99888d867dSTomas Winkler 		return 0;
100888d867dSTomas Winkler 
101888d867dSTomas Winkler 	rc = chip->ops->request_locality(chip, 0);
102888d867dSTomas Winkler 	if (rc < 0)
103888d867dSTomas Winkler 		return rc;
104888d867dSTomas Winkler 
105888d867dSTomas Winkler 	chip->locality = rc;
106888d867dSTomas Winkler 
107888d867dSTomas Winkler 	return 0;
108888d867dSTomas Winkler }
109888d867dSTomas Winkler 
110627448e8STomas Winkler static void tpm_relinquish_locality(struct tpm_chip *chip, unsigned int flags)
111888d867dSTomas Winkler {
112888d867dSTomas Winkler 	int rc;
113888d867dSTomas Winkler 
11458bac8ccSJarkko Sakkinen 	if (flags & TPM_TRANSMIT_NESTED)
115627448e8STomas Winkler 		return;
116627448e8STomas Winkler 
117888d867dSTomas Winkler 	if (!chip->ops->relinquish_locality)
118888d867dSTomas Winkler 		return;
119888d867dSTomas Winkler 
120888d867dSTomas Winkler 	rc = chip->ops->relinquish_locality(chip, chip->locality);
121888d867dSTomas Winkler 	if (rc)
122888d867dSTomas Winkler 		dev_err(&chip->dev, "%s: : error %d\n", __func__, rc);
123888d867dSTomas Winkler 
124888d867dSTomas Winkler 	chip->locality = -1;
125888d867dSTomas Winkler }
126888d867dSTomas Winkler 
127627448e8STomas Winkler static int tpm_cmd_ready(struct tpm_chip *chip, unsigned int flags)
128627448e8STomas Winkler {
12958bac8ccSJarkko Sakkinen 	if (flags & TPM_TRANSMIT_NESTED)
130627448e8STomas Winkler 		return 0;
131627448e8STomas Winkler 
132627448e8STomas Winkler 	if (!chip->ops->cmd_ready)
133627448e8STomas Winkler 		return 0;
134627448e8STomas Winkler 
135627448e8STomas Winkler 	return chip->ops->cmd_ready(chip);
136627448e8STomas Winkler }
137627448e8STomas Winkler 
138627448e8STomas Winkler static int tpm_go_idle(struct tpm_chip *chip, unsigned int flags)
139627448e8STomas Winkler {
14058bac8ccSJarkko Sakkinen 	if (flags & TPM_TRANSMIT_NESTED)
141627448e8STomas Winkler 		return 0;
142627448e8STomas Winkler 
143627448e8STomas Winkler 	if (!chip->ops->go_idle)
144627448e8STomas Winkler 		return 0;
145627448e8STomas Winkler 
146627448e8STomas Winkler 	return chip->ops->go_idle(chip);
147627448e8STomas Winkler }
148627448e8STomas Winkler 
149e2fb992dSJames Bottomley static ssize_t tpm_try_transmit(struct tpm_chip *chip,
150e2fb992dSJames Bottomley 				struct tpm_space *space,
151e2fb992dSJames Bottomley 				u8 *buf, size_t bufsiz,
152e2fb992dSJames Bottomley 				unsigned int flags)
1539deb0eb7SJason Gunthorpe {
154745b361eSJarkko Sakkinen 	struct tpm_output_header *header = (void *)buf;
155745b361eSJarkko Sakkinen 	int rc;
156745b361eSJarkko Sakkinen 	ssize_t len = 0;
1579deb0eb7SJason Gunthorpe 	u32 count, ordinal;
1589deb0eb7SJason Gunthorpe 	unsigned long stop;
159877c57d0SJarkko Sakkinen 	bool need_locality;
1609deb0eb7SJason Gunthorpe 
161095531f8SJavier Martinez Canillas 	rc = tpm_validate_command(chip, space, buf, bufsiz);
162095531f8SJavier Martinez Canillas 	if (rc == -EINVAL)
163095531f8SJavier Martinez Canillas 		return rc;
164095531f8SJavier Martinez Canillas 	/*
165095531f8SJavier Martinez Canillas 	 * If the command is not implemented by the TPM, synthesize a
166095531f8SJavier Martinez Canillas 	 * response with a TPM2_RC_COMMAND_CODE return for user-space.
167095531f8SJavier Martinez Canillas 	 */
168095531f8SJavier Martinez Canillas 	if (rc == -EOPNOTSUPP) {
169095531f8SJavier Martinez Canillas 		header->length = cpu_to_be32(sizeof(*header));
170095531f8SJavier Martinez Canillas 		header->tag = cpu_to_be16(TPM2_ST_NO_SESSIONS);
171095531f8SJavier Martinez Canillas 		header->return_code = cpu_to_be32(TPM2_RC_COMMAND_CODE |
172095531f8SJavier Martinez Canillas 						  TSS2_RESMGR_TPM_RC_LAYER);
17336a11029SRicardo Schwarzmeier 		return sizeof(*header);
174095531f8SJavier Martinez Canillas 	}
175ebfd7532SJarkko Sakkinen 
1769deb0eb7SJason Gunthorpe 	if (bufsiz > TPM_BUFSIZE)
1779deb0eb7SJason Gunthorpe 		bufsiz = TPM_BUFSIZE;
1789deb0eb7SJason Gunthorpe 
1799deb0eb7SJason Gunthorpe 	count = be32_to_cpu(*((__be32 *) (buf + 2)));
1809deb0eb7SJason Gunthorpe 	ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
1819deb0eb7SJason Gunthorpe 	if (count == 0)
1829deb0eb7SJason Gunthorpe 		return -ENODATA;
1839deb0eb7SJason Gunthorpe 	if (count > bufsiz) {
1848cfffc9dSJason Gunthorpe 		dev_err(&chip->dev,
1859deb0eb7SJason Gunthorpe 			"invalid count value %x %zx\n", count, bufsiz);
1869deb0eb7SJason Gunthorpe 		return -E2BIG;
1879deb0eb7SJason Gunthorpe 	}
1889deb0eb7SJason Gunthorpe 
18958bac8ccSJarkko Sakkinen 	if (!(flags & TPM_TRANSMIT_UNLOCKED) && !(flags & TPM_TRANSMIT_NESTED))
1909deb0eb7SJason Gunthorpe 		mutex_lock(&chip->tpm_mutex);
1919deb0eb7SJason Gunthorpe 
192b3e958ceSAzhar Shaikh 	if (chip->ops->clk_enable != NULL)
193b3e958ceSAzhar Shaikh 		chip->ops->clk_enable(chip, true);
194b3e958ceSAzhar Shaikh 
195877c57d0SJarkko Sakkinen 	/* Store the decision as chip->locality will be changed. */
196877c57d0SJarkko Sakkinen 	need_locality = chip->locality == -1;
197877c57d0SJarkko Sakkinen 
198627448e8STomas Winkler 	if (need_locality) {
199627448e8STomas Winkler 		rc = tpm_request_locality(chip, flags);
200877c57d0SJarkko Sakkinen 		if (rc < 0)
201877c57d0SJarkko Sakkinen 			goto out_no_locality;
202877c57d0SJarkko Sakkinen 	}
203877c57d0SJarkko Sakkinen 
204627448e8STomas Winkler 	rc = tpm_cmd_ready(chip, flags);
205627448e8STomas Winkler 	if (rc)
206627448e8STomas Winkler 		goto out;
207888d867dSTomas Winkler 
208745b361eSJarkko Sakkinen 	rc = tpm2_prepare_space(chip, space, ordinal, buf);
209745b361eSJarkko Sakkinen 	if (rc)
210745b361eSJarkko Sakkinen 		goto out;
211745b361eSJarkko Sakkinen 
21262c09e12SWinkler, Tomas 	rc = chip->ops->send(chip, buf, count);
2139deb0eb7SJason Gunthorpe 	if (rc < 0) {
214402149c6SStefan Berger 		if (rc != -EPIPE)
2158cfffc9dSJason Gunthorpe 			dev_err(&chip->dev,
216402149c6SStefan Berger 				"%s: tpm_send: error %d\n", __func__, rc);
2179deb0eb7SJason Gunthorpe 		goto out;
2189deb0eb7SJason Gunthorpe 	}
2199deb0eb7SJason Gunthorpe 
220570a3609SChristophe Ricard 	if (chip->flags & TPM_CHIP_FLAG_IRQ)
2219deb0eb7SJason Gunthorpe 		goto out_recv;
2229deb0eb7SJason Gunthorpe 
2237a1d7e6dSJarkko Sakkinen 	if (chip->flags & TPM_CHIP_FLAG_TPM2)
2247a1d7e6dSJarkko Sakkinen 		stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal);
2257a1d7e6dSJarkko Sakkinen 	else
226*b2d6e6deSTomas Winkler 		stop = jiffies + tpm1_calc_ordinal_duration(chip, ordinal);
2279deb0eb7SJason Gunthorpe 	do {
2285f82e9f0SJason Gunthorpe 		u8 status = chip->ops->status(chip);
2295f82e9f0SJason Gunthorpe 		if ((status & chip->ops->req_complete_mask) ==
2305f82e9f0SJason Gunthorpe 		    chip->ops->req_complete_val)
2319deb0eb7SJason Gunthorpe 			goto out_recv;
2329deb0eb7SJason Gunthorpe 
2335f82e9f0SJason Gunthorpe 		if (chip->ops->req_canceled(chip, status)) {
2348cfffc9dSJason Gunthorpe 			dev_err(&chip->dev, "Operation Canceled\n");
2359deb0eb7SJason Gunthorpe 			rc = -ECANCELED;
2369deb0eb7SJason Gunthorpe 			goto out;
2379deb0eb7SJason Gunthorpe 		}
2389deb0eb7SJason Gunthorpe 
23959f5a6b0SNayna Jain 		tpm_msleep(TPM_TIMEOUT_POLL);
2409deb0eb7SJason Gunthorpe 		rmb();
2419deb0eb7SJason Gunthorpe 	} while (time_before(jiffies, stop));
2429deb0eb7SJason Gunthorpe 
2435f82e9f0SJason Gunthorpe 	chip->ops->cancel(chip);
2448cfffc9dSJason Gunthorpe 	dev_err(&chip->dev, "Operation Timed out\n");
2459deb0eb7SJason Gunthorpe 	rc = -ETIME;
2469deb0eb7SJason Gunthorpe 	goto out;
2479deb0eb7SJason Gunthorpe 
2489deb0eb7SJason Gunthorpe out_recv:
24962c09e12SWinkler, Tomas 	len = chip->ops->recv(chip, buf, bufsiz);
250745b361eSJarkko Sakkinen 	if (len < 0) {
251745b361eSJarkko Sakkinen 		rc = len;
2528cfffc9dSJason Gunthorpe 		dev_err(&chip->dev,
253745b361eSJarkko Sakkinen 			"tpm_transmit: tpm_recv: error %d\n", rc);
254a147918eSJarkko Sakkinen 		goto out;
255745b361eSJarkko Sakkinen 	} else if (len < TPM_HEADER_SIZE) {
256a147918eSJarkko Sakkinen 		rc = -EFAULT;
257a147918eSJarkko Sakkinen 		goto out;
258a147918eSJarkko Sakkinen 	}
259a147918eSJarkko Sakkinen 
260745b361eSJarkko Sakkinen 	if (len != be32_to_cpu(header->length)) {
261745b361eSJarkko Sakkinen 		rc = -EFAULT;
262a147918eSJarkko Sakkinen 		goto out;
263745b361eSJarkko Sakkinen 	}
264745b361eSJarkko Sakkinen 
265745b361eSJarkko Sakkinen 	rc = tpm2_commit_space(chip, space, ordinal, buf, &len);
266627448e8STomas Winkler 	if (rc)
267627448e8STomas Winkler 		dev_err(&chip->dev, "tpm2_commit_space: error %d\n", rc);
268a147918eSJarkko Sakkinen 
2699deb0eb7SJason Gunthorpe out:
270627448e8STomas Winkler 	rc = tpm_go_idle(chip, flags);
271627448e8STomas Winkler 	if (rc)
272627448e8STomas Winkler 		goto out;
273888d867dSTomas Winkler 
274888d867dSTomas Winkler 	if (need_locality)
275627448e8STomas Winkler 		tpm_relinquish_locality(chip, flags);
276888d867dSTomas Winkler 
277877c57d0SJarkko Sakkinen out_no_locality:
278b3e958ceSAzhar Shaikh 	if (chip->ops->clk_enable != NULL)
279b3e958ceSAzhar Shaikh 		chip->ops->clk_enable(chip, false);
280b3e958ceSAzhar Shaikh 
28158bac8ccSJarkko Sakkinen 	if (!(flags & TPM_TRANSMIT_UNLOCKED) && !(flags & TPM_TRANSMIT_NESTED))
2829deb0eb7SJason Gunthorpe 		mutex_unlock(&chip->tpm_mutex);
283745b361eSJarkko Sakkinen 	return rc ? rc : len;
2849deb0eb7SJason Gunthorpe }
2859deb0eb7SJason Gunthorpe 
286f865c196SWinkler, Tomas /**
287e2fb992dSJames Bottomley  * tpm_transmit - Internal kernel interface to transmit TPM commands.
288e2fb992dSJames Bottomley  *
289e2fb992dSJames Bottomley  * @chip: TPM chip to use
290e2fb992dSJames Bottomley  * @space: tpm space
291e2fb992dSJames Bottomley  * @buf: TPM command buffer
292e2fb992dSJames Bottomley  * @bufsiz: length of the TPM command buffer
293e2fb992dSJames Bottomley  * @flags: tpm transmit flags - bitmap
294e2fb992dSJames Bottomley  *
295e2fb992dSJames Bottomley  * A wrapper around tpm_try_transmit that handles TPM2_RC_RETRY
296e2fb992dSJames Bottomley  * returns from the TPM and retransmits the command after a delay up
297e2fb992dSJames Bottomley  * to a maximum wait of TPM2_DURATION_LONG.
298e2fb992dSJames Bottomley  *
299e2fb992dSJames Bottomley  * Note: TPM1 never returns TPM2_RC_RETRY so the retry logic is TPM2
300e2fb992dSJames Bottomley  * only
301e2fb992dSJames Bottomley  *
302e2fb992dSJames Bottomley  * Return:
303e2fb992dSJames Bottomley  *     the length of the return when the operation is successful.
304e2fb992dSJames Bottomley  *     A negative number for system errors (errno).
305e2fb992dSJames Bottomley  */
306e2fb992dSJames Bottomley ssize_t tpm_transmit(struct tpm_chip *chip, struct tpm_space *space,
307e2fb992dSJames Bottomley 		     u8 *buf, size_t bufsiz, unsigned int flags)
308e2fb992dSJames Bottomley {
309e2fb992dSJames Bottomley 	struct tpm_output_header *header = (struct tpm_output_header *)buf;
310e2fb992dSJames Bottomley 	/* space for header and handles */
311e2fb992dSJames Bottomley 	u8 save[TPM_HEADER_SIZE + 3*sizeof(u32)];
312e2fb992dSJames Bottomley 	unsigned int delay_msec = TPM2_DURATION_SHORT;
313e2fb992dSJames Bottomley 	u32 rc = 0;
314e2fb992dSJames Bottomley 	ssize_t ret;
315e2fb992dSJames Bottomley 	const size_t save_size = min(space ? sizeof(save) : TPM_HEADER_SIZE,
316e2fb992dSJames Bottomley 				     bufsiz);
3172be8ffedSJames Bottomley 	/* the command code is where the return code will be */
3182be8ffedSJames Bottomley 	u32 cc = be32_to_cpu(header->return_code);
319e2fb992dSJames Bottomley 
320e2fb992dSJames Bottomley 	/*
321e2fb992dSJames Bottomley 	 * Subtlety here: if we have a space, the handles will be
322e2fb992dSJames Bottomley 	 * transformed, so when we restore the header we also have to
323e2fb992dSJames Bottomley 	 * restore the handles.
324e2fb992dSJames Bottomley 	 */
325e2fb992dSJames Bottomley 	memcpy(save, buf, save_size);
326e2fb992dSJames Bottomley 
327e2fb992dSJames Bottomley 	for (;;) {
328e2fb992dSJames Bottomley 		ret = tpm_try_transmit(chip, space, buf, bufsiz, flags);
329e2fb992dSJames Bottomley 		if (ret < 0)
330e2fb992dSJames Bottomley 			break;
331e2fb992dSJames Bottomley 		rc = be32_to_cpu(header->return_code);
3322be8ffedSJames Bottomley 		if (rc != TPM2_RC_RETRY && rc != TPM2_RC_TESTING)
3332be8ffedSJames Bottomley 			break;
3342be8ffedSJames Bottomley 		/*
3352be8ffedSJames Bottomley 		 * return immediately if self test returns test
3362be8ffedSJames Bottomley 		 * still running to shorten boot time.
3372be8ffedSJames Bottomley 		 */
3382be8ffedSJames Bottomley 		if (rc == TPM2_RC_TESTING && cc == TPM2_CC_SELF_TEST)
339e2fb992dSJames Bottomley 			break;
34092980756SNayna Jain 
341e2fb992dSJames Bottomley 		if (delay_msec > TPM2_DURATION_LONG) {
3422be8ffedSJames Bottomley 			if (rc == TPM2_RC_RETRY)
3432be8ffedSJames Bottomley 				dev_err(&chip->dev, "in retry loop\n");
3442be8ffedSJames Bottomley 			else
3452be8ffedSJames Bottomley 				dev_err(&chip->dev,
3462be8ffedSJames Bottomley 					"self test is still running\n");
347e2fb992dSJames Bottomley 			break;
348e2fb992dSJames Bottomley 		}
349e2fb992dSJames Bottomley 		tpm_msleep(delay_msec);
35092980756SNayna Jain 		delay_msec *= 2;
351e2fb992dSJames Bottomley 		memcpy(buf, save, save_size);
352e2fb992dSJames Bottomley 	}
353e2fb992dSJames Bottomley 	return ret;
354e2fb992dSJames Bottomley }
355e2fb992dSJames Bottomley /**
35665520d46SWinkler, Tomas  * tpm_transmit_cmd - send a tpm command to the device
357f865c196SWinkler, Tomas  *    The function extracts tpm out header return code
358f865c196SWinkler, Tomas  *
359f865c196SWinkler, Tomas  * @chip: TPM chip to use
36065520d46SWinkler, Tomas  * @space: tpm space
361c659af78SStefan Berger  * @buf: TPM command buffer
362c659af78SStefan Berger  * @bufsiz: length of the buffer
363c659af78SStefan Berger  * @min_rsp_body_length: minimum expected length of response body
364f865c196SWinkler, Tomas  * @flags: tpm transmit flags - bitmap
365f865c196SWinkler, Tomas  * @desc: command description used in the error message
366f865c196SWinkler, Tomas  *
367f865c196SWinkler, Tomas  * Return:
368f865c196SWinkler, Tomas  *     0 when the operation is successful.
369f865c196SWinkler, Tomas  *     A negative number for system errors (errno).
370f865c196SWinkler, Tomas  *     A positive number for a TPM error.
371f865c196SWinkler, Tomas  */
372745b361eSJarkko Sakkinen ssize_t tpm_transmit_cmd(struct tpm_chip *chip, struct tpm_space *space,
37362c09e12SWinkler, Tomas 			 void *buf, size_t bufsiz,
374745b361eSJarkko Sakkinen 			 size_t min_rsp_body_length, unsigned int flags,
375745b361eSJarkko Sakkinen 			 const char *desc)
3769deb0eb7SJason Gunthorpe {
377a147918eSJarkko Sakkinen 	const struct tpm_output_header *header = buf;
3789deb0eb7SJason Gunthorpe 	int err;
379c659af78SStefan Berger 	ssize_t len;
3809deb0eb7SJason Gunthorpe 
38162c09e12SWinkler, Tomas 	len = tpm_transmit(chip, space, buf, bufsiz, flags);
3829deb0eb7SJason Gunthorpe 	if (len <  0)
3839deb0eb7SJason Gunthorpe 		return len;
38487155b73SJarkko Sakkinen 
38587155b73SJarkko Sakkinen 	err = be32_to_cpu(header->return_code);
3860d6d0d62SJavier Martinez Canillas 	if (err != 0 && err != TPM_ERR_DISABLED && err != TPM_ERR_DEACTIVATED
3870d6d0d62SJavier Martinez Canillas 	    && desc)
3888cfffc9dSJason Gunthorpe 		dev_err(&chip->dev, "A TPM error (%d) occurred %s\n", err,
38971ed848fSJarkko Sakkinen 			desc);
390c659af78SStefan Berger 	if (err)
3919deb0eb7SJason Gunthorpe 		return err;
392c659af78SStefan Berger 
393c659af78SStefan Berger 	if (len < min_rsp_body_length + TPM_HEADER_SIZE)
394c659af78SStefan Berger 		return -EFAULT;
395c659af78SStefan Berger 
396c659af78SStefan Berger 	return 0;
3979deb0eb7SJason Gunthorpe }
398be4c9acfSStefan Berger EXPORT_SYMBOL_GPL(tpm_transmit_cmd);
3999deb0eb7SJason Gunthorpe 
40019cbe4f6SJarkko Sakkinen #define TPM_ORD_STARTUP 153
40119cbe4f6SJarkko Sakkinen #define TPM_ST_CLEAR 1
40219cbe4f6SJarkko Sakkinen 
40319cbe4f6SJarkko Sakkinen /**
40419cbe4f6SJarkko Sakkinen  * tpm_startup - turn on the TPM
40519cbe4f6SJarkko Sakkinen  * @chip: TPM chip to use
40619cbe4f6SJarkko Sakkinen  *
40719cbe4f6SJarkko Sakkinen  * Normally the firmware should start the TPM. This function is provided as a
40819cbe4f6SJarkko Sakkinen  * workaround if this does not happen. A legal case for this could be for
40919cbe4f6SJarkko Sakkinen  * example when a TPM emulator is used.
41019cbe4f6SJarkko Sakkinen  *
41119cbe4f6SJarkko Sakkinen  * Return: same as tpm_transmit_cmd()
41219cbe4f6SJarkko Sakkinen  */
41319cbe4f6SJarkko Sakkinen int tpm_startup(struct tpm_chip *chip)
41419cbe4f6SJarkko Sakkinen {
41519cbe4f6SJarkko Sakkinen 	struct tpm_buf buf;
41619cbe4f6SJarkko Sakkinen 	int rc;
41719cbe4f6SJarkko Sakkinen 
41819cbe4f6SJarkko Sakkinen 	dev_info(&chip->dev, "starting up the TPM manually\n");
41919cbe4f6SJarkko Sakkinen 
42019cbe4f6SJarkko Sakkinen 	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
42119cbe4f6SJarkko Sakkinen 		rc = tpm_buf_init(&buf, TPM2_ST_NO_SESSIONS, TPM2_CC_STARTUP);
42219cbe4f6SJarkko Sakkinen 		if (rc < 0)
42319cbe4f6SJarkko Sakkinen 			return rc;
42419cbe4f6SJarkko Sakkinen 
42519cbe4f6SJarkko Sakkinen 		tpm_buf_append_u16(&buf, TPM2_SU_CLEAR);
42619cbe4f6SJarkko Sakkinen 	} else {
42719cbe4f6SJarkko Sakkinen 		rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_STARTUP);
42819cbe4f6SJarkko Sakkinen 		if (rc < 0)
42919cbe4f6SJarkko Sakkinen 			return rc;
43019cbe4f6SJarkko Sakkinen 
43119cbe4f6SJarkko Sakkinen 		tpm_buf_append_u16(&buf, TPM_ST_CLEAR);
43219cbe4f6SJarkko Sakkinen 	}
43319cbe4f6SJarkko Sakkinen 
43419cbe4f6SJarkko Sakkinen 	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE, 0, 0,
43519cbe4f6SJarkko Sakkinen 			      "attempting to start the TPM");
43619cbe4f6SJarkko Sakkinen 
43719cbe4f6SJarkko Sakkinen 	tpm_buf_destroy(&buf);
43819cbe4f6SJarkko Sakkinen 	return rc;
43919cbe4f6SJarkko Sakkinen }
44019cbe4f6SJarkko Sakkinen 
441f865c196SWinkler, Tomas #define TPM_DIGEST_SIZE 20
442f865c196SWinkler, Tomas #define TPM_RET_CODE_IDX 6
4439deb0eb7SJason Gunthorpe #define TPM_INTERNAL_RESULT_SIZE 200
444a69faebfSRoberto Sassu #define TPM_ORD_GET_CAP 101
445a69faebfSRoberto Sassu #define TPM_ORD_GET_RANDOM 70
4469deb0eb7SJason Gunthorpe 
4479deb0eb7SJason Gunthorpe static const struct tpm_input_header tpm_getcap_header = {
44806e93279SRoberto Sassu 	.tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
4499deb0eb7SJason Gunthorpe 	.length = cpu_to_be32(22),
450a69faebfSRoberto Sassu 	.ordinal = cpu_to_be32(TPM_ORD_GET_CAP)
4519deb0eb7SJason Gunthorpe };
4529deb0eb7SJason Gunthorpe 
45384fda152SJarkko Sakkinen ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap,
454c659af78SStefan Berger 		   const char *desc, size_t min_cap_length)
4559deb0eb7SJason Gunthorpe {
456124bdcf4SJarkko Sakkinen 	struct tpm_buf buf;
4579deb0eb7SJason Gunthorpe 	int rc;
4589deb0eb7SJason Gunthorpe 
459124bdcf4SJarkko Sakkinen 	rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_GET_CAP);
460124bdcf4SJarkko Sakkinen 	if (rc)
461124bdcf4SJarkko Sakkinen 		return rc;
462124bdcf4SJarkko Sakkinen 
46384fda152SJarkko Sakkinen 	if (subcap_id == TPM_CAP_VERSION_1_1 ||
46484fda152SJarkko Sakkinen 	    subcap_id == TPM_CAP_VERSION_1_2) {
465124bdcf4SJarkko Sakkinen 		tpm_buf_append_u32(&buf, subcap_id);
466124bdcf4SJarkko Sakkinen 		tpm_buf_append_u32(&buf, 0);
4679deb0eb7SJason Gunthorpe 	} else {
4689deb0eb7SJason Gunthorpe 		if (subcap_id == TPM_CAP_FLAG_PERM ||
4699deb0eb7SJason Gunthorpe 		    subcap_id == TPM_CAP_FLAG_VOL)
470124bdcf4SJarkko Sakkinen 			tpm_buf_append_u32(&buf, TPM_CAP_FLAG);
4719deb0eb7SJason Gunthorpe 		else
472124bdcf4SJarkko Sakkinen 			tpm_buf_append_u32(&buf, TPM_CAP_PROP);
473124bdcf4SJarkko Sakkinen 
474124bdcf4SJarkko Sakkinen 		tpm_buf_append_u32(&buf, 4);
475124bdcf4SJarkko Sakkinen 		tpm_buf_append_u32(&buf, subcap_id);
4769deb0eb7SJason Gunthorpe 	}
477124bdcf4SJarkko Sakkinen 	rc = tpm_transmit_cmd(chip, NULL, buf.data, PAGE_SIZE,
478c659af78SStefan Berger 			      min_cap_length, 0, desc);
4799deb0eb7SJason Gunthorpe 	if (!rc)
480124bdcf4SJarkko Sakkinen 		*cap = *(cap_t *)&buf.data[TPM_HEADER_SIZE + 4];
481124bdcf4SJarkko Sakkinen 
482124bdcf4SJarkko Sakkinen 	tpm_buf_destroy(&buf);
4839deb0eb7SJason Gunthorpe 	return rc;
4849deb0eb7SJason Gunthorpe }
485eb5854e7SJarkko Sakkinen EXPORT_SYMBOL_GPL(tpm_getcap);
4869deb0eb7SJason Gunthorpe 
4879deb0eb7SJason Gunthorpe int tpm_get_timeouts(struct tpm_chip *chip)
4889deb0eb7SJason Gunthorpe {
489aaa6f7f6SEd Swierk 	cap_t cap;
4901d70fe9dSMaciej S. Szmigiero 	unsigned long timeout_old[4], timeout_chip[4], timeout_eff[4];
4919deb0eb7SJason Gunthorpe 	ssize_t rc;
4929deb0eb7SJason Gunthorpe 
493d1d253cfSJason Gunthorpe 	if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS)
494d1d253cfSJason Gunthorpe 		return 0;
495d1d253cfSJason Gunthorpe 
49625112048SJason Gunthorpe 	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
49725112048SJason Gunthorpe 		/* Fixed timeouts for TPM2 */
498af782f33SChristophe Ricard 		chip->timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
499af782f33SChristophe Ricard 		chip->timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
500af782f33SChristophe Ricard 		chip->timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
501af782f33SChristophe Ricard 		chip->timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
502af782f33SChristophe Ricard 		chip->duration[TPM_SHORT] =
50325112048SJason Gunthorpe 		    msecs_to_jiffies(TPM2_DURATION_SHORT);
504af782f33SChristophe Ricard 		chip->duration[TPM_MEDIUM] =
50525112048SJason Gunthorpe 		    msecs_to_jiffies(TPM2_DURATION_MEDIUM);
506af782f33SChristophe Ricard 		chip->duration[TPM_LONG] =
50725112048SJason Gunthorpe 		    msecs_to_jiffies(TPM2_DURATION_LONG);
508076d3564STomas Winkler 		chip->duration[TPM_LONG_LONG] =
509076d3564STomas Winkler 		    msecs_to_jiffies(TPM2_DURATION_LONG_LONG);
510d1d253cfSJason Gunthorpe 
511d1d253cfSJason Gunthorpe 		chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS;
51225112048SJason Gunthorpe 		return 0;
51325112048SJason Gunthorpe 	}
51425112048SJason Gunthorpe 
515c659af78SStefan Berger 	rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, NULL,
516c659af78SStefan Berger 			sizeof(cap.timeout));
5179deb0eb7SJason Gunthorpe 	if (rc == TPM_ERR_INVALID_POSTINIT) {
51819cbe4f6SJarkko Sakkinen 		if (tpm_startup(chip))
5199deb0eb7SJason Gunthorpe 			return rc;
5209deb0eb7SJason Gunthorpe 
521aaa6f7f6SEd Swierk 		rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap,
522c659af78SStefan Berger 				"attempting to determine the timeouts",
523c659af78SStefan Berger 				sizeof(cap.timeout));
5249deb0eb7SJason Gunthorpe 	}
525c659af78SStefan Berger 
52662bfdacbSJason Gunthorpe 	if (rc) {
52762bfdacbSJason Gunthorpe 		dev_err(&chip->dev,
52862bfdacbSJason Gunthorpe 			"A TPM error (%zd) occurred attempting to determine the timeouts\n",
52962bfdacbSJason Gunthorpe 			rc);
530aaa6f7f6SEd Swierk 		return rc;
53162bfdacbSJason Gunthorpe 	}
5329deb0eb7SJason Gunthorpe 
5331d70fe9dSMaciej S. Szmigiero 	timeout_old[0] = jiffies_to_usecs(chip->timeout_a);
5341d70fe9dSMaciej S. Szmigiero 	timeout_old[1] = jiffies_to_usecs(chip->timeout_b);
5351d70fe9dSMaciej S. Szmigiero 	timeout_old[2] = jiffies_to_usecs(chip->timeout_c);
5361d70fe9dSMaciej S. Szmigiero 	timeout_old[3] = jiffies_to_usecs(chip->timeout_d);
5371d70fe9dSMaciej S. Szmigiero 	timeout_chip[0] = be32_to_cpu(cap.timeout.a);
5381d70fe9dSMaciej S. Szmigiero 	timeout_chip[1] = be32_to_cpu(cap.timeout.b);
5391d70fe9dSMaciej S. Szmigiero 	timeout_chip[2] = be32_to_cpu(cap.timeout.c);
5401d70fe9dSMaciej S. Szmigiero 	timeout_chip[3] = be32_to_cpu(cap.timeout.d);
5411d70fe9dSMaciej S. Szmigiero 	memcpy(timeout_eff, timeout_chip, sizeof(timeout_eff));
5428e54caf4SJason Gunthorpe 
5438e54caf4SJason Gunthorpe 	/*
5448e54caf4SJason Gunthorpe 	 * Provide ability for vendor overrides of timeout values in case
5458e54caf4SJason Gunthorpe 	 * of misreporting.
5468e54caf4SJason Gunthorpe 	 */
5478e54caf4SJason Gunthorpe 	if (chip->ops->update_timeouts != NULL)
548af782f33SChristophe Ricard 		chip->timeout_adjusted =
5491d70fe9dSMaciej S. Szmigiero 			chip->ops->update_timeouts(chip, timeout_eff);
5508e54caf4SJason Gunthorpe 
551af782f33SChristophe Ricard 	if (!chip->timeout_adjusted) {
5521d70fe9dSMaciej S. Szmigiero 		/* Restore default if chip reported 0 */
5538e54caf4SJason Gunthorpe 		int i;
5548e54caf4SJason Gunthorpe 
5551d70fe9dSMaciej S. Szmigiero 		for (i = 0; i < ARRAY_SIZE(timeout_eff); i++) {
5561d70fe9dSMaciej S. Szmigiero 			if (timeout_eff[i])
5571d70fe9dSMaciej S. Szmigiero 				continue;
5581d70fe9dSMaciej S. Szmigiero 
5591d70fe9dSMaciej S. Szmigiero 			timeout_eff[i] = timeout_old[i];
5601d70fe9dSMaciej S. Szmigiero 			chip->timeout_adjusted = true;
5611d70fe9dSMaciej S. Szmigiero 		}
5621d70fe9dSMaciej S. Szmigiero 
5631d70fe9dSMaciej S. Szmigiero 		if (timeout_eff[0] != 0 && timeout_eff[0] < 1000) {
5649deb0eb7SJason Gunthorpe 			/* timeouts in msec rather usec */
5651d70fe9dSMaciej S. Szmigiero 			for (i = 0; i != ARRAY_SIZE(timeout_eff); i++)
5661d70fe9dSMaciej S. Szmigiero 				timeout_eff[i] *= 1000;
567af782f33SChristophe Ricard 			chip->timeout_adjusted = true;
5689deb0eb7SJason Gunthorpe 		}
5698e54caf4SJason Gunthorpe 	}
5708e54caf4SJason Gunthorpe 
5718e54caf4SJason Gunthorpe 	/* Report adjusted timeouts */
572af782f33SChristophe Ricard 	if (chip->timeout_adjusted) {
5738cfffc9dSJason Gunthorpe 		dev_info(&chip->dev,
5748e54caf4SJason Gunthorpe 			 HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n",
5751d70fe9dSMaciej S. Szmigiero 			 timeout_chip[0], timeout_eff[0],
5761d70fe9dSMaciej S. Szmigiero 			 timeout_chip[1], timeout_eff[1],
5771d70fe9dSMaciej S. Szmigiero 			 timeout_chip[2], timeout_eff[2],
5781d70fe9dSMaciej S. Szmigiero 			 timeout_chip[3], timeout_eff[3]);
5798e54caf4SJason Gunthorpe 	}
5808e54caf4SJason Gunthorpe 
5811d70fe9dSMaciej S. Szmigiero 	chip->timeout_a = usecs_to_jiffies(timeout_eff[0]);
5821d70fe9dSMaciej S. Szmigiero 	chip->timeout_b = usecs_to_jiffies(timeout_eff[1]);
5831d70fe9dSMaciej S. Szmigiero 	chip->timeout_c = usecs_to_jiffies(timeout_eff[2]);
5841d70fe9dSMaciej S. Szmigiero 	chip->timeout_d = usecs_to_jiffies(timeout_eff[3]);
5859deb0eb7SJason Gunthorpe 
586aaa6f7f6SEd Swierk 	rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap,
587c659af78SStefan Berger 			"attempting to determine the durations",
588c659af78SStefan Berger 			sizeof(cap.duration));
5899deb0eb7SJason Gunthorpe 	if (rc)
5909deb0eb7SJason Gunthorpe 		return rc;
5919deb0eb7SJason Gunthorpe 
592af782f33SChristophe Ricard 	chip->duration[TPM_SHORT] =
593aaa6f7f6SEd Swierk 		usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_short));
594af782f33SChristophe Ricard 	chip->duration[TPM_MEDIUM] =
595aaa6f7f6SEd Swierk 		usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium));
596af782f33SChristophe Ricard 	chip->duration[TPM_LONG] =
597aaa6f7f6SEd Swierk 		usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_long));
598076d3564STomas Winkler 	chip->duration[TPM_LONG_LONG] = 0; /* not used under 1.2 */
5999deb0eb7SJason Gunthorpe 
6009deb0eb7SJason Gunthorpe 	/* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
6019deb0eb7SJason Gunthorpe 	 * value wrong and apparently reports msecs rather than usecs. So we
6029deb0eb7SJason Gunthorpe 	 * fix up the resulting too-small TPM_SHORT value to make things work.
6039deb0eb7SJason Gunthorpe 	 * We also scale the TPM_MEDIUM and -_LONG values by 1000.
6049deb0eb7SJason Gunthorpe 	 */
605af782f33SChristophe Ricard 	if (chip->duration[TPM_SHORT] < (HZ / 100)) {
606af782f33SChristophe Ricard 		chip->duration[TPM_SHORT] = HZ;
607af782f33SChristophe Ricard 		chip->duration[TPM_MEDIUM] *= 1000;
608af782f33SChristophe Ricard 		chip->duration[TPM_LONG] *= 1000;
609af782f33SChristophe Ricard 		chip->duration_adjusted = true;
6108cfffc9dSJason Gunthorpe 		dev_info(&chip->dev, "Adjusting TPM timeout parameters.");
6119deb0eb7SJason Gunthorpe 	}
612d1d253cfSJason Gunthorpe 
613d1d253cfSJason Gunthorpe 	chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS;
6149deb0eb7SJason Gunthorpe 	return 0;
6159deb0eb7SJason Gunthorpe }
6169deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_get_timeouts);
6179deb0eb7SJason Gunthorpe 
6189deb0eb7SJason Gunthorpe #define TPM_ORD_CONTINUE_SELFTEST 83
6199deb0eb7SJason Gunthorpe #define CONTINUE_SELFTEST_RESULT_SIZE 10
6209deb0eb7SJason Gunthorpe 
6210014777fSJulia Lawall static const struct tpm_input_header continue_selftest_header = {
62206e93279SRoberto Sassu 	.tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
6239deb0eb7SJason Gunthorpe 	.length = cpu_to_be32(10),
6249deb0eb7SJason Gunthorpe 	.ordinal = cpu_to_be32(TPM_ORD_CONTINUE_SELFTEST),
6259deb0eb7SJason Gunthorpe };
6269deb0eb7SJason Gunthorpe 
6279deb0eb7SJason Gunthorpe /**
6289deb0eb7SJason Gunthorpe  * tpm_continue_selftest -- run TPM's selftest
6299deb0eb7SJason Gunthorpe  * @chip: TPM chip to use
6309deb0eb7SJason Gunthorpe  *
6319deb0eb7SJason Gunthorpe  * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
6329deb0eb7SJason Gunthorpe  * a TPM error code.
6339deb0eb7SJason Gunthorpe  */
6349deb0eb7SJason Gunthorpe static int tpm_continue_selftest(struct tpm_chip *chip)
6359deb0eb7SJason Gunthorpe {
6369deb0eb7SJason Gunthorpe 	int rc;
6379deb0eb7SJason Gunthorpe 	struct tpm_cmd_t cmd;
6389deb0eb7SJason Gunthorpe 
6399deb0eb7SJason Gunthorpe 	cmd.header.in = continue_selftest_header;
640745b361eSJarkko Sakkinen 	rc = tpm_transmit_cmd(chip, NULL, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
641745b361eSJarkko Sakkinen 			      0, 0, "continue selftest");
6429deb0eb7SJason Gunthorpe 	return rc;
6439deb0eb7SJason Gunthorpe }
6449deb0eb7SJason Gunthorpe 
645a69faebfSRoberto Sassu #define TPM_ORDINAL_PCRREAD 21
6469deb0eb7SJason Gunthorpe #define READ_PCR_RESULT_SIZE 30
647c659af78SStefan Berger #define READ_PCR_RESULT_BODY_SIZE 20
6480014777fSJulia Lawall static const struct tpm_input_header pcrread_header = {
64906e93279SRoberto Sassu 	.tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
6509deb0eb7SJason Gunthorpe 	.length = cpu_to_be32(14),
651a69faebfSRoberto Sassu 	.ordinal = cpu_to_be32(TPM_ORDINAL_PCRREAD)
6529deb0eb7SJason Gunthorpe };
6539deb0eb7SJason Gunthorpe 
654000a07b0SJason Gunthorpe int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
6559deb0eb7SJason Gunthorpe {
6569deb0eb7SJason Gunthorpe 	int rc;
6579deb0eb7SJason Gunthorpe 	struct tpm_cmd_t cmd;
6589deb0eb7SJason Gunthorpe 
6599deb0eb7SJason Gunthorpe 	cmd.header.in = pcrread_header;
6609deb0eb7SJason Gunthorpe 	cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
661745b361eSJarkko Sakkinen 	rc = tpm_transmit_cmd(chip, NULL, &cmd, READ_PCR_RESULT_SIZE,
662c659af78SStefan Berger 			      READ_PCR_RESULT_BODY_SIZE, 0,
6639deb0eb7SJason Gunthorpe 			      "attempting to read a pcr value");
6649deb0eb7SJason Gunthorpe 
6659deb0eb7SJason Gunthorpe 	if (rc == 0)
6669deb0eb7SJason Gunthorpe 		memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
6679deb0eb7SJason Gunthorpe 		       TPM_DIGEST_SIZE);
6689deb0eb7SJason Gunthorpe 	return rc;
6699deb0eb7SJason Gunthorpe }
6709deb0eb7SJason Gunthorpe 
6719deb0eb7SJason Gunthorpe /**
672aad887f6SJarkko Sakkinen  * tpm_is_tpm2 - do we a have a TPM2 chip?
673aad887f6SJarkko Sakkinen  * @chip:	a &struct tpm_chip instance, %NULL for the default chip
674954650efSJarkko Sakkinen  *
675aad887f6SJarkko Sakkinen  * Return:
676aad887f6SJarkko Sakkinen  * 1 if we have a TPM2 chip.
677aad887f6SJarkko Sakkinen  * 0 if we don't have a TPM2 chip.
678aad887f6SJarkko Sakkinen  * A negative number for system errors (errno).
679954650efSJarkko Sakkinen  */
680aad887f6SJarkko Sakkinen int tpm_is_tpm2(struct tpm_chip *chip)
681954650efSJarkko Sakkinen {
682954650efSJarkko Sakkinen 	int rc;
683954650efSJarkko Sakkinen 
684fc1d52b7SStefan Berger 	chip = tpm_find_get_ops(chip);
685aad887f6SJarkko Sakkinen 	if (!chip)
686954650efSJarkko Sakkinen 		return -ENODEV;
687954650efSJarkko Sakkinen 
688954650efSJarkko Sakkinen 	rc = (chip->flags & TPM_CHIP_FLAG_TPM2) != 0;
689954650efSJarkko Sakkinen 
6904e26195fSJason Gunthorpe 	tpm_put_ops(chip);
691954650efSJarkko Sakkinen 
692954650efSJarkko Sakkinen 	return rc;
693954650efSJarkko Sakkinen }
694954650efSJarkko Sakkinen EXPORT_SYMBOL_GPL(tpm_is_tpm2);
695954650efSJarkko Sakkinen 
696954650efSJarkko Sakkinen /**
697aad887f6SJarkko Sakkinen  * tpm_pcr_read - read a PCR value from SHA1 bank
698aad887f6SJarkko Sakkinen  * @chip:	a &struct tpm_chip instance, %NULL for the default chip
699aad887f6SJarkko Sakkinen  * @pcr_idx:	the PCR to be retrieved
700aad887f6SJarkko Sakkinen  * @res_buf:	the value of the PCR
7019deb0eb7SJason Gunthorpe  *
702aad887f6SJarkko Sakkinen  * Return: same as with tpm_transmit_cmd()
7039deb0eb7SJason Gunthorpe  */
704aad887f6SJarkko Sakkinen int tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
7059deb0eb7SJason Gunthorpe {
7069deb0eb7SJason Gunthorpe 	int rc;
7079deb0eb7SJason Gunthorpe 
708fc1d52b7SStefan Berger 	chip = tpm_find_get_ops(chip);
709aad887f6SJarkko Sakkinen 	if (!chip)
7109deb0eb7SJason Gunthorpe 		return -ENODEV;
7117a1d7e6dSJarkko Sakkinen 	if (chip->flags & TPM_CHIP_FLAG_TPM2)
7127a1d7e6dSJarkko Sakkinen 		rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
7137a1d7e6dSJarkko Sakkinen 	else
714000a07b0SJason Gunthorpe 		rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
7154e26195fSJason Gunthorpe 	tpm_put_ops(chip);
7169deb0eb7SJason Gunthorpe 	return rc;
7179deb0eb7SJason Gunthorpe }
7189deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_pcr_read);
7199deb0eb7SJason Gunthorpe 
720a69faebfSRoberto Sassu #define TPM_ORD_PCR_EXTEND 20
721ca6d4580SWinkler, Tomas #define EXTEND_PCR_RESULT_SIZE 34
72251b0be64SStefan Berger #define EXTEND_PCR_RESULT_BODY_SIZE 20
723ca6d4580SWinkler, Tomas static const struct tpm_input_header pcrextend_header = {
72406e93279SRoberto Sassu 	.tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
725ca6d4580SWinkler, Tomas 	.length = cpu_to_be32(34),
726a69faebfSRoberto Sassu 	.ordinal = cpu_to_be32(TPM_ORD_PCR_EXTEND)
727ca6d4580SWinkler, Tomas };
728ca6d4580SWinkler, Tomas 
729175d5b2aSRoberto Sassu static int tpm1_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash,
730175d5b2aSRoberto Sassu 			   char *log_msg)
731175d5b2aSRoberto Sassu {
732175d5b2aSRoberto Sassu 	struct tpm_buf buf;
733175d5b2aSRoberto Sassu 	int rc;
734175d5b2aSRoberto Sassu 
735175d5b2aSRoberto Sassu 	rc = tpm_buf_init(&buf, TPM_TAG_RQU_COMMAND, TPM_ORD_PCR_EXTEND);
736175d5b2aSRoberto Sassu 	if (rc)
737175d5b2aSRoberto Sassu 		return rc;
738175d5b2aSRoberto Sassu 
739175d5b2aSRoberto Sassu 	tpm_buf_append_u32(&buf, pcr_idx);
740175d5b2aSRoberto Sassu 	tpm_buf_append(&buf, hash, TPM_DIGEST_SIZE);
741175d5b2aSRoberto Sassu 
742175d5b2aSRoberto Sassu 	rc = tpm_transmit_cmd(chip, NULL, buf.data, EXTEND_PCR_RESULT_SIZE,
743175d5b2aSRoberto Sassu 			      EXTEND_PCR_RESULT_BODY_SIZE, 0, log_msg);
744175d5b2aSRoberto Sassu 	tpm_buf_destroy(&buf);
745175d5b2aSRoberto Sassu 	return rc;
746175d5b2aSRoberto Sassu }
747175d5b2aSRoberto Sassu 
7489deb0eb7SJason Gunthorpe /**
749aad887f6SJarkko Sakkinen  * tpm_pcr_extend - extend a PCR value in SHA1 bank.
750aad887f6SJarkko Sakkinen  * @chip:	a &struct tpm_chip instance, %NULL for the default chip
751aad887f6SJarkko Sakkinen  * @pcr_idx:	the PCR to be retrieved
752aad887f6SJarkko Sakkinen  * @hash:	the hash value used to extend the PCR value
7539deb0eb7SJason Gunthorpe  *
754aad887f6SJarkko Sakkinen  * Note: with TPM 2.0 extends also those banks with a known digest size to the
755aad887f6SJarkko Sakkinen  * cryto subsystem in order to prevent malicious use of those PCR banks. In the
756aad887f6SJarkko Sakkinen  * future we should dynamically determine digest sizes.
757aad887f6SJarkko Sakkinen  *
758aad887f6SJarkko Sakkinen  * Return: same as with tpm_transmit_cmd()
7599deb0eb7SJason Gunthorpe  */
760aad887f6SJarkko Sakkinen int tpm_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash)
7619deb0eb7SJason Gunthorpe {
7629deb0eb7SJason Gunthorpe 	int rc;
763c1f92b4bSNayna Jain 	struct tpm2_digest digest_list[ARRAY_SIZE(chip->active_banks)];
764c1f92b4bSNayna Jain 	u32 count = 0;
765c1f92b4bSNayna Jain 	int i;
7669deb0eb7SJason Gunthorpe 
767fc1d52b7SStefan Berger 	chip = tpm_find_get_ops(chip);
768aad887f6SJarkko Sakkinen 	if (!chip)
7699deb0eb7SJason Gunthorpe 		return -ENODEV;
7709deb0eb7SJason Gunthorpe 
7717a1d7e6dSJarkko Sakkinen 	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
772c1f92b4bSNayna Jain 		memset(digest_list, 0, sizeof(digest_list));
773c1f92b4bSNayna Jain 
77470ea1636SDan Carpenter 		for (i = 0; i < ARRAY_SIZE(chip->active_banks) &&
77570ea1636SDan Carpenter 			    chip->active_banks[i] != TPM2_ALG_ERROR; i++) {
776c1f92b4bSNayna Jain 			digest_list[i].alg_id = chip->active_banks[i];
777c1f92b4bSNayna Jain 			memcpy(digest_list[i].digest, hash, TPM_DIGEST_SIZE);
778c1f92b4bSNayna Jain 			count++;
779c1f92b4bSNayna Jain 		}
780c1f92b4bSNayna Jain 
781c1f92b4bSNayna Jain 		rc = tpm2_pcr_extend(chip, pcr_idx, count, digest_list);
7824e26195fSJason Gunthorpe 		tpm_put_ops(chip);
7837a1d7e6dSJarkko Sakkinen 		return rc;
7847a1d7e6dSJarkko Sakkinen 	}
7857a1d7e6dSJarkko Sakkinen 
786175d5b2aSRoberto Sassu 	rc = tpm1_pcr_extend(chip, pcr_idx, hash,
7879deb0eb7SJason Gunthorpe 			     "attempting extend a PCR value");
7884e26195fSJason Gunthorpe 	tpm_put_ops(chip);
7899deb0eb7SJason Gunthorpe 	return rc;
7909deb0eb7SJason Gunthorpe }
7919deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_pcr_extend);
7929deb0eb7SJason Gunthorpe 
7939deb0eb7SJason Gunthorpe /**
7949deb0eb7SJason Gunthorpe  * tpm_do_selftest - have the TPM continue its selftest and wait until it
7959deb0eb7SJason Gunthorpe  *                   can receive further commands
7969deb0eb7SJason Gunthorpe  * @chip: TPM chip to use
7979deb0eb7SJason Gunthorpe  *
7989deb0eb7SJason Gunthorpe  * Returns 0 on success, < 0 in case of fatal error or a value > 0 representing
7999deb0eb7SJason Gunthorpe  * a TPM error code.
8009deb0eb7SJason Gunthorpe  */
8019deb0eb7SJason Gunthorpe int tpm_do_selftest(struct tpm_chip *chip)
8029deb0eb7SJason Gunthorpe {
8039deb0eb7SJason Gunthorpe 	int rc;
8049deb0eb7SJason Gunthorpe 	unsigned int loops;
8059deb0eb7SJason Gunthorpe 	unsigned int delay_msec = 100;
8069deb0eb7SJason Gunthorpe 	unsigned long duration;
8070c541332SJarkko Sakkinen 	u8 dummy[TPM_DIGEST_SIZE];
8089deb0eb7SJason Gunthorpe 
809*b2d6e6deSTomas Winkler 	duration = tpm1_calc_ordinal_duration(chip, TPM_ORD_CONTINUE_SELFTEST);
8109deb0eb7SJason Gunthorpe 
8119deb0eb7SJason Gunthorpe 	loops = jiffies_to_msecs(duration) / delay_msec;
8129deb0eb7SJason Gunthorpe 
8139deb0eb7SJason Gunthorpe 	rc = tpm_continue_selftest(chip);
8140803d7beSChris Chiu 	if (rc == TPM_ERR_INVALID_POSTINIT) {
8150803d7beSChris Chiu 		chip->flags |= TPM_CHIP_FLAG_ALWAYS_POWERED;
8160803d7beSChris Chiu 		dev_info(&chip->dev, "TPM not ready (%d)\n", rc);
8170803d7beSChris Chiu 	}
8189deb0eb7SJason Gunthorpe 	/* This may fail if there was no TPM driver during a suspend/resume
8199deb0eb7SJason Gunthorpe 	 * cycle; some may return 10 (BAD_ORDINAL), others 28 (FAILEDSELFTEST)
8209deb0eb7SJason Gunthorpe 	 */
8219deb0eb7SJason Gunthorpe 	if (rc)
8229deb0eb7SJason Gunthorpe 		return rc;
8239deb0eb7SJason Gunthorpe 
8249deb0eb7SJason Gunthorpe 	do {
8259deb0eb7SJason Gunthorpe 		/* Attempt to read a PCR value */
8260c541332SJarkko Sakkinen 		rc = tpm_pcr_read_dev(chip, 0, dummy);
8270c541332SJarkko Sakkinen 
8289deb0eb7SJason Gunthorpe 		/* Some buggy TPMs will not respond to tpm_tis_ready() for
8299deb0eb7SJason Gunthorpe 		 * around 300ms while the self test is ongoing, keep trying
8309deb0eb7SJason Gunthorpe 		 * until the self test duration expires. */
8319deb0eb7SJason Gunthorpe 		if (rc == -ETIME) {
8328cfffc9dSJason Gunthorpe 			dev_info(
8338cfffc9dSJason Gunthorpe 			    &chip->dev, HW_ERR
8348cfffc9dSJason Gunthorpe 			    "TPM command timed out during continue self test");
8359f3fc7bcSHamza Attak 			tpm_msleep(delay_msec);
8369deb0eb7SJason Gunthorpe 			continue;
8379deb0eb7SJason Gunthorpe 		}
8389deb0eb7SJason Gunthorpe 
8399deb0eb7SJason Gunthorpe 		if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) {
8408cfffc9dSJason Gunthorpe 			dev_info(&chip->dev,
8419deb0eb7SJason Gunthorpe 				 "TPM is disabled/deactivated (0x%X)\n", rc);
8429deb0eb7SJason Gunthorpe 			/* TPM is disabled and/or deactivated; driver can
8439deb0eb7SJason Gunthorpe 			 * proceed and TPM does handle commands for
8449deb0eb7SJason Gunthorpe 			 * suspend/resume correctly
8459deb0eb7SJason Gunthorpe 			 */
8469deb0eb7SJason Gunthorpe 			return 0;
8479deb0eb7SJason Gunthorpe 		}
8489deb0eb7SJason Gunthorpe 		if (rc != TPM_WARN_DOING_SELFTEST)
8499deb0eb7SJason Gunthorpe 			return rc;
8509f3fc7bcSHamza Attak 		tpm_msleep(delay_msec);
8519deb0eb7SJason Gunthorpe 	} while (--loops > 0);
8529deb0eb7SJason Gunthorpe 
8539deb0eb7SJason Gunthorpe 	return rc;
8549deb0eb7SJason Gunthorpe }
8559deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_do_selftest);
8569deb0eb7SJason Gunthorpe 
857cae8b441SJason Gunthorpe /**
858cae8b441SJason Gunthorpe  * tpm1_auto_startup - Perform the standard automatic TPM initialization
859cae8b441SJason Gunthorpe  *                     sequence
860cae8b441SJason Gunthorpe  * @chip: TPM chip to use
861cae8b441SJason Gunthorpe  *
862cae8b441SJason Gunthorpe  * Returns 0 on success, < 0 in case of fatal error.
863cae8b441SJason Gunthorpe  */
864cae8b441SJason Gunthorpe int tpm1_auto_startup(struct tpm_chip *chip)
865cae8b441SJason Gunthorpe {
866cae8b441SJason Gunthorpe 	int rc;
867cae8b441SJason Gunthorpe 
868cae8b441SJason Gunthorpe 	rc = tpm_get_timeouts(chip);
869cae8b441SJason Gunthorpe 	if (rc)
870cae8b441SJason Gunthorpe 		goto out;
871cae8b441SJason Gunthorpe 	rc = tpm_do_selftest(chip);
872cae8b441SJason Gunthorpe 	if (rc) {
873cae8b441SJason Gunthorpe 		dev_err(&chip->dev, "TPM self test failed\n");
874cae8b441SJason Gunthorpe 		goto out;
875cae8b441SJason Gunthorpe 	}
876cae8b441SJason Gunthorpe 
877cae8b441SJason Gunthorpe 	return rc;
878cae8b441SJason Gunthorpe out:
879cae8b441SJason Gunthorpe 	if (rc > 0)
880cae8b441SJason Gunthorpe 		rc = -ENODEV;
881cae8b441SJason Gunthorpe 	return rc;
882cae8b441SJason Gunthorpe }
883cae8b441SJason Gunthorpe 
884aad887f6SJarkko Sakkinen /**
885aad887f6SJarkko Sakkinen  * tpm_send - send a TPM command
886aad887f6SJarkko Sakkinen  * @chip:	a &struct tpm_chip instance, %NULL for the default chip
887aad887f6SJarkko Sakkinen  * @cmd:	a TPM command buffer
888aad887f6SJarkko Sakkinen  * @buflen:	the length of the TPM command buffer
889aad887f6SJarkko Sakkinen  *
890aad887f6SJarkko Sakkinen  * Return: same as with tpm_transmit_cmd()
891aad887f6SJarkko Sakkinen  */
892aad887f6SJarkko Sakkinen int tpm_send(struct tpm_chip *chip, void *cmd, size_t buflen)
8939deb0eb7SJason Gunthorpe {
8949deb0eb7SJason Gunthorpe 	int rc;
8959deb0eb7SJason Gunthorpe 
896fc1d52b7SStefan Berger 	chip = tpm_find_get_ops(chip);
897aad887f6SJarkko Sakkinen 	if (!chip)
8989deb0eb7SJason Gunthorpe 		return -ENODEV;
8999deb0eb7SJason Gunthorpe 
900745b361eSJarkko Sakkinen 	rc = tpm_transmit_cmd(chip, NULL, cmd, buflen, 0, 0,
901aad887f6SJarkko Sakkinen 			      "attempting to a send a command");
9024e26195fSJason Gunthorpe 	tpm_put_ops(chip);
9039deb0eb7SJason Gunthorpe 	return rc;
9049deb0eb7SJason Gunthorpe }
9059deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_send);
9069deb0eb7SJason Gunthorpe 
907a69faebfSRoberto Sassu #define TPM_ORD_SAVESTATE 152
9089deb0eb7SJason Gunthorpe #define SAVESTATE_RESULT_SIZE 10
9099deb0eb7SJason Gunthorpe 
9100014777fSJulia Lawall static const struct tpm_input_header savestate_header = {
91106e93279SRoberto Sassu 	.tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
9129deb0eb7SJason Gunthorpe 	.length = cpu_to_be32(10),
913a69faebfSRoberto Sassu 	.ordinal = cpu_to_be32(TPM_ORD_SAVESTATE)
9149deb0eb7SJason Gunthorpe };
9159deb0eb7SJason Gunthorpe 
9169deb0eb7SJason Gunthorpe /*
9179deb0eb7SJason Gunthorpe  * We are about to suspend. Save the TPM state
9189deb0eb7SJason Gunthorpe  * so that it can be restored.
9199deb0eb7SJason Gunthorpe  */
9209deb0eb7SJason Gunthorpe int tpm_pm_suspend(struct device *dev)
9219deb0eb7SJason Gunthorpe {
922ec03c50bSStefan Berger 	struct tpm_chip *chip = dev_get_drvdata(dev);
9239deb0eb7SJason Gunthorpe 	struct tpm_cmd_t cmd;
9249deb0eb7SJason Gunthorpe 	int rc, try;
9259deb0eb7SJason Gunthorpe 
9269deb0eb7SJason Gunthorpe 	u8 dummy_hash[TPM_DIGEST_SIZE] = { 0 };
9279deb0eb7SJason Gunthorpe 
9289deb0eb7SJason Gunthorpe 	if (chip == NULL)
9299deb0eb7SJason Gunthorpe 		return -ENODEV;
9309deb0eb7SJason Gunthorpe 
931b5d0ebc9SEnric Balletbo i Serra 	if (chip->flags & TPM_CHIP_FLAG_ALWAYS_POWERED)
932b5d0ebc9SEnric Balletbo i Serra 		return 0;
933b5d0ebc9SEnric Balletbo i Serra 
93474d6b3ceSJarkko Sakkinen 	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
93574d6b3ceSJarkko Sakkinen 		tpm2_shutdown(chip, TPM2_SU_STATE);
93674d6b3ceSJarkko Sakkinen 		return 0;
93774d6b3ceSJarkko Sakkinen 	}
93830fc8d13SJarkko Sakkinen 
9399deb0eb7SJason Gunthorpe 	/* for buggy tpm, flush pcrs with extend to selected dummy */
940175d5b2aSRoberto Sassu 	if (tpm_suspend_pcr)
941175d5b2aSRoberto Sassu 		rc = tpm1_pcr_extend(chip, tpm_suspend_pcr, dummy_hash,
9429deb0eb7SJason Gunthorpe 				     "extending dummy pcr before suspend");
9439deb0eb7SJason Gunthorpe 
9449deb0eb7SJason Gunthorpe 	/* now do the actual savestate */
9459deb0eb7SJason Gunthorpe 	for (try = 0; try < TPM_RETRY; try++) {
9469deb0eb7SJason Gunthorpe 		cmd.header.in = savestate_header;
947745b361eSJarkko Sakkinen 		rc = tpm_transmit_cmd(chip, NULL, &cmd, SAVESTATE_RESULT_SIZE,
948745b361eSJarkko Sakkinen 				      0, 0, NULL);
9499deb0eb7SJason Gunthorpe 
9509deb0eb7SJason Gunthorpe 		/*
9519deb0eb7SJason Gunthorpe 		 * If the TPM indicates that it is too busy to respond to
9529deb0eb7SJason Gunthorpe 		 * this command then retry before giving up.  It can take
9539deb0eb7SJason Gunthorpe 		 * several seconds for this TPM to be ready.
9549deb0eb7SJason Gunthorpe 		 *
9559deb0eb7SJason Gunthorpe 		 * This can happen if the TPM has already been sent the
9569deb0eb7SJason Gunthorpe 		 * SaveState command before the driver has loaded.  TCG 1.2
9579deb0eb7SJason Gunthorpe 		 * specification states that any communication after SaveState
9589deb0eb7SJason Gunthorpe 		 * may cause the TPM to invalidate previously saved state.
9599deb0eb7SJason Gunthorpe 		 */
9609deb0eb7SJason Gunthorpe 		if (rc != TPM_WARN_RETRY)
9619deb0eb7SJason Gunthorpe 			break;
9629f3fc7bcSHamza Attak 		tpm_msleep(TPM_TIMEOUT_RETRY);
9639deb0eb7SJason Gunthorpe 	}
9649deb0eb7SJason Gunthorpe 
9659deb0eb7SJason Gunthorpe 	if (rc)
9668cfffc9dSJason Gunthorpe 		dev_err(&chip->dev,
9679deb0eb7SJason Gunthorpe 			"Error (%d) sending savestate before suspend\n", rc);
9689deb0eb7SJason Gunthorpe 	else if (try > 0)
9698cfffc9dSJason Gunthorpe 		dev_warn(&chip->dev, "TPM savestate took %dms\n",
9709deb0eb7SJason Gunthorpe 			 try * TPM_TIMEOUT_RETRY);
9719deb0eb7SJason Gunthorpe 
9729deb0eb7SJason Gunthorpe 	return rc;
9739deb0eb7SJason Gunthorpe }
9749deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_pm_suspend);
9759deb0eb7SJason Gunthorpe 
9769deb0eb7SJason Gunthorpe /*
9779deb0eb7SJason Gunthorpe  * Resume from a power safe. The BIOS already restored
9789deb0eb7SJason Gunthorpe  * the TPM state.
9799deb0eb7SJason Gunthorpe  */
9809deb0eb7SJason Gunthorpe int tpm_pm_resume(struct device *dev)
9819deb0eb7SJason Gunthorpe {
982ec03c50bSStefan Berger 	struct tpm_chip *chip = dev_get_drvdata(dev);
9839deb0eb7SJason Gunthorpe 
9849deb0eb7SJason Gunthorpe 	if (chip == NULL)
9859deb0eb7SJason Gunthorpe 		return -ENODEV;
9869deb0eb7SJason Gunthorpe 
9879deb0eb7SJason Gunthorpe 	return 0;
9889deb0eb7SJason Gunthorpe }
9899deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_pm_resume);
9909deb0eb7SJason Gunthorpe 
9919deb0eb7SJason Gunthorpe #define TPM_GETRANDOM_RESULT_SIZE	18
9920014777fSJulia Lawall static const struct tpm_input_header tpm_getrandom_header = {
99306e93279SRoberto Sassu 	.tag = cpu_to_be16(TPM_TAG_RQU_COMMAND),
9949deb0eb7SJason Gunthorpe 	.length = cpu_to_be32(14),
995a69faebfSRoberto Sassu 	.ordinal = cpu_to_be32(TPM_ORD_GET_RANDOM)
9969deb0eb7SJason Gunthorpe };
9979deb0eb7SJason Gunthorpe 
9989deb0eb7SJason Gunthorpe /**
999aad887f6SJarkko Sakkinen  * tpm_get_random() - get random bytes from the TPM's RNG
1000aad887f6SJarkko Sakkinen  * @chip:	a &struct tpm_chip instance, %NULL for the default chip
10019deb0eb7SJason Gunthorpe  * @out:	destination buffer for the random bytes
10029deb0eb7SJason Gunthorpe  * @max:	the max number of bytes to write to @out
10039deb0eb7SJason Gunthorpe  *
1004aad887f6SJarkko Sakkinen  * Return: same as with tpm_transmit_cmd()
10059deb0eb7SJason Gunthorpe  */
1006aad887f6SJarkko Sakkinen int tpm_get_random(struct tpm_chip *chip, u8 *out, size_t max)
10079deb0eb7SJason Gunthorpe {
10089deb0eb7SJason Gunthorpe 	struct tpm_cmd_t tpm_cmd;
1009c659af78SStefan Berger 	u32 recd, num_bytes = min_t(u32, max, TPM_MAX_RNG_DATA), rlength;
10109deb0eb7SJason Gunthorpe 	int err, total = 0, retries = 5;
10119deb0eb7SJason Gunthorpe 	u8 *dest = out;
10129deb0eb7SJason Gunthorpe 
10133e14d83eSJarkko Sakkinen 	if (!out || !num_bytes || max > TPM_MAX_RNG_DATA)
10143e14d83eSJarkko Sakkinen 		return -EINVAL;
10153e14d83eSJarkko Sakkinen 
1016fc1d52b7SStefan Berger 	chip = tpm_find_get_ops(chip);
1017aad887f6SJarkko Sakkinen 	if (!chip)
10189deb0eb7SJason Gunthorpe 		return -ENODEV;
10199deb0eb7SJason Gunthorpe 
10207a1d7e6dSJarkko Sakkinen 	if (chip->flags & TPM_CHIP_FLAG_TPM2) {
10217a1d7e6dSJarkko Sakkinen 		err = tpm2_get_random(chip, out, max);
10224e26195fSJason Gunthorpe 		tpm_put_ops(chip);
10237a1d7e6dSJarkko Sakkinen 		return err;
10247a1d7e6dSJarkko Sakkinen 	}
10257a1d7e6dSJarkko Sakkinen 
10269deb0eb7SJason Gunthorpe 	do {
10279deb0eb7SJason Gunthorpe 		tpm_cmd.header.in = tpm_getrandom_header;
10289deb0eb7SJason Gunthorpe 		tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
10299deb0eb7SJason Gunthorpe 
1030745b361eSJarkko Sakkinen 		err = tpm_transmit_cmd(chip, NULL, &tpm_cmd,
10319deb0eb7SJason Gunthorpe 				       TPM_GETRANDOM_RESULT_SIZE + num_bytes,
1032c659af78SStefan Berger 				       offsetof(struct tpm_getrandom_out,
1033c659af78SStefan Berger 						rng_data),
1034d4816edfSJarkko Sakkinen 				       0, "attempting get random");
10359deb0eb7SJason Gunthorpe 		if (err)
10369deb0eb7SJason Gunthorpe 			break;
10379deb0eb7SJason Gunthorpe 
10389deb0eb7SJason Gunthorpe 		recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len);
10393be23274SJeremy Boone 		if (recd > num_bytes) {
10403be23274SJeremy Boone 			total = -EFAULT;
10413be23274SJeremy Boone 			break;
10423be23274SJeremy Boone 		}
1043c659af78SStefan Berger 
1044c659af78SStefan Berger 		rlength = be32_to_cpu(tpm_cmd.header.out.length);
104584b59f64SJarkko Sakkinen 		if (rlength < TPM_HEADER_SIZE +
104684b59f64SJarkko Sakkinen 			      offsetof(struct tpm_getrandom_out, rng_data) +
1047c659af78SStefan Berger 			      recd) {
1048c659af78SStefan Berger 			total = -EFAULT;
1049c659af78SStefan Berger 			break;
1050c659af78SStefan Berger 		}
10519deb0eb7SJason Gunthorpe 		memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd);
10529deb0eb7SJason Gunthorpe 
10539deb0eb7SJason Gunthorpe 		dest += recd;
10549deb0eb7SJason Gunthorpe 		total += recd;
10559deb0eb7SJason Gunthorpe 		num_bytes -= recd;
10569deb0eb7SJason Gunthorpe 	} while (retries-- && total < max);
10579deb0eb7SJason Gunthorpe 
10584e26195fSJason Gunthorpe 	tpm_put_ops(chip);
10599deb0eb7SJason Gunthorpe 	return total ? total : -EIO;
10609deb0eb7SJason Gunthorpe }
10619deb0eb7SJason Gunthorpe EXPORT_SYMBOL_GPL(tpm_get_random);
10629deb0eb7SJason Gunthorpe 
1063954650efSJarkko Sakkinen /**
1064aad887f6SJarkko Sakkinen  * tpm_seal_trusted() - seal a trusted key payload
1065aad887f6SJarkko Sakkinen  * @chip:	a &struct tpm_chip instance, %NULL for the default chip
1066954650efSJarkko Sakkinen  * @options:	authentication values and other options
1067954650efSJarkko Sakkinen  * @payload:	the key data in clear and encrypted form
1068954650efSJarkko Sakkinen  *
1069aad887f6SJarkko Sakkinen  * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in
1070aad887f6SJarkko Sakkinen  * the keyring subsystem.
1071aad887f6SJarkko Sakkinen  *
1072aad887f6SJarkko Sakkinen  * Return: same as with tpm_transmit_cmd()
1073954650efSJarkko Sakkinen  */
1074aad887f6SJarkko Sakkinen int tpm_seal_trusted(struct tpm_chip *chip, struct trusted_key_payload *payload,
1075954650efSJarkko Sakkinen 		     struct trusted_key_options *options)
1076954650efSJarkko Sakkinen {
1077954650efSJarkko Sakkinen 	int rc;
1078954650efSJarkko Sakkinen 
1079fc1d52b7SStefan Berger 	chip = tpm_find_get_ops(chip);
1080aad887f6SJarkko Sakkinen 	if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2))
1081954650efSJarkko Sakkinen 		return -ENODEV;
1082954650efSJarkko Sakkinen 
1083954650efSJarkko Sakkinen 	rc = tpm2_seal_trusted(chip, payload, options);
1084954650efSJarkko Sakkinen 
10854e26195fSJason Gunthorpe 	tpm_put_ops(chip);
1086954650efSJarkko Sakkinen 	return rc;
1087954650efSJarkko Sakkinen }
1088954650efSJarkko Sakkinen EXPORT_SYMBOL_GPL(tpm_seal_trusted);
1089954650efSJarkko Sakkinen 
1090954650efSJarkko Sakkinen /**
1091954650efSJarkko Sakkinen  * tpm_unseal_trusted() - unseal a trusted key
1092aad887f6SJarkko Sakkinen  * @chip:	a &struct tpm_chip instance, %NULL for the default chip
1093954650efSJarkko Sakkinen  * @options:	authentication values and other options
1094954650efSJarkko Sakkinen  * @payload:	the key data in clear and encrypted form
1095954650efSJarkko Sakkinen  *
1096aad887f6SJarkko Sakkinen  * Note: only TPM 2.0 chip are supported. TPM 1.x implementation is located in
1097aad887f6SJarkko Sakkinen  * the keyring subsystem.
1098aad887f6SJarkko Sakkinen  *
1099aad887f6SJarkko Sakkinen  * Return: same as with tpm_transmit_cmd()
1100954650efSJarkko Sakkinen  */
1101aad887f6SJarkko Sakkinen int tpm_unseal_trusted(struct tpm_chip *chip,
1102aad887f6SJarkko Sakkinen 		       struct trusted_key_payload *payload,
1103954650efSJarkko Sakkinen 		       struct trusted_key_options *options)
1104954650efSJarkko Sakkinen {
1105954650efSJarkko Sakkinen 	int rc;
1106954650efSJarkko Sakkinen 
1107fc1d52b7SStefan Berger 	chip = tpm_find_get_ops(chip);
1108aad887f6SJarkko Sakkinen 	if (!chip || !(chip->flags & TPM_CHIP_FLAG_TPM2))
1109954650efSJarkko Sakkinen 		return -ENODEV;
1110954650efSJarkko Sakkinen 
1111954650efSJarkko Sakkinen 	rc = tpm2_unseal_trusted(chip, payload, options);
1112954650efSJarkko Sakkinen 
11134e26195fSJason Gunthorpe 	tpm_put_ops(chip);
11144e26195fSJason Gunthorpe 
1115954650efSJarkko Sakkinen 	return rc;
1116954650efSJarkko Sakkinen }
1117954650efSJarkko Sakkinen EXPORT_SYMBOL_GPL(tpm_unseal_trusted);
1118954650efSJarkko Sakkinen 
1119313d21eeSJarkko Sakkinen static int __init tpm_init(void)
1120313d21eeSJarkko Sakkinen {
1121313d21eeSJarkko Sakkinen 	int rc;
1122313d21eeSJarkko Sakkinen 
1123313d21eeSJarkko Sakkinen 	tpm_class = class_create(THIS_MODULE, "tpm");
1124313d21eeSJarkko Sakkinen 	if (IS_ERR(tpm_class)) {
1125313d21eeSJarkko Sakkinen 		pr_err("couldn't create tpm class\n");
1126313d21eeSJarkko Sakkinen 		return PTR_ERR(tpm_class);
1127313d21eeSJarkko Sakkinen 	}
1128313d21eeSJarkko Sakkinen 
1129fdc915f7SJames Bottomley 	tpmrm_class = class_create(THIS_MODULE, "tpmrm");
1130fdc915f7SJames Bottomley 	if (IS_ERR(tpmrm_class)) {
1131fdc915f7SJames Bottomley 		pr_err("couldn't create tpmrm class\n");
11329e1b74a6STadeusz Struk 		rc = PTR_ERR(tpmrm_class);
11339e1b74a6STadeusz Struk 		goto out_destroy_tpm_class;
1134fdc915f7SJames Bottomley 	}
1135fdc915f7SJames Bottomley 
1136fdc915f7SJames Bottomley 	rc = alloc_chrdev_region(&tpm_devt, 0, 2*TPM_NUM_DEVICES, "tpm");
1137313d21eeSJarkko Sakkinen 	if (rc < 0) {
1138313d21eeSJarkko Sakkinen 		pr_err("tpm: failed to allocate char dev region\n");
11399e1b74a6STadeusz Struk 		goto out_destroy_tpmrm_class;
11409e1b74a6STadeusz Struk 	}
11419e1b74a6STadeusz Struk 
11429e1b74a6STadeusz Struk 	rc = tpm_dev_common_init();
11439e1b74a6STadeusz Struk 	if (rc) {
11449e1b74a6STadeusz Struk 		pr_err("tpm: failed to allocate char dev region\n");
11459e1b74a6STadeusz Struk 		goto out_unreg_chrdev;
1146313d21eeSJarkko Sakkinen 	}
1147313d21eeSJarkko Sakkinen 
1148313d21eeSJarkko Sakkinen 	return 0;
11499e1b74a6STadeusz Struk 
11509e1b74a6STadeusz Struk out_unreg_chrdev:
11519e1b74a6STadeusz Struk 	unregister_chrdev_region(tpm_devt, 2 * TPM_NUM_DEVICES);
11529e1b74a6STadeusz Struk out_destroy_tpmrm_class:
11539e1b74a6STadeusz Struk 	class_destroy(tpmrm_class);
11549e1b74a6STadeusz Struk out_destroy_tpm_class:
11559e1b74a6STadeusz Struk 	class_destroy(tpm_class);
11569e1b74a6STadeusz Struk 
11579e1b74a6STadeusz Struk 	return rc;
1158313d21eeSJarkko Sakkinen }
1159313d21eeSJarkko Sakkinen 
1160313d21eeSJarkko Sakkinen static void __exit tpm_exit(void)
1161313d21eeSJarkko Sakkinen {
116215516788SStefan Berger 	idr_destroy(&dev_nums_idr);
1163313d21eeSJarkko Sakkinen 	class_destroy(tpm_class);
1164fdc915f7SJames Bottomley 	class_destroy(tpmrm_class);
1165fdc915f7SJames Bottomley 	unregister_chrdev_region(tpm_devt, 2*TPM_NUM_DEVICES);
11669e1b74a6STadeusz Struk 	tpm_dev_common_exit();
1167313d21eeSJarkko Sakkinen }
1168313d21eeSJarkko Sakkinen 
1169313d21eeSJarkko Sakkinen subsys_initcall(tpm_init);
1170313d21eeSJarkko Sakkinen module_exit(tpm_exit);
1171313d21eeSJarkko Sakkinen 
11729deb0eb7SJason Gunthorpe MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
11739deb0eb7SJason Gunthorpe MODULE_DESCRIPTION("TPM Driver");
11749deb0eb7SJason Gunthorpe MODULE_VERSION("2.0");
11759deb0eb7SJason Gunthorpe MODULE_LICENSE("GPL");
1176