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