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