From patchwork Fri May 20 15:42:41 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stefan Berger X-Patchwork-Id: 96625 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id A551CB71A2 for ; Sat, 21 May 2011 01:44:04 +1000 (EST) Received: from localhost ([::1]:38208 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QNRrt-0003Li-Sc for incoming@patchwork.ozlabs.org; Fri, 20 May 2011 11:44:01 -0400 Received: from eggs.gnu.org ([140.186.70.92]:59451) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QNRrR-0003Gh-5s for qemu-devel@nongnu.org; Fri, 20 May 2011 11:43:35 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1QNRrL-0008WD-2e for qemu-devel@nongnu.org; Fri, 20 May 2011 11:43:30 -0400 Received: from e33.co.us.ibm.com ([32.97.110.151]:54194) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1QNRrK-0008Vv-ND for qemu-devel@nongnu.org; Fri, 20 May 2011 11:43:27 -0400 Received: from d03relay01.boulder.ibm.com (d03relay01.boulder.ibm.com [9.17.195.226]) by e33.co.us.ibm.com (8.14.4/8.13.1) with ESMTP id p4KFaExx020475 for ; Fri, 20 May 2011 09:36:14 -0600 Received: from d03av02.boulder.ibm.com (d03av02.boulder.ibm.com [9.17.195.168]) by d03relay01.boulder.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p4KFh83P130158 for ; Fri, 20 May 2011 09:43:09 -0600 Received: from d03av02.boulder.ibm.com (loopback [127.0.0.1]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p4K9gZv0012137 for ; Fri, 20 May 2011 03:42:37 -0600 Received: from localhost.localdomain (d941e-10.watson.ibm.com [9.59.241.154]) by d03av02.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p4K9gXWH012017 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Fri, 20 May 2011 03:42:34 -0600 Received: from localhost.localdomain (d941e-10 [127.0.0.1]) by localhost.localdomain (8.14.4/8.14.3) with ESMTP id p4KFh01t020405; Fri, 20 May 2011 11:43:00 -0400 Received: (from root@localhost) by localhost.localdomain (8.14.4/8.14.4/Submit) id p4KFgxpL020404; Fri, 20 May 2011 11:42:59 -0400 Message-Id: <20110520154259.829562800@linux.vnet.ibm.com> User-Agent: quilt/0.48-1 Date: Fri, 20 May 2011 11:42:41 -0400 From: Stefan Berger To: stefanb@linux.vnet.ibm.com, qemu-devel@nongnu.org References: <20110520154240.279198011@linux.vnet.ibm.com> Content-Disposition: inline; filename=qemu_tpm.diff X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-Received-From: 32.97.110.151 Cc: anbang.ruan@cs.ox.ac.uk, andreas.niederl@iaik.tugraz.at, serge@hallyn.com Subject: [Qemu-devel] [PATCH V5 01/12] Support for TPM command line options X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This patch adds support for TPM command line options. The command line supported here (considering the libtpms based backend) are ./qemu-... -tpm builtin,path= and ./qemu-... -tpmdev builtin,path=,id= -device tpm-tis,tpmdev= and ./qemu-... -tpmdev ? where the latter works similar to -soundhw ? and shows a list of available TPM backends ('builtin'). To show the available TPM models do: ./qemu-... -tpm model=? In case of -tpm, 'type' (above 'builtin') and 'model' are interpreted in tpm.c. In case of -tpmdev 'type' and 'id' are interpreted in tpm.c Using the type parameter, the backend is chosen, i.e., 'builtin' for the libtpms-based builtin TPM. The interpretation of the other parameters along with determining whether enough parameters were provided is pushed into the backend driver, which needs to implement the interface function 'create' and return a TPMDriver structure if the VM can be started or 'NULL' if not enough or bad parameters were provided. Since SeaBIOS will now use 128kb for ACPI tables the amount of reserved memory for ACPI tables needs to be increased -- increasing it to 128kb. Monitor support for 'info tpm' has been added. It for example prints the following: TPM devices: builtin: model=tpm-tis,id=tpm0 v5: - fixing typo reported by Serge Hallyn - Adapting code to split command line parameters supporting -tpmdev ... -device tpm-tis,tpmdev=... - moved code out of arch_init.c|h into tpm.c|h - increasing reserved memory for ACPI tables to 128kb (from 64kb) - the backend interface has a create() function for interpreting the command line parameters and returning a TPMDevice structure; previoulsy this function was called handle_options() - the backend interface has a destroy() function for cleaning up after the create() function was called - added support for 'info tpm' in monitor v4: - coding style fixes v3: - added hw/tpm_tis.h to this patch so Qemu compiles at this stage Signed-off-by: Stefan Berger --- Makefile.target | 1 hmp-commands.hx | 2 hw/pc.c | 5 - hw/tpm_tis.h | 76 +++++++++++++++ monitor.c | 10 ++ qemu-config.c | 46 +++++++++ qemu-options.hx | 80 ++++++++++++++++ tpm.c | 277 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tpm.h | 104 +++++++++++++++++++++ vl.c | 14 ++ 10 files changed, 614 insertions(+), 1 deletion(-) Index: qemu-git/qemu-options.hx =================================================================== --- qemu-git.orig/qemu-options.hx +++ qemu-git/qemu-options.hx @@ -1691,6 +1691,86 @@ ETEXI DEFHEADING() +DEFHEADING(TPM device options:) + +#ifndef _WIN32 +# ifdef CONFIG_TPM +DEF("tpm", HAS_ARG, QEMU_OPTION_tpm, \ + "" \ + "-tpm builtin,path=[,model=]\n" \ + " enable a builtin TPM with state in file in path\n" \ + "-tpm model=? to list available TPM device models\n" \ + "-tpm ? to list available TPM backend types\n", + QEMU_ARCH_I386) +DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \ + "-tpmdev [builtin],id=str[,option][,option][,...]\n", + QEMU_ARCH_I386) +# endif +#endif +STEXI + +The general form of a TPM device option is: +@table @option + +@item -tpmdev @var{backend} ,id=@var{id} [,@var{options}] +@findex -tpmdev +Backend type must be: +@option{builtin}. + +The specific backend type will determine the applicable options. +The @code{-tpmdev} options requires a @code{-device} option. + +Options to each backend are described below. + +Use ? to print all available TPM backend types. +@example +qemu -tpmdev ? +@end example + +@item -tpmdev builtin ,id=@var{id}, path=@var{path} + +Creates an instance of the built-in TPM. + +@option{path} specifies the path to the QCoW2 image that will store +the TPM's persistent data. @option{path} is required. + +To create a built-in TPM use the following two options: +@example +-tpmdev builtin,id=tpm0,path= -device tpm-tis,tpmdev=tpm0 +@end example +Not that the @code{-tpmdev} id is @code{tpm0} and is referenced by +@code{tpmdev=tpm0} in the device option. + +@end table + +The short form of a TPM device option is: +@table @option + +@item -tpm @var{backend-type}, path=@var{path} [,model=@var{model}] +@findex -tpm + +@option{model} specifies the device model. The default device model is a +@code{tpm-tis} device model. @code{model} is optional. + +Use ? to print all available TPM models. +@example +qemu -tpm model=? +@end example + +The other options have the same meaning as explained above. + +To create a built-in TPM use the following option: +@example +-tpm builtin, path= +@end example + +@end table + +ETEXI + + +DEFHEADING() + DEFHEADING(Linux/Multiboot boot specific:) STEXI Index: qemu-git/vl.c =================================================================== --- qemu-git.orig/vl.c +++ qemu-git/vl.c @@ -137,6 +137,7 @@ int main(int argc, char **argv) #include "block.h" #include "blockdev.h" #include "block-migration.h" +#include "tpm.h" #include "dma.h" #include "audio/audio.h" #include "migration.h" @@ -2425,6 +2426,14 @@ int main(int argc, char **argv, char **e ram_size = value; break; } +#ifdef CONFIG_TPM + case QEMU_OPTION_tpm: + tpm_config_parse(qemu_find_opts("tpm"), optarg); + break; + case QEMU_OPTION_tpmdev: + tpm_config_parse(qemu_find_opts("tpmdev"), optarg); + break; +#endif case QEMU_OPTION_mempath: mem_path = optarg; break; @@ -3051,6 +3060,10 @@ int main(int argc, char **argv, char **e exit(1); } + if (tpm_init() < 0) { + exit(1); + } + /* init the bluetooth world */ if (foreach_device_config(DEV_BT, bt_parse)) exit(1); @@ -3292,6 +3305,7 @@ int main(int argc, char **argv, char **e main_loop(); quit_timers(); net_cleanup(); + tpm_cleanup(); return 0; } Index: qemu-git/qemu-config.c =================================================================== --- qemu-git.orig/qemu-config.c +++ qemu-git/qemu-config.c @@ -463,6 +463,50 @@ static QemuOptsList qemu_machine_opts = }, }; +static QemuOptsList qemu_tpmdev_opts = { + .name = "tpmdev", + .implied_opt_name = "type", + .head = QTAILQ_HEAD_INITIALIZER(qemu_tpmdev_opts.head), + .desc = { + { + .name = "type", + .type = QEMU_OPT_STRING, + .help = "Type of TPM backend", + }, + { + .name = "path", + .type = QEMU_OPT_STRING, + .help = "Persistent storage for TPM state", + }, + { /* end of list */ } + }, +}; + +static QemuOptsList qemu_tpm_opts = { + .name = "tpm", + .implied_opt_name = "type", + .head = QTAILQ_HEAD_INITIALIZER(qemu_tpm_opts.head), + .desc = { + { + .name = "type", + .type = QEMU_OPT_STRING, + .help = "Type of TPM backend", + }, + { + .name = "model", + .type = QEMU_OPT_STRING, + .help = "Model of TPM frontend", + }, + { + .name = "path", + .type = QEMU_OPT_STRING, + .help = "Persistent storage for TPM state", + }, + { /* end of list */ } + }, +}; + + static QemuOptsList *vm_config_groups[32] = { &qemu_drive_opts, &qemu_chardev_opts, @@ -478,6 +522,8 @@ static QemuOptsList *vm_config_groups[32 #endif &qemu_option_rom_opts, &qemu_machine_opts, + &qemu_tpmdev_opts, + &qemu_tpm_opts, NULL, }; Index: qemu-git/hw/tpm_tis.h =================================================================== --- /dev/null +++ qemu-git/hw/tpm_tis.h @@ -0,0 +1,76 @@ +/* + * tpm_tis.h - include file for tpm_tis.c + * + * Copyright (C) 2006,2010,2011 IBM Corporation + * + * Author: Stefan Berger + * David Safford + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2 of the + * License. + */ +#ifndef _HW_TPM_TIS_H +#define _HW_TPM_TIS_H + +#include "isa.h" +#include "block_int.h" +#include "qemu-thread.h" + +#include + +#define TIS_ADDR_BASE 0xFED40000 + +#define NUM_LOCALITIES 5 /* per spec */ +#define NO_LOCALITY 0xff + +#define IS_VALID_LOCTY(x) ((x) < NUM_LOCALITIES) + + +#define TPM_TIS_IRQ 11 + +#define TIS_TPM_BUFFER_MAX 4096 + + +typedef struct TPMSizedBuffer +{ + uint32_t size; + uint8_t *buffer; +} TPMSizedBuffer; + + +enum tis_state { + STATE_IDLE = 0, + STATE_READY, + STATE_COMPLETION, + STATE_EXECUTION, + STATE_RECEPTION, +}; + + +void tis_reset_for_snapshot_resume(TPMState *s); + + +/* utility functions */ + +static inline uint16_t tis_get_size_from_buffer(const TPMSizedBuffer *sb) +{ + return (sb->buffer[4] << 8) + sb->buffer[5]; +} + +static inline void dumpBuffer(FILE *stream, + unsigned char *buffer, unsigned int len) +{ + int i; + + for (i = 0; i < len; i++) { + if (i && !(i % 16)) { + fprintf(stream, "\n"); + } + fprintf(stream, "%.2X ", buffer[i]); + } + fprintf(stream, "\n"); +} + +#endif /* _HW_TPM_TIS_H */ Index: qemu-git/Makefile.target =================================================================== --- qemu-git.orig/Makefile.target +++ qemu-git/Makefile.target @@ -199,6 +199,7 @@ obj-y += rwhandler.o obj-$(CONFIG_KVM) += kvm.o kvm-all.o obj-$(CONFIG_NO_KVM) += kvm-stub.o LIBS+=-lz +obj-y += tpm.o QEMU_CFLAGS += $(VNC_TLS_CFLAGS) QEMU_CFLAGS += $(VNC_SASL_CFLAGS) Index: qemu-git/tpm.c =================================================================== --- /dev/null +++ qemu-git/tpm.c @@ -0,0 +1,277 @@ +/* + * TPM configuraion + * + * Copyright (C) 2011 IBM Corporation + * Copyright (C) 2011 Stefan Berger + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Based on net.c + */ +#include "config.h" + +#include "tpm.h" +#include "monitor.h" +#include "qerror.h" + + +#ifdef CONFIG_TPM + +#if defined (TARGET_I386) || defined (TARGET_X86_64) + +static const TPMDriverOps *bes[] = { + NULL, +}; + + +static const char *tpm_models[] = { + TPM_DEFAULT_DEVICE_MODEL, + NULL, +}; + + +static QLIST_HEAD(, TPMBackend) tpm_backends = + QLIST_HEAD_INITIALIZER(tpm_backends); + + +const TPMDriverOps *tpm_get_backend_driver(const char *id) +{ + int i; + + for (i = 0; bes[i] != NULL; i++) { + if (!strcmp(bes[i]->id, id)) { + break; + } + } + + return bes[i]; +} + + +static void tpm_display_models(FILE *out) +{ + int i; + + fprintf(stderr, "qemu: Supported TPM models: "); + for (i = 0 ; tpm_models[i]; i++) { + fprintf(stderr, "%s%c", tpm_models[i], tpm_models[i+1] ? ',' : '\n'); + } +} + + +static int tpm_check_model(const char *model) +{ + int i; + + for (i = 0 ; tpm_models[i]; i++) { + if (strcmp(tpm_models[i], model) == 0) + return 1; + } + + return 0; +} + + +void tpm_display_backend_drivers(FILE *out) +{ + int i; + + fprintf(out, "Supported TPM types (choose only one):\n"); + + for (i = 0; bes[i] != NULL; i++) { + fprintf(out, "%7s %s", + bes[i]->id, bes[i]->desc()); + fprintf(out, "\n"); + } + fprintf(out, "\n"); +} + + +TPMBackend *qemu_find_tpm(const char *id) +{ + TPMBackend *drv; + + QLIST_FOREACH(drv, &tpm_backends, list) { + if (!strcmp(drv->id, id)) { + return drv; + } + } + + return NULL; +} + + +void do_info_tpm(Monitor *mon) +{ + TPMBackend *drv; + const char *model; + + monitor_printf(mon, "TPM devices:\n"); + + QLIST_FOREACH(drv, &tpm_backends, list) { + model = drv->model ? drv->model : TPM_DEFAULT_DEVICE_MODEL; + monitor_printf(mon, " %s: model=%s,id=%s\n", + drv->ops->id, model, drv->id); + } +} + +/* + * Create those TPMs that were created with -tpm rather than -tpmdev. + * The ones created with -tpm have a 'model' name. + */ +void qemu_create_tpm(void) +{ + TPMBackend *drv; + + QLIST_FOREACH(drv, &tpm_backends, list) { + if (drv->model) { + if (strcmp(drv->model, TPM_DEFAULT_DEVICE_MODEL) == 0) { + isa_create_simple(drv->model); + } + } + } +} + + +static int configure_tpm(QemuOpts *opts, int is_tpmdev) +{ + const char *value; + const char *id = TPM_DEFAULT_DEVICE_ID; + const char *model = NULL; + const TPMDriverOps *be; + TPMBackend *drv; + + if (!QLIST_EMPTY(&tpm_backends)) { + fprintf(stderr, "Only one TPM is allowed.\n"); + return 1; + } + + if (is_tpmdev) { + if (!(id = qemu_opts_id(opts))) { + qerror_report(QERR_MISSING_PARAMETER, "id"); + return 1; + } + } else { + model = qemu_opt_get(opts, "model"); + if (model) { + if (strcmp(model, "?") == 0) { + tpm_display_models(stdout); + return 1; + } + if (!tpm_check_model(model)) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "model", + "a tpm model"); + tpm_display_models(stderr); + return 1; + } + } else { + model = TPM_DEFAULT_DEVICE_MODEL; + } + } + + value = qemu_opt_get(opts, "type"); + if (!value) { + qerror_report(QERR_MISSING_PARAMETER, "type"); + tpm_display_backend_drivers(stderr); + return 1; + } + + be = tpm_get_backend_driver(value); + if (be == NULL) { + qerror_report(QERR_INVALID_PARAMETER_VALUE, "type", + "a tpm backend type"); + tpm_display_backend_drivers(stderr); + return 1; + } + + assert((is_tpmdev && model == NULL) || (!is_tpmdev && model != NULL)); + + drv = be->create(opts, id, model); + if (!drv) { + return 1; + } + + QLIST_INSERT_HEAD(&tpm_backends, drv, list); + + return 0; +} + + +static int tpm_init_tpmdev(QemuOpts *opts, void *dummy) +{ + return configure_tpm(opts, 1); +} + + +static int tpm_init_tpm(QemuOpts *opts, void *dummy) +{ + return configure_tpm(opts, 0); +} + + +int tpm_init(void) +{ + if (qemu_opts_foreach(qemu_find_opts("tpmdev"), + tpm_init_tpmdev, NULL, 1) != 0) { + return -1; + } + + if (qemu_opts_foreach(qemu_find_opts("tpm"), + tpm_init_tpm, NULL, 1) != 0) { + return -1; + } + + return 0; +} + + +void tpm_cleanup(void) +{ + TPMBackend *drv; + + QLIST_FOREACH(drv, &tpm_backends, list) { + QLIST_REMOVE(drv, list); + drv->ops->destroy(drv); + } +} + + +void tpm_config_parse(QemuOptsList *opts_list, const char *optarg) +{ + QemuOpts *opts; + + if (strcmp("none", optarg) != 0) { + if (*optarg == '?') { + tpm_display_backend_drivers(stdout); + exit(0); + } + opts = qemu_opts_parse(opts_list, optarg, 1); + if (!opts) { + exit(1); + } + } +} + +# else /* TARGET_I386 || TARGET_X86_64 */ + +void tpm_config_parse(QemuOptsList *opts_list, const char *optarg) +{ +} + +int tpm_init(void) +{ + return 0; +} + +void tpm_cleanup(void) +{ +} + +void do_info_tpm(Monitor *mon) +{ + monitor_printf(mon, "TPM support: not compiled\n"); +} + +# endif +#endif /* CONFIG_TPM */ Index: qemu-git/tpm.h =================================================================== --- /dev/null +++ qemu-git/tpm.h @@ -0,0 +1,104 @@ +#ifndef _HW_TPM_CONFIG_H +#define _HW_TPM_CONFIG_H + +struct TPMState; +typedef struct TPMState TPMState; + +#include "hw/tpm_tis.h" + +struct TPMDriverOps; +typedef struct TPMDriverOps TPMDriverOps; + +typedef struct TPMBackend { + char *id; + char *model; + TPMDriverOps *ops; + + QLIST_ENTRY(TPMBackend) list; +} TPMBackend; + + +/* locality data -- all fields are persisted */ +typedef struct TPMLocality { + enum tis_state state; + uint8_t access; + uint8_t sts; + uint32_t inte; + uint32_t ints; + + uint16_t w_offset; + uint16_t r_offset; + TPMSizedBuffer w_buffer; + TPMSizedBuffer r_buffer; +} TPMLocality; + + +/* overall state of the TPM interface */ +struct TPMState { + ISADevice busdev; + + uint32_t offset; + uint8_t buf[TIS_TPM_BUFFER_MAX]; + + uint8_t active_locty; + uint8_t aborting_locty; + uint8_t next_locty; + + uint8_t command_locty; + TPMLocality loc[NUM_LOCALITIES]; + + qemu_irq irq; + uint32_t irq_num; + + QemuMutex state_lock; + QemuCond from_tpm_cond; + QemuCond to_tpm_cond; + bool to_tpm_execute; + + bool tpm_initialized; + + char *backend; + TPMBackend *be_driver; +}; + + +typedef void (TPMRecvDataCB)(TPMState *s, uint8_t locty); + +struct TPMDriverOps { + const char *id; + const char *(*desc)(void); + + void (*job_for_main_thread)(void *); + + TPMBackend *(*create)(QemuOpts *, const char *id, const char *model); + void (*destroy)(TPMBackend *drv); + + int (*init)(TPMState *s, TPMRecvDataCB *datacb); + int (*early_startup_tpm)(void); + int (*late_startup_tpm)(void); + bool (*had_startup_error)(void); + + size_t (*realloc_buffer)(TPMSizedBuffer *sb); + + void (*reset)(void); + + int (*save_volatile_data)(void); + int (*load_volatile_data)(TPMState *s); + + bool (*get_tpm_established_flag)(void); +}; + +#define TPM_DEFAULT_DEVICE_ID "tpm0" +#define TPM_DEFAULT_DEVICE_MODEL "tpm-tis" + +void tpm_config_parse(QemuOptsList *opts_list, const char *optarg); +int tpm_init(void); +void tpm_cleanup(void); +void qemu_create_tpm(void); +TPMBackend *qemu_find_tpm(const char *id); +void do_info_tpm(Monitor *mon); +void tpm_display_backend_drivers(FILE *out); +const TPMDriverOps *tpm_get_backend_driver(const char *id); + + +#endif /* _HW_TPM_CONFIG_H */ Index: qemu-git/hw/pc.c =================================================================== --- qemu-git.orig/hw/pc.c +++ qemu-git/hw/pc.c @@ -41,6 +41,7 @@ #include "sysemu.h" #include "blockdev.h" #include "ui/qemu-spice.h" +#include "tpm.h" /* output Bochs bios info messages */ //#define DEBUG_BIOS @@ -60,7 +61,7 @@ #define PC_MAX_BIOS_SIZE (4 * 1024 * 1024) /* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */ -#define ACPI_DATA_SIZE 0x10000 +#define ACPI_DATA_SIZE 0x20000 #define BIOS_CFG_IOPORT 0x510 #define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0) #define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1) @@ -1148,6 +1149,8 @@ void pc_basic_device_init(qemu_irq *isa_ fd[i] = drive_get(IF_FLOPPY, 0, i); } fdctrl_init_isa(fd); + + qemu_create_tpm(); } void pc_pci_device_init(PCIBus *pci_bus) Index: qemu-git/monitor.c =================================================================== --- qemu-git.orig/monitor.c +++ qemu-git/monitor.c @@ -47,6 +47,7 @@ #include "migration.h" #include "kvm.h" #include "acl.h" +#include "tpm.h" #include "qint.h" #include "qfloat.h" #include "qlist.h" @@ -3100,6 +3101,15 @@ static const mon_cmd_t info_cmds[] = { .mhandler.info = do_info_trace_events, }, #endif +#if defined(CONFIG_TPM) + { + .name = "tpm", + .args_type = "", + .params = "", + .help = "show the TPM devices", + .mhandler.info = do_info_tpm, + }, +#endif { .name = NULL, }, Index: qemu-git/hmp-commands.hx =================================================================== --- qemu-git.orig/hmp-commands.hx +++ qemu-git/hmp-commands.hx @@ -1352,6 +1352,8 @@ show device tree show qdev device model list @item info roms show roms +@item info tpm +show the TPM devices @end table ETEXI