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