brintos

brintos / linux-shallow public Read only

0
0
Text · 9.4 KiB · 80cca3b Raw
442 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Implementation of the Xen vTPM device frontend4 *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 count)135{136	struct tpm_private *priv = dev_get_drvdata(&chip->dev);137	struct vtpm_shared_page *shr = priv->shr;138	size_t offset = shr_data_offset(shr);139 140	u32 ordinal;141	unsigned long duration;142 143	if (offset > PAGE_SIZE)144		return -EINVAL;145 146	if (offset + count > PAGE_SIZE)147		return -EINVAL;148 149	/* Wait for completion of any existing command or cancellation */150	if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, chip->timeout_c,151			&priv->read_queue, true) < 0) {152		vtpm_cancel(chip);153		return -ETIME;154	}155 156	memcpy(offset + (u8 *)shr, buf, count);157	shr->length = count;158	barrier();159	shr->state = VTPM_STATE_SUBMIT;160	wmb();161	notify_remote_via_evtchn(priv->evtchn);162 163	ordinal = be32_to_cpu(((struct tpm_header *)buf)->ordinal);164	duration = tpm_calc_ordinal_duration(chip, ordinal);165 166	if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, duration,167			&priv->read_queue, true) < 0) {168		/* got a signal or timeout, try to cancel */169		vtpm_cancel(chip);170		return -ETIME;171	}172 173	return 0;174}175 176static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count)177{178	struct tpm_private *priv = dev_get_drvdata(&chip->dev);179	struct vtpm_shared_page *shr = priv->shr;180	size_t offset = shr_data_offset(shr);181	size_t length = shr->length;182 183	if (shr->state == VTPM_STATE_IDLE)184		return -ECANCELED;185 186	/* In theory the wait at the end of _send makes this one unnecessary */187	if (wait_for_tpm_stat(chip, VTPM_STATUS_RESULT, chip->timeout_c,188			&priv->read_queue, true) < 0) {189		vtpm_cancel(chip);190		return -ETIME;191	}192 193	if (offset > PAGE_SIZE)194		return -EIO;195 196	if (offset + length > PAGE_SIZE)197		length = PAGE_SIZE - offset;198 199	if (length > count)200		length = count;201 202	memcpy(buf, offset + (u8 *)shr, length);203 204	return length;205}206 207static const struct tpm_class_ops tpm_vtpm = {208	.status = vtpm_status,209	.recv = vtpm_recv,210	.send = vtpm_send,211	.cancel = vtpm_cancel,212	.req_complete_mask = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT,213	.req_complete_val  = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT,214	.req_canceled      = vtpm_req_canceled,215};216 217static irqreturn_t tpmif_interrupt(int dummy, void *dev_id)218{219	struct tpm_private *priv = dev_id;220 221	switch (priv->shr->state) {222	case VTPM_STATE_IDLE:223	case VTPM_STATE_FINISH:224		wake_up_interruptible(&priv->read_queue);225		break;226	case VTPM_STATE_SUBMIT:227	case VTPM_STATE_CANCEL:228	default:229		break;230	}231	return IRQ_HANDLED;232}233 234static int setup_chip(struct device *dev, struct tpm_private *priv)235{236	struct tpm_chip *chip;237 238	chip = tpmm_chip_alloc(dev, &tpm_vtpm);239	if (IS_ERR(chip))240		return PTR_ERR(chip);241 242	init_waitqueue_head(&priv->read_queue);243 244	priv->chip = chip;245	dev_set_drvdata(&chip->dev, priv);246 247	return 0;248}249 250/* caller must clean up in case of errors */251static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv)252{253	struct xenbus_transaction xbt;254	const char *message = NULL;255	int rv;256 257	rv = xenbus_setup_ring(dev, GFP_KERNEL, (void **)&priv->shr, 1,258			       &priv->ring_ref);259	if (rv < 0)260		return rv;261 262	rv = xenbus_alloc_evtchn(dev, &priv->evtchn);263	if (rv)264		return rv;265 266	rv = bind_evtchn_to_irqhandler(priv->evtchn, tpmif_interrupt, 0,267				       "tpmif", priv);268	if (rv <= 0) {269		xenbus_dev_fatal(dev, rv, "allocating TPM irq");270		return rv;271	}272	priv->irq = rv;273 274 again:275	rv = xenbus_transaction_start(&xbt);276	if (rv) {277		xenbus_dev_fatal(dev, rv, "starting transaction");278		return rv;279	}280 281	rv = xenbus_printf(xbt, dev->nodename,282			"ring-ref", "%u", priv->ring_ref);283	if (rv) {284		message = "writing ring-ref";285		goto abort_transaction;286	}287 288	rv = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",289			priv->evtchn);290	if (rv) {291		message = "writing event-channel";292		goto abort_transaction;293	}294 295	rv = xenbus_printf(xbt, dev->nodename, "feature-protocol-v2", "1");296	if (rv) {297		message = "writing feature-protocol-v2";298		goto abort_transaction;299	}300 301	rv = xenbus_transaction_end(xbt, 0);302	if (rv == -EAGAIN)303		goto again;304	if (rv) {305		xenbus_dev_fatal(dev, rv, "completing transaction");306		return rv;307	}308 309	xenbus_switch_state(dev, XenbusStateInitialised);310 311	return 0;312 313 abort_transaction:314	xenbus_transaction_end(xbt, 1);315	if (message)316		xenbus_dev_error(dev, rv, "%s", message);317 318	return rv;319}320 321static void ring_free(struct tpm_private *priv)322{323	if (!priv)324		return;325 326	xenbus_teardown_ring((void **)&priv->shr, 1, &priv->ring_ref);327 328	if (priv->irq)329		unbind_from_irqhandler(priv->irq, priv);330 331	kfree(priv);332}333 334static int tpmfront_probe(struct xenbus_device *dev,335		const struct xenbus_device_id *id)336{337	struct tpm_private *priv;338	int rv;339 340	priv = kzalloc(sizeof(*priv), GFP_KERNEL);341	if (!priv) {342		xenbus_dev_fatal(dev, -ENOMEM, "allocating priv structure");343		return -ENOMEM;344	}345 346	rv = setup_chip(&dev->dev, priv);347	if (rv) {348		kfree(priv);349		return rv;350	}351 352	rv = setup_ring(dev, priv);353	if (rv) {354		ring_free(priv);355		return rv;356	}357 358	tpm_get_timeouts(priv->chip);359 360	return tpm_chip_register(priv->chip);361}362 363static void tpmfront_remove(struct xenbus_device *dev)364{365	struct tpm_chip *chip = dev_get_drvdata(&dev->dev);366	struct tpm_private *priv = dev_get_drvdata(&chip->dev);367	tpm_chip_unregister(chip);368	ring_free(priv);369	dev_set_drvdata(&chip->dev, NULL);370}371 372static int tpmfront_resume(struct xenbus_device *dev)373{374	/* A suspend/resume/migrate will interrupt a vTPM anyway */375	tpmfront_remove(dev);376	return tpmfront_probe(dev, NULL);377}378 379static void backend_changed(struct xenbus_device *dev,380		enum xenbus_state backend_state)381{382	switch (backend_state) {383	case XenbusStateInitialised:384	case XenbusStateConnected:385		if (dev->state == XenbusStateConnected)386			break;387 388		if (!xenbus_read_unsigned(dev->otherend, "feature-protocol-v2",389					  0)) {390			xenbus_dev_fatal(dev, -EINVAL,391					"vTPM protocol 2 required");392			return;393		}394		xenbus_switch_state(dev, XenbusStateConnected);395		break;396 397	case XenbusStateClosing:398	case XenbusStateClosed:399		device_unregister(&dev->dev);400		xenbus_frontend_closed(dev);401		break;402	default:403		break;404	}405}406 407static const struct xenbus_device_id tpmfront_ids[] = {408	{ "vtpm" },409	{ "" }410};411MODULE_ALIAS("xen:vtpm");412 413static struct xenbus_driver tpmfront_driver = {414	.ids = tpmfront_ids,415	.probe = tpmfront_probe,416	.remove = tpmfront_remove,417	.resume = tpmfront_resume,418	.otherend_changed = backend_changed,419};420 421static int __init xen_tpmfront_init(void)422{423	if (!xen_domain())424		return -ENODEV;425 426	if (!xen_has_pv_devices())427		return -ENODEV;428 429	return xenbus_register_frontend(&tpmfront_driver);430}431module_init(xen_tpmfront_init);432 433static void __exit xen_tpmfront_exit(void)434{435	xenbus_unregister_driver(&tpmfront_driver);436}437module_exit(xen_tpmfront_exit);438 439MODULE_AUTHOR("Daniel De Graaf <dgdegra@tycho.nsa.gov>");440MODULE_DESCRIPTION("Xen vTPM Driver");441MODULE_LICENSE("GPL");442