18f0605ccSStefan Berger /* 28f0605ccSStefan Berger * QEMU TPM Backend 38f0605ccSStefan Berger * 48f0605ccSStefan Berger * Copyright IBM, Corp. 2013 58f0605ccSStefan Berger * 68f0605ccSStefan Berger * Authors: 78f0605ccSStefan Berger * Stefan Berger <stefanb@us.ibm.com> 88f0605ccSStefan Berger * 98f0605ccSStefan Berger * This work is licensed under the terms of the GNU GPL, version 2 or later. 108f0605ccSStefan Berger * See the COPYING file in the top-level directory. 118f0605ccSStefan Berger * 128f0605ccSStefan Berger * Based on backends/rng.c by Anthony Liguori 138f0605ccSStefan Berger */ 148f0605ccSStefan Berger 159c058332SPeter Maydell #include "qemu/osdep.h" 16dccfcd0eSPaolo Bonzini #include "sysemu/tpm_backend.h" 17da34e65cSMarkus Armbruster #include "qapi/error.h" 188f0605ccSStefan Berger #include "qapi/qmp/qerror.h" 19bdee56f5SPaolo Bonzini #include "sysemu/tpm.h" 20bdee56f5SPaolo Bonzini #include "qemu/thread.h" 2168999059SMarc-André Lureau #include "qemu/main-loop.h" 22c4fb8561SMarc-André Lureau #include "block/thread-pool.h" 23c4fb8561SMarc-André Lureau #include "qemu/error-report.h" 2468999059SMarc-André Lureau 25c4fb8561SMarc-André Lureau static void tpm_backend_request_completed(void *opaque, int ret) 2668999059SMarc-André Lureau { 2768999059SMarc-André Lureau TPMBackend *s = TPM_BACKEND(opaque); 2868999059SMarc-André Lureau TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif); 2968999059SMarc-André Lureau 30*6a8a2354SMarc-André Lureau tic->request_completed(s->tpmif, ret); 31c4fb8561SMarc-André Lureau 32c4fb8561SMarc-André Lureau /* no need for atomic, as long the BQL is taken */ 33c4fb8561SMarc-André Lureau s->cmd = NULL; 34c4fb8561SMarc-André Lureau object_unref(OBJECT(s)); 3568999059SMarc-André Lureau } 36b19a5eeaSAmarnath Valluri 37c4fb8561SMarc-André Lureau static int tpm_backend_worker_thread(gpointer data) 38b19a5eeaSAmarnath Valluri { 39c4fb8561SMarc-André Lureau TPMBackend *s = TPM_BACKEND(data); 40b19a5eeaSAmarnath Valluri TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 41*6a8a2354SMarc-André Lureau Error *err = NULL; 42b19a5eeaSAmarnath Valluri 43*6a8a2354SMarc-André Lureau k->handle_request(s, s->cmd, &err); 44*6a8a2354SMarc-André Lureau if (err) { 45*6a8a2354SMarc-André Lureau error_report_err(err); 46*6a8a2354SMarc-André Lureau return -1; 47*6a8a2354SMarc-André Lureau } 4868999059SMarc-André Lureau 49c4fb8561SMarc-André Lureau return 0; 50b19a5eeaSAmarnath Valluri } 51b19a5eeaSAmarnath Valluri 52c4fb8561SMarc-André Lureau void tpm_backend_finish_sync(TPMBackend *s) 53b19a5eeaSAmarnath Valluri { 54c4fb8561SMarc-André Lureau while (s->cmd) { 55c4fb8561SMarc-André Lureau aio_poll(qemu_get_aio_context(), true); 56b19a5eeaSAmarnath Valluri } 57b19a5eeaSAmarnath Valluri } 588f0605ccSStefan Berger 598f0605ccSStefan Berger enum TpmType tpm_backend_get_type(TPMBackend *s) 608f0605ccSStefan Berger { 618f0605ccSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 628f0605ccSStefan Berger 63d31076baSMarc-André Lureau return k->type; 648f0605ccSStefan Berger } 658f0605ccSStefan Berger 660bd6c8a9SMarc-André Lureau int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp) 678f0605ccSStefan Berger { 688a89c9acSMarc-André Lureau if (s->tpmif) { 690bd6c8a9SMarc-André Lureau error_setg(errp, "TPM backend '%s' is already initialized", s->id); 708a89c9acSMarc-André Lureau return -1; 718a89c9acSMarc-André Lureau } 728a89c9acSMarc-André Lureau 738a89c9acSMarc-André Lureau s->tpmif = tpmif; 748a89c9acSMarc-André Lureau object_ref(OBJECT(tpmif)); 758a89c9acSMarc-André Lureau 7693330cf5SAmarnath Valluri s->had_startup_error = false; 77b19a5eeaSAmarnath Valluri 7827a79d96SMarc-André Lureau return 0; 798f0605ccSStefan Berger } 808f0605ccSStefan Berger 819375c44fSStefan Berger int tpm_backend_startup_tpm(TPMBackend *s, size_t buffersize) 828f0605ccSStefan Berger { 8393330cf5SAmarnath Valluri int res = 0; 848f0605ccSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 858f0605ccSStefan Berger 86b19a5eeaSAmarnath Valluri /* terminate a running TPM */ 87c4fb8561SMarc-André Lureau tpm_backend_finish_sync(s); 88b19a5eeaSAmarnath Valluri 899375c44fSStefan Berger res = k->startup_tpm ? k->startup_tpm(s, buffersize) : 0; 9093330cf5SAmarnath Valluri 9193330cf5SAmarnath Valluri s->had_startup_error = (res != 0); 9293330cf5SAmarnath Valluri 9393330cf5SAmarnath Valluri return res; 948f0605ccSStefan Berger } 958f0605ccSStefan Berger 968f0605ccSStefan Berger bool tpm_backend_had_startup_error(TPMBackend *s) 978f0605ccSStefan Berger { 9893330cf5SAmarnath Valluri return s->had_startup_error; 998f0605ccSStefan Berger } 1008f0605ccSStefan Berger 1010e43b7e6SMarc-André Lureau void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd) 1028f0605ccSStefan Berger { 103c4fb8561SMarc-André Lureau ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context()); 104c4fb8561SMarc-André Lureau 105c4fb8561SMarc-André Lureau if (s->cmd != NULL) { 106c4fb8561SMarc-André Lureau error_report("There is a TPM request pending"); 107c4fb8561SMarc-André Lureau return; 108c4fb8561SMarc-André Lureau } 109c4fb8561SMarc-André Lureau 110c4fb8561SMarc-André Lureau s->cmd = cmd; 111c4fb8561SMarc-André Lureau object_ref(OBJECT(s)); 112c4fb8561SMarc-André Lureau thread_pool_submit_aio(pool, tpm_backend_worker_thread, s, 113c4fb8561SMarc-André Lureau tpm_backend_request_completed, s); 1148f0605ccSStefan Berger } 1158f0605ccSStefan Berger 1168f0605ccSStefan Berger void tpm_backend_reset(TPMBackend *s) 1178f0605ccSStefan Berger { 1188f0605ccSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 1198f0605ccSStefan Berger 120d31076baSMarc-André Lureau if (k->reset) { 121d31076baSMarc-André Lureau k->reset(s); 12293330cf5SAmarnath Valluri } 123b19a5eeaSAmarnath Valluri 124c4fb8561SMarc-André Lureau tpm_backend_finish_sync(s); 12593330cf5SAmarnath Valluri 12693330cf5SAmarnath Valluri s->had_startup_error = false; 1278f0605ccSStefan Berger } 1288f0605ccSStefan Berger 1298f0605ccSStefan Berger void tpm_backend_cancel_cmd(TPMBackend *s) 1308f0605ccSStefan Berger { 1318f0605ccSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 1328f0605ccSStefan Berger 133d31076baSMarc-André Lureau k->cancel_cmd(s); 1348f0605ccSStefan Berger } 1358f0605ccSStefan Berger 1368f0605ccSStefan Berger bool tpm_backend_get_tpm_established_flag(TPMBackend *s) 1378f0605ccSStefan Berger { 1388f0605ccSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 1398f0605ccSStefan Berger 140d31076baSMarc-André Lureau return k->get_tpm_established_flag ? 141d31076baSMarc-André Lureau k->get_tpm_established_flag(s) : false; 1428f0605ccSStefan Berger } 1438f0605ccSStefan Berger 144116694c3SStefan Berger int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty) 145116694c3SStefan Berger { 146116694c3SStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 147116694c3SStefan Berger 148d31076baSMarc-André Lureau return k->reset_tpm_established_flag ? 149d31076baSMarc-André Lureau k->reset_tpm_established_flag(s, locty) : 0; 150116694c3SStefan Berger } 151116694c3SStefan Berger 152116694c3SStefan Berger TPMVersion tpm_backend_get_tpm_version(TPMBackend *s) 153116694c3SStefan Berger { 154116694c3SStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 155116694c3SStefan Berger 156d31076baSMarc-André Lureau return k->get_tpm_version(s); 157116694c3SStefan Berger } 158116694c3SStefan Berger 159b21e6aafSStefan Berger size_t tpm_backend_get_buffer_size(TPMBackend *s) 160b21e6aafSStefan Berger { 161b21e6aafSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 162b21e6aafSStefan Berger 163b21e6aafSStefan Berger return k->get_buffer_size(s); 164b21e6aafSStefan Berger } 165b21e6aafSStefan Berger 166f59864baSAmarnath Valluri TPMInfo *tpm_backend_query_tpm(TPMBackend *s) 167f59864baSAmarnath Valluri { 168f59864baSAmarnath Valluri TPMInfo *info = g_new0(TPMInfo, 1); 169f59864baSAmarnath Valluri TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 170191adc94SMarc-André Lureau TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif); 171f59864baSAmarnath Valluri 172f59864baSAmarnath Valluri info->id = g_strdup(s->id); 173191adc94SMarc-André Lureau info->model = tic->model; 174d31076baSMarc-André Lureau info->options = k->get_tpm_options(s); 175f59864baSAmarnath Valluri 176f59864baSAmarnath Valluri return info; 177f59864baSAmarnath Valluri } 178f59864baSAmarnath Valluri 179b19a5eeaSAmarnath Valluri static void tpm_backend_instance_finalize(Object *obj) 180bdee56f5SPaolo Bonzini { 181b19a5eeaSAmarnath Valluri TPMBackend *s = TPM_BACKEND(obj); 182bdee56f5SPaolo Bonzini 1838a89c9acSMarc-André Lureau object_unref(OBJECT(s->tpmif)); 184f35fe5cbSAmarnath Valluri g_free(s->id); 185bdee56f5SPaolo Bonzini } 186bdee56f5SPaolo Bonzini 1878f0605ccSStefan Berger static const TypeInfo tpm_backend_info = { 1888f0605ccSStefan Berger .name = TYPE_TPM_BACKEND, 1898f0605ccSStefan Berger .parent = TYPE_OBJECT, 1908f0605ccSStefan Berger .instance_size = sizeof(TPMBackend), 191b19a5eeaSAmarnath Valluri .instance_finalize = tpm_backend_instance_finalize, 1928f0605ccSStefan Berger .class_size = sizeof(TPMBackendClass), 1938f0605ccSStefan Berger .abstract = true, 1948f0605ccSStefan Berger }; 1958f0605ccSStefan Berger 196698f5daaSMarc-André Lureau static const TypeInfo tpm_if_info = { 197698f5daaSMarc-André Lureau .name = TYPE_TPM_IF, 198698f5daaSMarc-André Lureau .parent = TYPE_INTERFACE, 199698f5daaSMarc-André Lureau .class_size = sizeof(TPMIfClass), 200698f5daaSMarc-André Lureau }; 201698f5daaSMarc-André Lureau 2028f0605ccSStefan Berger static void register_types(void) 2038f0605ccSStefan Berger { 2048f0605ccSStefan Berger type_register_static(&tpm_backend_info); 205698f5daaSMarc-André Lureau type_register_static(&tpm_if_info); 2068f0605ccSStefan Berger } 2078f0605ccSStefan Berger 2088f0605ccSStefan Berger type_init(register_types); 209