File Index
Files and directories
Sign in
FILE

xen-tpmfront.c

File preview with syntax highlighting.

linux-6.19.14/drivers/char/tpm/xen-tpmfront.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Implementation of the Xen vTPM device frontend
  4 *
  5 * Author:  Daniel De Graaf <dgdegra@tycho.nsa.gov>
  6 */
  7#include <linux/errno.h>
  8#include <linux/err.h>
  9#include <linux/interrupt.h>
 10#include <linux/freezer.h>
 11#include <xen/xen.h>
 12#include <xen/events.h>
 13#include <xen/interface/io/tpmif.h>
 14#include <xen/grant_table.h>
 15#include <xen/xenbus.h>
 16#include <xen/page.h>
 17#include "tpm.h"
 18#include <xen/platform_pci.h>
 19
 20struct tpm_private {
 21	struct tpm_chip *chip;
 22	struct xenbus_device *dev;
 23
 24	struct vtpm_shared_page *shr;
 25
 26	unsigned int evtchn;
 27	int ring_ref;
 28	domid_t backend_id;
 29	int irq;
 30	wait_queue_head_t read_queue;
 31};
 32
 33enum status_bits {
 34	VTPM_STATUS_RUNNING  = 0x1,
 35	VTPM_STATUS_IDLE     = 0x2,
 36	VTPM_STATUS_RESULT   = 0x4,
 37	VTPM_STATUS_CANCELED = 0x8,
 38};
 39
 40static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
 41					bool check_cancel, bool *canceled)
 42{
 43	u8 status = chip->ops->status(chip);
 44
 45	*canceled = false;
 46	if ((status & mask) == mask)
 47		return true;
 48	if (check_cancel && chip->ops->req_canceled(chip, status)) {
 49		*canceled = true;
 50		return true;
 51	}
 52	return false;
 53}
 54
 55static int wait_for_tpm_stat(struct tpm_chip *chip, u8 mask,
 56		unsigned long timeout, wait_queue_head_t *queue,
 57		bool check_cancel)
 58{
 59	unsigned long stop;
 60	long rc;
 61	u8 status;
 62	bool canceled = false;
 63
 64	/* check current status */
 65	status = chip->ops->status(chip);
 66	if ((status & mask) == mask)
 67		return 0;
 68
 69	stop = jiffies + timeout;
 70
 71	if (chip->flags & TPM_CHIP_FLAG_IRQ) {
 72again:
 73		timeout = stop - jiffies;
 74		if ((long)timeout <= 0)
 75			return -ETIME;
 76		rc = wait_event_interruptible_timeout(*queue,
 77			wait_for_tpm_stat_cond(chip, mask, check_cancel,
 78					       &canceled),
 79			timeout);
 80		if (rc > 0) {
 81			if (canceled)
 82				return -ECANCELED;
 83			return 0;
 84		}
 85		if (rc == -ERESTARTSYS && freezing(current)) {
 86			clear_thread_flag(TIF_SIGPENDING);
 87			goto again;
 88		}
 89	} else {
 90		do {
 91			tpm_msleep(TPM_TIMEOUT);
 92			status = chip->ops->status(chip);
 93			if ((status & mask) == mask)
 94				return 0;
 95		} while (time_before(jiffies, stop));
 96	}
 97	return -ETIME;
 98}
 99
100static u8 vtpm_status(struct tpm_chip *chip)
101{
102	struct tpm_private *priv = dev_get_drvdata(&chip->dev);
103	switch (priv->shr->state) {
104	case VTPM_STATE_IDLE:
105		return VTPM_STATUS_IDLE | VTPM_STATUS_CANCELED;
106	case VTPM_STATE_FINISH:
107		return VTPM_STATUS_IDLE | VTPM_STATUS_RESULT;
108	case VTPM_STATE_SUBMIT:
109	case VTPM_STATE_CANCEL: /* cancel requested, not yet canceled */
110		return VTPM_STATUS_RUNNING;
111	default:
112		return 0;
113	}
114}
115
116static bool vtpm_req_canceled(struct tpm_chip *chip, u8 status)
117{
118	return status & VTPM_STATUS_CANCELED;
119}
120
121static void vtpm_cancel(struct tpm_chip *chip)
122{
123	struct tpm_private *priv = dev_get_drvdata(&chip->dev);
124	priv->shr->state = VTPM_STATE_CANCEL;
125	wmb();
126	notify_remote_via_evtchn(priv->evtchn);
127}
128
129static size_t shr_data_offset(struct vtpm_shared_page *shr)
130{
131	return struct_size(shr, extra_pages, shr->nr_extra_pages);
132}
133
134static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t bufsiz,
135		     size_t count)
136{
137	struct tpm_private *priv = dev_get_drvdata(&chip->dev);
138	struct vtpm_shared_page *shr = priv->shr;
139	size_t offset = shr_data_offset(shr);
140
141	u32 ordinal;
142	unsigned long duration;
143
144	if (offset > PAGE_SIZE)
145		return -EINVAL;
146
147	if (offset + count > PAGE_SIZE)
148		return -EINVAL;
149
150	/* Wait for completion of any existing command or cancellation */
151	if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, chip->timeout_c,
152			&priv->read_queue, true) < 0) {
153		vtpm_cancel(chip);
154		return -ETIME;
155	}
156
157	memcpy(offset + (u8 *)shr, buf, count);
158	shr->length = count;
159	barrier();
160	shr->state = VTPM_STATE_SUBMIT;
161	wmb();
162	notify_remote_via_evtchn(priv->evtchn);
163
164	ordinal = be32_to_cpu(((struct tpm_header *)buf)->ordinal);
165	duration = tpm_calc_ordinal_duration(chip, ordinal);
166
167	if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, duration,
168			&priv->read_queue, true) < 0) {
169		/* got a signal or timeout, try to cancel */
170		vtpm_cancel(chip);
171		return -ETIME;
172	}
173
174	return 0;
175}
176
177static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)
178{
179	struct tpm_private *priv = dev_get_drvdata(&chip->dev);
180	struct vtpm_shared_page *shr = priv->shr;
181	size_t offset = shr_data_offset(shr);
182	size_t length = shr->length;
183
184	if (shr->state == VTPM_STATE_IDLE)
185		return -ECANCELED;
186
187	/* In theory the wait at the end of _send makes this one unnecessary */
188	if (wait_for_tpm_stat(chip, VTPM_STATUS_RESULT, chip->timeout_c,
189			&priv->read_queue, true) < 0) {
190		vtpm_cancel(chip);
191		return -ETIME;
192	}
193
194	if (offset > PAGE_SIZE)
195		return -EIO;
196
197	if (offset + length > PAGE_SIZE)
198		length = PAGE_SIZE - offset;
199
200	if (length > count)
201		length = count;
202
203	memcpy(buf, offset + (u8 *)shr, length);
204
205	return length;
206}
207
208static const struct tpm_class_ops tpm_vtpm = {
209	.status = vtpm_status,
210	.recv = vtpm_recv,
211	.send = vtpm_send,
212	.cancel = vtpm_cancel,
213	.req_complete_mask = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT,
214	.req_complete_val  = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT,
215	.req_canceled      = vtpm_req_canceled,
216};
217
218static irqreturn_t tpmif_interrupt(int dummy, void *dev_id)
219{
220	struct tpm_private *priv = dev_id;
221
222	switch (priv->shr->state) {
223	case VTPM_STATE_IDLE:
224	case VTPM_STATE_FINISH:
225		wake_up_interruptible(&priv->read_queue);
226		break;
227	case VTPM_STATE_SUBMIT:
228	case VTPM_STATE_CANCEL:
229	default:
230		break;
231	}
232	return IRQ_HANDLED;
233}
234
235static int setup_chip(struct device *dev, struct tpm_private *priv)
236{
237	struct tpm_chip *chip;
238
239	chip = tpmm_chip_alloc(dev, &tpm_vtpm);
240	if (IS_ERR(chip))
241		return PTR_ERR(chip);
242
243	init_waitqueue_head(&priv->read_queue);
244
245	priv->chip = chip;
246	dev_set_drvdata(&chip->dev, priv);
247
248	return 0;
249}
250
251/* caller must clean up in case of errors */
252static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv)
253{
254	struct xenbus_transaction xbt;
255	const char *message = NULL;
256	int rv;
257
258	rv = xenbus_setup_ring(dev, GFP_KERNEL, (void **)&priv->shr, 1,
259			       &priv->ring_ref);
260	if (rv < 0)
261		return rv;
262
263	rv = xenbus_alloc_evtchn(dev, &priv->evtchn);
264	if (rv)
265		return rv;
266
267	rv = bind_evtchn_to_irqhandler(priv->evtchn, tpmif_interrupt, 0,
268				       "tpmif", priv);
269	if (rv <= 0) {
270		xenbus_dev_fatal(dev, rv, "allocating TPM irq");
271		return rv;
272	}
273	priv->irq = rv;
274
275 again:
276	rv = xenbus_transaction_start(&xbt);
277	if (rv) {
278		xenbus_dev_fatal(dev, rv, "starting transaction");
279		return rv;
280	}
281
282	rv = xenbus_printf(xbt, dev->nodename,
283			"ring-ref", "%u", priv->ring_ref);
284	if (rv) {
285		message = "writing ring-ref";
286		goto abort_transaction;
287	}
288
289	rv = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
290			priv->evtchn);
291	if (rv) {
292		message = "writing event-channel";
293		goto abort_transaction;
294	}
295
296	rv = xenbus_printf(xbt, dev->nodename, "feature-protocol-v2", "1");
297	if (rv) {
298		message = "writing feature-protocol-v2";
299		goto abort_transaction;
300	}
301
302	rv = xenbus_transaction_end(xbt, 0);
303	if (rv == -EAGAIN)
304		goto again;
305	if (rv) {
306		xenbus_dev_fatal(dev, rv, "completing transaction");
307		return rv;
308	}
309
310	xenbus_switch_state(dev, XenbusStateInitialised);
311
312	return 0;
313
314 abort_transaction:
315	xenbus_transaction_end(xbt, 1);
316	if (message)
317		xenbus_dev_error(dev, rv, "%s", message);
318
319	return rv;
320}
321
322static void ring_free(struct tpm_private *priv)
323{
324	if (!priv)
325		return;
326
327	xenbus_teardown_ring((void **)&priv->shr, 1, &priv->ring_ref);
328
329	if (priv->irq)
330		unbind_from_irqhandler(priv->irq, priv);
331
332	kfree(priv);
333}
334
335static int tpmfront_probe(struct xenbus_device *dev,
336		const struct xenbus_device_id *id)
337{
338	struct tpm_private *priv;
339	int rv;
340
341	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
342	if (!priv) {
343		xenbus_dev_fatal(dev, -ENOMEM, "allocating priv structure");
344		return -ENOMEM;
345	}
346
347	rv = setup_chip(&dev->dev, priv);
348	if (rv) {
349		kfree(priv);
350		return rv;
351	}
352
353	rv = setup_ring(dev, priv);
354	if (rv) {
355		ring_free(priv);
356		return rv;
357	}
358
359	tpm_get_timeouts(priv->chip);
360
361	return tpm_chip_register(priv->chip);
362}
363
364static void tpmfront_remove(struct xenbus_device *dev)
365{
366	struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
367	struct tpm_private *priv = dev_get_drvdata(&chip->dev);
368	tpm_chip_unregister(chip);
369	ring_free(priv);
370	dev_set_drvdata(&chip->dev, NULL);
371}
372
373static int tpmfront_resume(struct xenbus_device *dev)
374{
375	/* A suspend/resume/migrate will interrupt a vTPM anyway */
376	tpmfront_remove(dev);
377	return tpmfront_probe(dev, NULL);
378}
379
380static void backend_changed(struct xenbus_device *dev,
381		enum xenbus_state backend_state)
382{
383	switch (backend_state) {
384	case XenbusStateInitialised:
385	case XenbusStateConnected:
386		if (dev->state == XenbusStateConnected)
387			break;
388
389		if (!xenbus_read_unsigned(dev->otherend, "feature-protocol-v2",
390					  0)) {
391			xenbus_dev_fatal(dev, -EINVAL,
392					"vTPM protocol 2 required");
393			return;
394		}
395		xenbus_switch_state(dev, XenbusStateConnected);
396		break;
397
398	case XenbusStateClosing:
399	case XenbusStateClosed:
400		device_unregister(&dev->dev);
401		xenbus_frontend_closed(dev);
402		break;
403	default:
404		break;
405	}
406}
407
408static const struct xenbus_device_id tpmfront_ids[] = {
409	{ "vtpm" },
410	{ "" }
411};
412MODULE_ALIAS("xen:vtpm");
413
414static struct xenbus_driver tpmfront_driver = {
415	.ids = tpmfront_ids,
416	.probe = tpmfront_probe,
417	.remove = tpmfront_remove,
418	.resume = tpmfront_resume,
419	.otherend_changed = backend_changed,
420};
421
422static int __init xen_tpmfront_init(void)
423{
424	if (!xen_domain())
425		return -ENODEV;
426
427	if (!xen_has_pv_devices())
428		return -ENODEV;
429
430	return xenbus_register_frontend(&tpmfront_driver);
431}
432module_init(xen_tpmfront_init);
433
434static void __exit xen_tpmfront_exit(void)
435{
436	xenbus_unregister_driver(&tpmfront_driver);
437}
438module_exit(xen_tpmfront_exit);
439
440MODULE_AUTHOR("Daniel De Graaf <dgdegra@tycho.nsa.gov>");
441MODULE_DESCRIPTION("Xen vTPM Driver");
442MODULE_LICENSE("GPL");
~/ Read-only file preview.