Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers/tpm: add xen tpmfront interface

This is a complete rewrite of the Xen TPM frontend driver, taking
advantage of a simplified frontend/backend interface and adding support
for cancellation and timeouts. The backend for this driver is provided
by a vTPM stub domain using the interface in Xen 4.3.

Signed-off-by: Daniel De Graaf <dgdegra@tycho.nsa.gov>
Acked-by: Matthew Fioravante <matthew.fioravante@jhuapl.edu>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Acked-by: Peter Huewe <peterhuewe@gmx.de>
Reviewed-by: Peter Huewe <peterhuewe@gmx.de>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>

authored by

Daniel De Graaf and committed by
Konrad Rzeszutek Wilk
e2683957 6efa20e4

+650
+113
Documentation/tpm/xen-tpmfront.txt
··· 1 + Virtual TPM interface for Xen 2 + 3 + Authors: Matthew Fioravante (JHUAPL), Daniel De Graaf (NSA) 4 + 5 + This document describes the virtual Trusted Platform Module (vTPM) subsystem for 6 + Xen. The reader is assumed to have familiarity with building and installing Xen, 7 + Linux, and a basic understanding of the TPM and vTPM concepts. 8 + 9 + INTRODUCTION 10 + 11 + The goal of this work is to provide a TPM functionality to a virtual guest 12 + operating system (in Xen terms, a DomU). This allows programs to interact with 13 + a TPM in a virtual system the same way they interact with a TPM on the physical 14 + system. Each guest gets its own unique, emulated, software TPM. However, each 15 + of the vTPM's secrets (Keys, NVRAM, etc) are managed by a vTPM Manager domain, 16 + which seals the secrets to the Physical TPM. If the process of creating each of 17 + these domains (manager, vTPM, and guest) is trusted, the vTPM subsystem extends 18 + the chain of trust rooted in the hardware TPM to virtual machines in Xen. Each 19 + major component of vTPM is implemented as a separate domain, providing secure 20 + separation guaranteed by the hypervisor. The vTPM domains are implemented in 21 + mini-os to reduce memory and processor overhead. 22 + 23 + This mini-os vTPM subsystem was built on top of the previous vTPM work done by 24 + IBM and Intel corporation. 25 + 26 + 27 + DESIGN OVERVIEW 28 + --------------- 29 + 30 + The architecture of vTPM is described below: 31 + 32 + +------------------+ 33 + | Linux DomU | ... 34 + | | ^ | 35 + | v | | 36 + | xen-tpmfront | 37 + +------------------+ 38 + | ^ 39 + v | 40 + +------------------+ 41 + | mini-os/tpmback | 42 + | | ^ | 43 + | v | | 44 + | vtpm-stubdom | ... 45 + | | ^ | 46 + | v | | 47 + | mini-os/tpmfront | 48 + +------------------+ 49 + | ^ 50 + v | 51 + +------------------+ 52 + | mini-os/tpmback | 53 + | | ^ | 54 + | v | | 55 + | vtpmmgr-stubdom | 56 + | | ^ | 57 + | v | | 58 + | mini-os/tpm_tis | 59 + +------------------+ 60 + | ^ 61 + v | 62 + +------------------+ 63 + | Hardware TPM | 64 + +------------------+ 65 + 66 + * Linux DomU: The Linux based guest that wants to use a vTPM. There may be 67 + more than one of these. 68 + 69 + * xen-tpmfront.ko: Linux kernel virtual TPM frontend driver. This driver 70 + provides vTPM access to a Linux-based DomU. 71 + 72 + * mini-os/tpmback: Mini-os TPM backend driver. The Linux frontend driver 73 + connects to this backend driver to facilitate communications 74 + between the Linux DomU and its vTPM. This driver is also 75 + used by vtpmmgr-stubdom to communicate with vtpm-stubdom. 76 + 77 + * vtpm-stubdom: A mini-os stub domain that implements a vTPM. There is a 78 + one to one mapping between running vtpm-stubdom instances and 79 + logical vtpms on the system. The vTPM Platform Configuration 80 + Registers (PCRs) are normally all initialized to zero. 81 + 82 + * mini-os/tpmfront: Mini-os TPM frontend driver. The vTPM mini-os domain 83 + vtpm-stubdom uses this driver to communicate with 84 + vtpmmgr-stubdom. This driver is also used in mini-os 85 + domains such as pv-grub that talk to the vTPM domain. 86 + 87 + * vtpmmgr-stubdom: A mini-os domain that implements the vTPM manager. There is 88 + only one vTPM manager and it should be running during the 89 + entire lifetime of the machine. This domain regulates 90 + access to the physical TPM on the system and secures the 91 + persistent state of each vTPM. 92 + 93 + * mini-os/tpm_tis: Mini-os TPM version 1.2 TPM Interface Specification (TIS) 94 + driver. This driver used by vtpmmgr-stubdom to talk directly to 95 + the hardware TPM. Communication is facilitated by mapping 96 + hardware memory pages into vtpmmgr-stubdom. 97 + 98 + * Hardware TPM: The physical TPM that is soldered onto the motherboard. 99 + 100 + 101 + INTEGRATION WITH XEN 102 + -------------------- 103 + 104 + Support for the vTPM driver was added in Xen using the libxl toolstack in Xen 105 + 4.3. See the Xen documentation (docs/misc/vtpm.txt) for details on setting up 106 + the vTPM and vTPM Manager stub domains. Once the stub domains are running, a 107 + vTPM device is set up in the same manner as a disk or network device in the 108 + domain's configuration file. 109 + 110 + In order to use features such as IMA that require a TPM to be loaded prior to 111 + the initrd, the xen-tpmfront driver must be compiled in to the kernel. If not 112 + using such features, the driver can be compiled as a module and will be loaded 113 + as usual.
+11
drivers/char/tpm/Kconfig
··· 91 91 To compile this driver as a module, choose M here; the module will be 92 92 called tpm_stm_st33_i2c. 93 93 94 + config TCG_XEN 95 + tristate "XEN TPM Interface" 96 + depends on TCG_TPM && XEN 97 + ---help--- 98 + If you want to make TPM support available to a Xen user domain, 99 + say Yes and it will be accessible from within Linux. See 100 + the manpages for xl, xl.conf, and docs/misc/vtpm.txt in 101 + the Xen source repository for more details. 102 + To compile this driver as a module, choose M here; the module 103 + will be called xen-tpmfront. 104 + 94 105 endif # TCG_TPM
+1
drivers/char/tpm/Makefile
··· 18 18 obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o 19 19 obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o 20 20 obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o 21 + obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
+473
drivers/char/tpm/xen-tpmfront.c
··· 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/events.h> 14 + #include <xen/interface/io/tpmif.h> 15 + #include <xen/grant_table.h> 16 + #include <xen/xenbus.h> 17 + #include <xen/page.h> 18 + #include "tpm.h" 19 + 20 + struct 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 + }; 30 + 31 + enum status_bits { 32 + VTPM_STATUS_RUNNING = 0x1, 33 + VTPM_STATUS_IDLE = 0x2, 34 + VTPM_STATUS_RESULT = 0x4, 35 + VTPM_STATUS_CANCELED = 0x8, 36 + }; 37 + 38 + static u8 vtpm_status(struct tpm_chip *chip) 39 + { 40 + struct tpm_private *priv = TPM_VPRIV(chip); 41 + switch (priv->shr->state) { 42 + case VTPM_STATE_IDLE: 43 + return VTPM_STATUS_IDLE | VTPM_STATUS_CANCELED; 44 + case VTPM_STATE_FINISH: 45 + return VTPM_STATUS_IDLE | VTPM_STATUS_RESULT; 46 + case VTPM_STATE_SUBMIT: 47 + case VTPM_STATE_CANCEL: /* cancel requested, not yet canceled */ 48 + return VTPM_STATUS_RUNNING; 49 + default: 50 + return 0; 51 + } 52 + } 53 + 54 + static bool vtpm_req_canceled(struct tpm_chip *chip, u8 status) 55 + { 56 + return status & VTPM_STATUS_CANCELED; 57 + } 58 + 59 + static void vtpm_cancel(struct tpm_chip *chip) 60 + { 61 + struct tpm_private *priv = TPM_VPRIV(chip); 62 + priv->shr->state = VTPM_STATE_CANCEL; 63 + wmb(); 64 + notify_remote_via_evtchn(priv->evtchn); 65 + } 66 + 67 + static unsigned int shr_data_offset(struct vtpm_shared_page *shr) 68 + { 69 + return sizeof(*shr) + sizeof(u32) * shr->nr_extra_pages; 70 + } 71 + 72 + static int vtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) 73 + { 74 + struct tpm_private *priv = TPM_VPRIV(chip); 75 + struct vtpm_shared_page *shr = priv->shr; 76 + unsigned int offset = shr_data_offset(shr); 77 + 78 + u32 ordinal; 79 + unsigned long duration; 80 + 81 + if (offset > PAGE_SIZE) 82 + return -EINVAL; 83 + 84 + if (offset + count > PAGE_SIZE) 85 + return -EINVAL; 86 + 87 + /* Wait for completion of any existing command or cancellation */ 88 + if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, chip->vendor.timeout_c, 89 + &chip->vendor.read_queue, true) < 0) { 90 + vtpm_cancel(chip); 91 + return -ETIME; 92 + } 93 + 94 + memcpy(offset + (u8 *)shr, buf, count); 95 + shr->length = count; 96 + barrier(); 97 + shr->state = VTPM_STATE_SUBMIT; 98 + wmb(); 99 + notify_remote_via_evtchn(priv->evtchn); 100 + 101 + ordinal = be32_to_cpu(((struct tpm_input_header*)buf)->ordinal); 102 + duration = tpm_calc_ordinal_duration(chip, ordinal); 103 + 104 + if (wait_for_tpm_stat(chip, VTPM_STATUS_IDLE, duration, 105 + &chip->vendor.read_queue, true) < 0) { 106 + /* got a signal or timeout, try to cancel */ 107 + vtpm_cancel(chip); 108 + return -ETIME; 109 + } 110 + 111 + return count; 112 + } 113 + 114 + static int vtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) 115 + { 116 + struct tpm_private *priv = TPM_VPRIV(chip); 117 + struct vtpm_shared_page *shr = priv->shr; 118 + unsigned int offset = shr_data_offset(shr); 119 + size_t length = shr->length; 120 + 121 + if (shr->state == VTPM_STATE_IDLE) 122 + return -ECANCELED; 123 + 124 + /* In theory the wait at the end of _send makes this one unnecessary */ 125 + if (wait_for_tpm_stat(chip, VTPM_STATUS_RESULT, chip->vendor.timeout_c, 126 + &chip->vendor.read_queue, true) < 0) { 127 + vtpm_cancel(chip); 128 + return -ETIME; 129 + } 130 + 131 + if (offset > PAGE_SIZE) 132 + return -EIO; 133 + 134 + if (offset + length > PAGE_SIZE) 135 + length = PAGE_SIZE - offset; 136 + 137 + if (length > count) 138 + length = count; 139 + 140 + memcpy(buf, offset + (u8 *)shr, length); 141 + 142 + return length; 143 + } 144 + 145 + ssize_t tpm_show_locality(struct device *dev, struct device_attribute *attr, 146 + char *buf) 147 + { 148 + struct tpm_chip *chip = dev_get_drvdata(dev); 149 + struct tpm_private *priv = TPM_VPRIV(chip); 150 + u8 locality = priv->shr->locality; 151 + 152 + return sprintf(buf, "%d\n", locality); 153 + } 154 + 155 + ssize_t tpm_store_locality(struct device *dev, struct device_attribute *attr, 156 + const char *buf, size_t len) 157 + { 158 + struct tpm_chip *chip = dev_get_drvdata(dev); 159 + struct tpm_private *priv = TPM_VPRIV(chip); 160 + u8 val; 161 + 162 + int rv = kstrtou8(buf, 0, &val); 163 + if (rv) 164 + return rv; 165 + 166 + priv->shr->locality = val; 167 + 168 + return len; 169 + } 170 + 171 + static const struct file_operations vtpm_ops = { 172 + .owner = THIS_MODULE, 173 + .llseek = no_llseek, 174 + .open = tpm_open, 175 + .read = tpm_read, 176 + .write = tpm_write, 177 + .release = tpm_release, 178 + }; 179 + 180 + static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); 181 + static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); 182 + static DEVICE_ATTR(enabled, S_IRUGO, tpm_show_enabled, NULL); 183 + static DEVICE_ATTR(active, S_IRUGO, tpm_show_active, NULL); 184 + static DEVICE_ATTR(owned, S_IRUGO, tpm_show_owned, NULL); 185 + static DEVICE_ATTR(temp_deactivated, S_IRUGO, tpm_show_temp_deactivated, 186 + NULL); 187 + static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); 188 + static DEVICE_ATTR(cancel, S_IWUSR | S_IWGRP, NULL, tpm_store_cancel); 189 + static DEVICE_ATTR(durations, S_IRUGO, tpm_show_durations, NULL); 190 + static DEVICE_ATTR(timeouts, S_IRUGO, tpm_show_timeouts, NULL); 191 + static DEVICE_ATTR(locality, S_IRUGO | S_IWUSR, tpm_show_locality, 192 + tpm_store_locality); 193 + 194 + static struct attribute *vtpm_attrs[] = { 195 + &dev_attr_pubek.attr, 196 + &dev_attr_pcrs.attr, 197 + &dev_attr_enabled.attr, 198 + &dev_attr_active.attr, 199 + &dev_attr_owned.attr, 200 + &dev_attr_temp_deactivated.attr, 201 + &dev_attr_caps.attr, 202 + &dev_attr_cancel.attr, 203 + &dev_attr_durations.attr, 204 + &dev_attr_timeouts.attr, 205 + &dev_attr_locality.attr, 206 + NULL, 207 + }; 208 + 209 + static struct attribute_group vtpm_attr_grp = { 210 + .attrs = vtpm_attrs, 211 + }; 212 + 213 + #define TPM_LONG_TIMEOUT (10 * 60 * HZ) 214 + 215 + static const struct tpm_vendor_specific tpm_vtpm = { 216 + .status = vtpm_status, 217 + .recv = vtpm_recv, 218 + .send = vtpm_send, 219 + .cancel = vtpm_cancel, 220 + .req_complete_mask = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT, 221 + .req_complete_val = VTPM_STATUS_IDLE | VTPM_STATUS_RESULT, 222 + .req_canceled = vtpm_req_canceled, 223 + .attr_group = &vtpm_attr_grp, 224 + .miscdev = { 225 + .fops = &vtpm_ops, 226 + }, 227 + .duration = { 228 + TPM_LONG_TIMEOUT, 229 + TPM_LONG_TIMEOUT, 230 + TPM_LONG_TIMEOUT, 231 + }, 232 + }; 233 + 234 + static irqreturn_t tpmif_interrupt(int dummy, void *dev_id) 235 + { 236 + struct tpm_private *priv = dev_id; 237 + 238 + switch (priv->shr->state) { 239 + case VTPM_STATE_IDLE: 240 + case VTPM_STATE_FINISH: 241 + wake_up_interruptible(&priv->chip->vendor.read_queue); 242 + break; 243 + case VTPM_STATE_SUBMIT: 244 + case VTPM_STATE_CANCEL: 245 + default: 246 + break; 247 + } 248 + return IRQ_HANDLED; 249 + } 250 + 251 + static int setup_chip(struct device *dev, struct tpm_private *priv) 252 + { 253 + struct tpm_chip *chip; 254 + 255 + chip = tpm_register_hardware(dev, &tpm_vtpm); 256 + if (!chip) 257 + return -ENODEV; 258 + 259 + init_waitqueue_head(&chip->vendor.read_queue); 260 + 261 + priv->chip = chip; 262 + TPM_VPRIV(chip) = priv; 263 + 264 + return 0; 265 + } 266 + 267 + /* caller must clean up in case of errors */ 268 + static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv) 269 + { 270 + struct xenbus_transaction xbt; 271 + const char *message = NULL; 272 + int rv; 273 + 274 + priv->shr = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO); 275 + if (!priv->shr) { 276 + xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); 277 + return -ENOMEM; 278 + } 279 + 280 + rv = xenbus_grant_ring(dev, virt_to_mfn(priv->shr)); 281 + if (rv < 0) 282 + return rv; 283 + 284 + priv->ring_ref = rv; 285 + 286 + rv = xenbus_alloc_evtchn(dev, &priv->evtchn); 287 + if (rv) 288 + return rv; 289 + 290 + rv = bind_evtchn_to_irqhandler(priv->evtchn, tpmif_interrupt, 0, 291 + "tpmif", priv); 292 + if (rv <= 0) { 293 + xenbus_dev_fatal(dev, rv, "allocating TPM irq"); 294 + return rv; 295 + } 296 + priv->chip->vendor.irq = rv; 297 + 298 + again: 299 + rv = xenbus_transaction_start(&xbt); 300 + if (rv) { 301 + xenbus_dev_fatal(dev, rv, "starting transaction"); 302 + return rv; 303 + } 304 + 305 + rv = xenbus_printf(xbt, dev->nodename, 306 + "ring-ref", "%u", priv->ring_ref); 307 + if (rv) { 308 + message = "writing ring-ref"; 309 + goto abort_transaction; 310 + } 311 + 312 + rv = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", 313 + priv->evtchn); 314 + if (rv) { 315 + message = "writing event-channel"; 316 + goto abort_transaction; 317 + } 318 + 319 + rv = xenbus_printf(xbt, dev->nodename, "feature-protocol-v2", "1"); 320 + if (rv) { 321 + message = "writing feature-protocol-v2"; 322 + goto abort_transaction; 323 + } 324 + 325 + rv = xenbus_transaction_end(xbt, 0); 326 + if (rv == -EAGAIN) 327 + goto again; 328 + if (rv) { 329 + xenbus_dev_fatal(dev, rv, "completing transaction"); 330 + return rv; 331 + } 332 + 333 + xenbus_switch_state(dev, XenbusStateInitialised); 334 + 335 + return 0; 336 + 337 + abort_transaction: 338 + xenbus_transaction_end(xbt, 1); 339 + if (message) 340 + xenbus_dev_error(dev, rv, "%s", message); 341 + 342 + return rv; 343 + } 344 + 345 + static void ring_free(struct tpm_private *priv) 346 + { 347 + if (!priv) 348 + return; 349 + 350 + if (priv->ring_ref) 351 + gnttab_end_foreign_access(priv->ring_ref, 0, 352 + (unsigned long)priv->shr); 353 + else 354 + free_page((unsigned long)priv->shr); 355 + 356 + if (priv->chip && priv->chip->vendor.irq) 357 + unbind_from_irqhandler(priv->chip->vendor.irq, priv); 358 + 359 + kfree(priv); 360 + } 361 + 362 + static int tpmfront_probe(struct xenbus_device *dev, 363 + const struct xenbus_device_id *id) 364 + { 365 + struct tpm_private *priv; 366 + int rv; 367 + 368 + priv = kzalloc(sizeof(*priv), GFP_KERNEL); 369 + if (!priv) { 370 + xenbus_dev_fatal(dev, -ENOMEM, "allocating priv structure"); 371 + return -ENOMEM; 372 + } 373 + 374 + rv = setup_chip(&dev->dev, priv); 375 + if (rv) { 376 + kfree(priv); 377 + return rv; 378 + } 379 + 380 + rv = setup_ring(dev, priv); 381 + if (rv) { 382 + tpm_remove_hardware(&dev->dev); 383 + ring_free(priv); 384 + return rv; 385 + } 386 + 387 + tpm_get_timeouts(priv->chip); 388 + 389 + dev_set_drvdata(&dev->dev, priv->chip); 390 + 391 + return rv; 392 + } 393 + 394 + static int tpmfront_remove(struct xenbus_device *dev) 395 + { 396 + struct tpm_chip *chip = dev_get_drvdata(&dev->dev); 397 + struct tpm_private *priv = TPM_VPRIV(chip); 398 + tpm_remove_hardware(&dev->dev); 399 + ring_free(priv); 400 + TPM_VPRIV(chip) = NULL; 401 + return 0; 402 + } 403 + 404 + static int tpmfront_resume(struct xenbus_device *dev) 405 + { 406 + /* A suspend/resume/migrate will interrupt a vTPM anyway */ 407 + tpmfront_remove(dev); 408 + return tpmfront_probe(dev, NULL); 409 + } 410 + 411 + static void backend_changed(struct xenbus_device *dev, 412 + enum xenbus_state backend_state) 413 + { 414 + int val; 415 + 416 + switch (backend_state) { 417 + case XenbusStateInitialised: 418 + case XenbusStateConnected: 419 + if (dev->state == XenbusStateConnected) 420 + break; 421 + 422 + if (xenbus_scanf(XBT_NIL, dev->otherend, 423 + "feature-protocol-v2", "%d", &val) < 0) 424 + val = 0; 425 + if (!val) { 426 + xenbus_dev_fatal(dev, -EINVAL, 427 + "vTPM protocol 2 required"); 428 + return; 429 + } 430 + xenbus_switch_state(dev, XenbusStateConnected); 431 + break; 432 + 433 + case XenbusStateClosing: 434 + case XenbusStateClosed: 435 + device_unregister(&dev->dev); 436 + xenbus_frontend_closed(dev); 437 + break; 438 + default: 439 + break; 440 + } 441 + } 442 + 443 + static const struct xenbus_device_id tpmfront_ids[] = { 444 + { "vtpm" }, 445 + { "" } 446 + }; 447 + MODULE_ALIAS("xen:vtpm"); 448 + 449 + static DEFINE_XENBUS_DRIVER(tpmfront, , 450 + .probe = tpmfront_probe, 451 + .remove = tpmfront_remove, 452 + .resume = tpmfront_resume, 453 + .otherend_changed = backend_changed, 454 + ); 455 + 456 + static int __init xen_tpmfront_init(void) 457 + { 458 + if (!xen_domain()) 459 + return -ENODEV; 460 + 461 + return xenbus_register_frontend(&tpmfront_driver); 462 + } 463 + module_init(xen_tpmfront_init); 464 + 465 + static void __exit xen_tpmfront_exit(void) 466 + { 467 + xenbus_unregister_driver(&tpmfront_driver); 468 + } 469 + module_exit(xen_tpmfront_exit); 470 + 471 + MODULE_AUTHOR("Daniel De Graaf <dgdegra@tycho.nsa.gov>"); 472 + MODULE_DESCRIPTION("Xen vTPM Driver"); 473 + MODULE_LICENSE("GPL");
+52
include/xen/interface/io/tpmif.h
··· 1 + /****************************************************************************** 2 + * tpmif.h 3 + * 4 + * TPM I/O interface for Xen guest OSes, v2 5 + * 6 + * This file is in the public domain. 7 + * 8 + */ 9 + 10 + #ifndef __XEN_PUBLIC_IO_TPMIF_H__ 11 + #define __XEN_PUBLIC_IO_TPMIF_H__ 12 + 13 + /* 14 + * Xenbus state machine 15 + * 16 + * Device open: 17 + * 1. Both ends start in XenbusStateInitialising 18 + * 2. Backend transitions to InitWait (frontend does not wait on this step) 19 + * 3. Frontend populates ring-ref, event-channel, feature-protocol-v2 20 + * 4. Frontend transitions to Initialised 21 + * 5. Backend maps grant and event channel, verifies feature-protocol-v2 22 + * 6. Backend transitions to Connected 23 + * 7. Frontend verifies feature-protocol-v2, transitions to Connected 24 + * 25 + * Device close: 26 + * 1. State is changed to XenbusStateClosing 27 + * 2. Frontend transitions to Closed 28 + * 3. Backend unmaps grant and event, changes state to InitWait 29 + */ 30 + 31 + enum vtpm_shared_page_state { 32 + VTPM_STATE_IDLE, /* no contents / vTPM idle / cancel complete */ 33 + VTPM_STATE_SUBMIT, /* request ready / vTPM working */ 34 + VTPM_STATE_FINISH, /* response ready / vTPM idle */ 35 + VTPM_STATE_CANCEL, /* cancel requested / vTPM working */ 36 + }; 37 + /* The backend should only change state to IDLE or FINISH, while the 38 + * frontend should only change to SUBMIT or CANCEL. */ 39 + 40 + 41 + struct vtpm_shared_page { 42 + uint32_t length; /* request/response length in bytes */ 43 + 44 + uint8_t state; /* enum vtpm_shared_page_state */ 45 + uint8_t locality; /* for the current request */ 46 + uint8_t pad; 47 + 48 + uint8_t nr_extra_pages; /* extra pages for long packets; may be zero */ 49 + uint32_t extra_pages[0]; /* grant IDs; length in nr_extra_pages */ 50 + }; 51 + 52 + #endif