xref: /openbmc/qemu/system/tpm.c (revision 1527c6b6fa6c6775523287e33f78b41afc7ba46c)
18d7f2e76SPhilippe Mathieu-Daudé /*
28d7f2e76SPhilippe Mathieu-Daudé  * TPM configuration
38d7f2e76SPhilippe Mathieu-Daudé  *
48d7f2e76SPhilippe Mathieu-Daudé  * Copyright (C) 2011-2013 IBM Corporation
58d7f2e76SPhilippe Mathieu-Daudé  *
68d7f2e76SPhilippe Mathieu-Daudé  * Authors:
78d7f2e76SPhilippe Mathieu-Daudé  *  Stefan Berger    <stefanb@us.ibm.com>
88d7f2e76SPhilippe Mathieu-Daudé  *
98d7f2e76SPhilippe Mathieu-Daudé  * This work is licensed under the terms of the GNU GPL, version 2 or later.
108d7f2e76SPhilippe Mathieu-Daudé  * See the COPYING file in the top-level directory.
118d7f2e76SPhilippe Mathieu-Daudé  *
128d7f2e76SPhilippe Mathieu-Daudé  * Based on net.c
138d7f2e76SPhilippe Mathieu-Daudé  */
148d7f2e76SPhilippe Mathieu-Daudé 
158d7f2e76SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
168d7f2e76SPhilippe Mathieu-Daudé 
178d7f2e76SPhilippe Mathieu-Daudé #include "qapi/error.h"
188d7f2e76SPhilippe Mathieu-Daudé #include "qapi/qapi-commands-tpm.h"
198d7f2e76SPhilippe Mathieu-Daudé #include "qapi/qmp/qerror.h"
208d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/tpm_backend.h"
218d7f2e76SPhilippe Mathieu-Daudé #include "sysemu/tpm.h"
228d7f2e76SPhilippe Mathieu-Daudé #include "qemu/config-file.h"
238d7f2e76SPhilippe Mathieu-Daudé #include "qemu/error-report.h"
248d7f2e76SPhilippe Mathieu-Daudé 
258d7f2e76SPhilippe Mathieu-Daudé static QLIST_HEAD(, TPMBackend) tpm_backends =
268d7f2e76SPhilippe Mathieu-Daudé     QLIST_HEAD_INITIALIZER(tpm_backends);
278d7f2e76SPhilippe Mathieu-Daudé 
288d7f2e76SPhilippe Mathieu-Daudé static const TPMBackendClass *
tpm_be_find_by_type(enum TpmType type)298d7f2e76SPhilippe Mathieu-Daudé tpm_be_find_by_type(enum TpmType type)
308d7f2e76SPhilippe Mathieu-Daudé {
318d7f2e76SPhilippe Mathieu-Daudé     ObjectClass *oc;
328d7f2e76SPhilippe Mathieu-Daudé     char *typename = g_strdup_printf("tpm-%s", TpmType_str(type));
338d7f2e76SPhilippe Mathieu-Daudé 
348d7f2e76SPhilippe Mathieu-Daudé     oc = object_class_by_name(typename);
358d7f2e76SPhilippe Mathieu-Daudé     g_free(typename);
368d7f2e76SPhilippe Mathieu-Daudé 
378d7f2e76SPhilippe Mathieu-Daudé     if (!object_class_dynamic_cast(oc, TYPE_TPM_BACKEND)) {
388d7f2e76SPhilippe Mathieu-Daudé         return NULL;
398d7f2e76SPhilippe Mathieu-Daudé     }
408d7f2e76SPhilippe Mathieu-Daudé 
418d7f2e76SPhilippe Mathieu-Daudé     return TPM_BACKEND_CLASS(oc);
428d7f2e76SPhilippe Mathieu-Daudé }
438d7f2e76SPhilippe Mathieu-Daudé 
448d7f2e76SPhilippe Mathieu-Daudé /*
458d7f2e76SPhilippe Mathieu-Daudé  * Walk the list of available TPM backend drivers and display them on the
468d7f2e76SPhilippe Mathieu-Daudé  * screen.
478d7f2e76SPhilippe Mathieu-Daudé  */
tpm_display_backend_drivers(void)488d7f2e76SPhilippe Mathieu-Daudé static void tpm_display_backend_drivers(void)
498d7f2e76SPhilippe Mathieu-Daudé {
508d7f2e76SPhilippe Mathieu-Daudé     bool got_one = false;
518d7f2e76SPhilippe Mathieu-Daudé     int i;
528d7f2e76SPhilippe Mathieu-Daudé 
538d7f2e76SPhilippe Mathieu-Daudé     for (i = 0; i < TPM_TYPE__MAX; i++) {
548d7f2e76SPhilippe Mathieu-Daudé         const TPMBackendClass *bc = tpm_be_find_by_type(i);
558d7f2e76SPhilippe Mathieu-Daudé         if (!bc) {
568d7f2e76SPhilippe Mathieu-Daudé             continue;
578d7f2e76SPhilippe Mathieu-Daudé         }
588d7f2e76SPhilippe Mathieu-Daudé         if (!got_one) {
598d7f2e76SPhilippe Mathieu-Daudé             error_printf("Supported TPM types (choose only one):\n");
608d7f2e76SPhilippe Mathieu-Daudé             got_one = true;
618d7f2e76SPhilippe Mathieu-Daudé         }
628d7f2e76SPhilippe Mathieu-Daudé         error_printf("%12s   %s\n", TpmType_str(i), bc->desc);
638d7f2e76SPhilippe Mathieu-Daudé     }
648d7f2e76SPhilippe Mathieu-Daudé     if (!got_one) {
658d7f2e76SPhilippe Mathieu-Daudé         error_printf("No TPM backend types are available\n");
668d7f2e76SPhilippe Mathieu-Daudé     }
678d7f2e76SPhilippe Mathieu-Daudé }
688d7f2e76SPhilippe Mathieu-Daudé 
698d7f2e76SPhilippe Mathieu-Daudé /*
708d7f2e76SPhilippe Mathieu-Daudé  * Find the TPM with the given Id
718d7f2e76SPhilippe Mathieu-Daudé  */
qemu_find_tpm_be(const char * id)728d7f2e76SPhilippe Mathieu-Daudé TPMBackend *qemu_find_tpm_be(const char *id)
738d7f2e76SPhilippe Mathieu-Daudé {
748d7f2e76SPhilippe Mathieu-Daudé     TPMBackend *drv;
758d7f2e76SPhilippe Mathieu-Daudé 
768d7f2e76SPhilippe Mathieu-Daudé     if (id) {
778d7f2e76SPhilippe Mathieu-Daudé         QLIST_FOREACH(drv, &tpm_backends, list) {
788d7f2e76SPhilippe Mathieu-Daudé             if (!strcmp(drv->id, id)) {
798d7f2e76SPhilippe Mathieu-Daudé                 return drv;
808d7f2e76SPhilippe Mathieu-Daudé             }
818d7f2e76SPhilippe Mathieu-Daudé         }
828d7f2e76SPhilippe Mathieu-Daudé     }
838d7f2e76SPhilippe Mathieu-Daudé 
848d7f2e76SPhilippe Mathieu-Daudé     return NULL;
858d7f2e76SPhilippe Mathieu-Daudé }
868d7f2e76SPhilippe Mathieu-Daudé 
tpm_init_tpmdev(void * dummy,QemuOpts * opts,Error ** errp)878d7f2e76SPhilippe Mathieu-Daudé static int tpm_init_tpmdev(void *dummy, QemuOpts *opts, Error **errp)
888d7f2e76SPhilippe Mathieu-Daudé {
898d7f2e76SPhilippe Mathieu-Daudé     /*
908d7f2e76SPhilippe Mathieu-Daudé      * Use of error_report() in a function with an Error ** parameter
918d7f2e76SPhilippe Mathieu-Daudé      * is suspicious.  It is okay here.  The parameter only exists to
928d7f2e76SPhilippe Mathieu-Daudé      * make the function usable with qemu_opts_foreach().  It is not
938d7f2e76SPhilippe Mathieu-Daudé      * actually used.
948d7f2e76SPhilippe Mathieu-Daudé      */
958d7f2e76SPhilippe Mathieu-Daudé     const char *value;
968d7f2e76SPhilippe Mathieu-Daudé     const char *id;
978d7f2e76SPhilippe Mathieu-Daudé     const TPMBackendClass *be;
988d7f2e76SPhilippe Mathieu-Daudé     TPMBackend *drv;
998d7f2e76SPhilippe Mathieu-Daudé     Error *local_err = NULL;
1008d7f2e76SPhilippe Mathieu-Daudé     int i;
1018d7f2e76SPhilippe Mathieu-Daudé 
1028d7f2e76SPhilippe Mathieu-Daudé     if (!QLIST_EMPTY(&tpm_backends)) {
1038d7f2e76SPhilippe Mathieu-Daudé         error_report("Only one TPM is allowed.");
1048d7f2e76SPhilippe Mathieu-Daudé         return 1;
1058d7f2e76SPhilippe Mathieu-Daudé     }
1068d7f2e76SPhilippe Mathieu-Daudé 
1078d7f2e76SPhilippe Mathieu-Daudé     id = qemu_opts_id(opts);
1088d7f2e76SPhilippe Mathieu-Daudé     if (id == NULL) {
1098d7f2e76SPhilippe Mathieu-Daudé         error_report(QERR_MISSING_PARAMETER, "id");
1108d7f2e76SPhilippe Mathieu-Daudé         return 1;
1118d7f2e76SPhilippe Mathieu-Daudé     }
1128d7f2e76SPhilippe Mathieu-Daudé 
1138d7f2e76SPhilippe Mathieu-Daudé     value = qemu_opt_get(opts, "type");
1148d7f2e76SPhilippe Mathieu-Daudé     if (!value) {
1158d7f2e76SPhilippe Mathieu-Daudé         error_report(QERR_MISSING_PARAMETER, "type");
1168d7f2e76SPhilippe Mathieu-Daudé         tpm_display_backend_drivers();
1178d7f2e76SPhilippe Mathieu-Daudé         return 1;
1188d7f2e76SPhilippe Mathieu-Daudé     }
1198d7f2e76SPhilippe Mathieu-Daudé 
1208d7f2e76SPhilippe Mathieu-Daudé     i = qapi_enum_parse(&TpmType_lookup, value, -1, NULL);
1218d7f2e76SPhilippe Mathieu-Daudé     be = i >= 0 ? tpm_be_find_by_type(i) : NULL;
1228d7f2e76SPhilippe Mathieu-Daudé     if (be == NULL) {
1238d7f2e76SPhilippe Mathieu-Daudé         error_report(QERR_INVALID_PARAMETER_VALUE,
1248d7f2e76SPhilippe Mathieu-Daudé                      "type", "a TPM backend type");
1258d7f2e76SPhilippe Mathieu-Daudé         tpm_display_backend_drivers();
1268d7f2e76SPhilippe Mathieu-Daudé         return 1;
1278d7f2e76SPhilippe Mathieu-Daudé     }
1288d7f2e76SPhilippe Mathieu-Daudé 
1298d7f2e76SPhilippe Mathieu-Daudé     /* validate backend specific opts */
1308d7f2e76SPhilippe Mathieu-Daudé     if (!qemu_opts_validate(opts, be->opts, &local_err)) {
1318d7f2e76SPhilippe Mathieu-Daudé         error_report_err(local_err);
1328d7f2e76SPhilippe Mathieu-Daudé         return 1;
1338d7f2e76SPhilippe Mathieu-Daudé     }
1348d7f2e76SPhilippe Mathieu-Daudé 
1358d7f2e76SPhilippe Mathieu-Daudé     drv = be->create(opts);
1368d7f2e76SPhilippe Mathieu-Daudé     if (!drv) {
1378d7f2e76SPhilippe Mathieu-Daudé         return 1;
1388d7f2e76SPhilippe Mathieu-Daudé     }
1398d7f2e76SPhilippe Mathieu-Daudé 
1408d7f2e76SPhilippe Mathieu-Daudé     drv->id = g_strdup(id);
1418d7f2e76SPhilippe Mathieu-Daudé     QLIST_INSERT_HEAD(&tpm_backends, drv, list);
1428d7f2e76SPhilippe Mathieu-Daudé 
1438d7f2e76SPhilippe Mathieu-Daudé     return 0;
1448d7f2e76SPhilippe Mathieu-Daudé }
1458d7f2e76SPhilippe Mathieu-Daudé 
1468d7f2e76SPhilippe Mathieu-Daudé /*
1478d7f2e76SPhilippe Mathieu-Daudé  * Walk the list of TPM backend drivers that are in use and call their
1488d7f2e76SPhilippe Mathieu-Daudé  * destroy function to have them cleaned up.
1498d7f2e76SPhilippe Mathieu-Daudé  */
tpm_cleanup(void)1508d7f2e76SPhilippe Mathieu-Daudé void tpm_cleanup(void)
1518d7f2e76SPhilippe Mathieu-Daudé {
1528d7f2e76SPhilippe Mathieu-Daudé     TPMBackend *drv, *next;
1538d7f2e76SPhilippe Mathieu-Daudé 
1548d7f2e76SPhilippe Mathieu-Daudé     QLIST_FOREACH_SAFE(drv, &tpm_backends, list, next) {
1558d7f2e76SPhilippe Mathieu-Daudé         QLIST_REMOVE(drv, list);
1568d7f2e76SPhilippe Mathieu-Daudé         object_unref(OBJECT(drv));
1578d7f2e76SPhilippe Mathieu-Daudé     }
1588d7f2e76SPhilippe Mathieu-Daudé }
1598d7f2e76SPhilippe Mathieu-Daudé 
1608d7f2e76SPhilippe Mathieu-Daudé /*
1618d7f2e76SPhilippe Mathieu-Daudé  * Initialize the TPM. Process the tpmdev command line options describing the
1628d7f2e76SPhilippe Mathieu-Daudé  * TPM backend.
1638d7f2e76SPhilippe Mathieu-Daudé  */
tpm_init(void)1648d7f2e76SPhilippe Mathieu-Daudé int tpm_init(void)
1658d7f2e76SPhilippe Mathieu-Daudé {
1668d7f2e76SPhilippe Mathieu-Daudé     if (qemu_opts_foreach(qemu_find_opts("tpmdev"),
1678d7f2e76SPhilippe Mathieu-Daudé                           tpm_init_tpmdev, NULL, NULL)) {
1688d7f2e76SPhilippe Mathieu-Daudé         return -1;
1698d7f2e76SPhilippe Mathieu-Daudé     }
1708d7f2e76SPhilippe Mathieu-Daudé 
1718d7f2e76SPhilippe Mathieu-Daudé     return 0;
1728d7f2e76SPhilippe Mathieu-Daudé }
1738d7f2e76SPhilippe Mathieu-Daudé 
1748d7f2e76SPhilippe Mathieu-Daudé /*
1758d7f2e76SPhilippe Mathieu-Daudé  * Parse the TPM configuration options.
1768d7f2e76SPhilippe Mathieu-Daudé  * To display all available TPM backends the user may use '-tpmdev help'
1778d7f2e76SPhilippe Mathieu-Daudé  */
tpm_config_parse(QemuOptsList * opts_list,const char * optstr)178*1527c6b6SStefan Hajnoczi int tpm_config_parse(QemuOptsList *opts_list, const char *optstr)
1798d7f2e76SPhilippe Mathieu-Daudé {
1808d7f2e76SPhilippe Mathieu-Daudé     QemuOpts *opts;
1818d7f2e76SPhilippe Mathieu-Daudé 
182*1527c6b6SStefan Hajnoczi     if (!strcmp(optstr, "help")) {
1838d7f2e76SPhilippe Mathieu-Daudé         tpm_display_backend_drivers();
1848d7f2e76SPhilippe Mathieu-Daudé         return -1;
1858d7f2e76SPhilippe Mathieu-Daudé     }
186*1527c6b6SStefan Hajnoczi     opts = qemu_opts_parse_noisily(opts_list, optstr, true);
1878d7f2e76SPhilippe Mathieu-Daudé     if (!opts) {
1888d7f2e76SPhilippe Mathieu-Daudé         return -1;
1898d7f2e76SPhilippe Mathieu-Daudé     }
1908d7f2e76SPhilippe Mathieu-Daudé     return 0;
1918d7f2e76SPhilippe Mathieu-Daudé }
1928d7f2e76SPhilippe Mathieu-Daudé 
1938d7f2e76SPhilippe Mathieu-Daudé /*
1948d7f2e76SPhilippe Mathieu-Daudé  * Walk the list of active TPM backends and collect information about them.
1958d7f2e76SPhilippe Mathieu-Daudé  */
qmp_query_tpm(Error ** errp)1968d7f2e76SPhilippe Mathieu-Daudé TPMInfoList *qmp_query_tpm(Error **errp)
1978d7f2e76SPhilippe Mathieu-Daudé {
1988d7f2e76SPhilippe Mathieu-Daudé     TPMBackend *drv;
1998d7f2e76SPhilippe Mathieu-Daudé     TPMInfoList *head = NULL, **tail = &head;
2008d7f2e76SPhilippe Mathieu-Daudé 
2018d7f2e76SPhilippe Mathieu-Daudé     QLIST_FOREACH(drv, &tpm_backends, list) {
2028d7f2e76SPhilippe Mathieu-Daudé         if (!drv->tpmif) {
2038d7f2e76SPhilippe Mathieu-Daudé             continue;
2048d7f2e76SPhilippe Mathieu-Daudé         }
2058d7f2e76SPhilippe Mathieu-Daudé 
2068d7f2e76SPhilippe Mathieu-Daudé         QAPI_LIST_APPEND(tail, tpm_backend_query_tpm(drv));
2078d7f2e76SPhilippe Mathieu-Daudé     }
2088d7f2e76SPhilippe Mathieu-Daudé 
2098d7f2e76SPhilippe Mathieu-Daudé     return head;
2108d7f2e76SPhilippe Mathieu-Daudé }
2118d7f2e76SPhilippe Mathieu-Daudé 
qmp_query_tpm_types(Error ** errp)2128d7f2e76SPhilippe Mathieu-Daudé TpmTypeList *qmp_query_tpm_types(Error **errp)
2138d7f2e76SPhilippe Mathieu-Daudé {
2148d7f2e76SPhilippe Mathieu-Daudé     unsigned int i = 0;
2158d7f2e76SPhilippe Mathieu-Daudé     TpmTypeList *head = NULL, **tail = &head;
2168d7f2e76SPhilippe Mathieu-Daudé 
2178d7f2e76SPhilippe Mathieu-Daudé     for (i = 0; i < TPM_TYPE__MAX; i++) {
2188d7f2e76SPhilippe Mathieu-Daudé         if (!tpm_be_find_by_type(i)) {
2198d7f2e76SPhilippe Mathieu-Daudé             continue;
2208d7f2e76SPhilippe Mathieu-Daudé         }
2218d7f2e76SPhilippe Mathieu-Daudé         QAPI_LIST_APPEND(tail, i);
2228d7f2e76SPhilippe Mathieu-Daudé     }
2238d7f2e76SPhilippe Mathieu-Daudé 
2248d7f2e76SPhilippe Mathieu-Daudé     return head;
2258d7f2e76SPhilippe Mathieu-Daudé }
qmp_query_tpm_models(Error ** errp)2268d7f2e76SPhilippe Mathieu-Daudé TpmModelList *qmp_query_tpm_models(Error **errp)
2278d7f2e76SPhilippe Mathieu-Daudé {
2288d7f2e76SPhilippe Mathieu-Daudé     TpmModelList *head = NULL, **tail = &head;
2298d7f2e76SPhilippe Mathieu-Daudé     GSList *e, *l = object_class_get_list(TYPE_TPM_IF, false);
2308d7f2e76SPhilippe Mathieu-Daudé 
2318d7f2e76SPhilippe Mathieu-Daudé     for (e = l; e; e = e->next) {
2328d7f2e76SPhilippe Mathieu-Daudé         TPMIfClass *c = TPM_IF_CLASS(e->data);
2338d7f2e76SPhilippe Mathieu-Daudé 
2348d7f2e76SPhilippe Mathieu-Daudé         QAPI_LIST_APPEND(tail, c->model);
2358d7f2e76SPhilippe Mathieu-Daudé     }
2368d7f2e76SPhilippe Mathieu-Daudé     g_slist_free(l);
2378d7f2e76SPhilippe Mathieu-Daudé 
2388d7f2e76SPhilippe Mathieu-Daudé     return head;
2398d7f2e76SPhilippe Mathieu-Daudé }
240