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" 18bdee56f5SPaolo Bonzini #include "sysemu/tpm.h" 19bdee56f5SPaolo Bonzini #include "qemu/thread.h" 2068999059SMarc-André Lureau #include "qemu/main-loop.h" 210b8fa32fSMarkus Armbruster #include "qemu/module.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 306a8a2354SMarc-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); 416a8a2354SMarc-André Lureau Error *err = NULL; 42b19a5eeaSAmarnath Valluri 436a8a2354SMarc-André Lureau k->handle_request(s, s->cmd, &err); 446a8a2354SMarc-André Lureau if (err) { 456a8a2354SMarc-André Lureau error_report_err(err); 466a8a2354SMarc-André Lureau return -1; 476a8a2354SMarc-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 if (s->cmd != NULL) { 104c4fb8561SMarc-André Lureau error_report("There is a TPM request pending"); 105c4fb8561SMarc-André Lureau return; 106c4fb8561SMarc-André Lureau } 107c4fb8561SMarc-André Lureau 108c4fb8561SMarc-André Lureau s->cmd = cmd; 109c4fb8561SMarc-André Lureau object_ref(OBJECT(s)); 110*aef04fc7SEmanuele Giuseppe Esposito thread_pool_submit_aio(tpm_backend_worker_thread, s, 111c4fb8561SMarc-André Lureau tpm_backend_request_completed, s); 1128f0605ccSStefan Berger } 1138f0605ccSStefan Berger 1148f0605ccSStefan Berger void tpm_backend_reset(TPMBackend *s) 1158f0605ccSStefan Berger { 1168f0605ccSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 1178f0605ccSStefan Berger 118d31076baSMarc-André Lureau if (k->reset) { 119d31076baSMarc-André Lureau k->reset(s); 12093330cf5SAmarnath Valluri } 121b19a5eeaSAmarnath Valluri 122c4fb8561SMarc-André Lureau tpm_backend_finish_sync(s); 12393330cf5SAmarnath Valluri 12493330cf5SAmarnath Valluri s->had_startup_error = false; 1258f0605ccSStefan Berger } 1268f0605ccSStefan Berger 1278f0605ccSStefan Berger void tpm_backend_cancel_cmd(TPMBackend *s) 1288f0605ccSStefan Berger { 1298f0605ccSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 1308f0605ccSStefan Berger 131d31076baSMarc-André Lureau k->cancel_cmd(s); 1328f0605ccSStefan Berger } 1338f0605ccSStefan Berger 1348f0605ccSStefan Berger bool tpm_backend_get_tpm_established_flag(TPMBackend *s) 1358f0605ccSStefan Berger { 1368f0605ccSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 1378f0605ccSStefan Berger 138d31076baSMarc-André Lureau return k->get_tpm_established_flag ? 139d31076baSMarc-André Lureau k->get_tpm_established_flag(s) : false; 1408f0605ccSStefan Berger } 1418f0605ccSStefan Berger 142116694c3SStefan Berger int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty) 143116694c3SStefan Berger { 144116694c3SStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 145116694c3SStefan Berger 146d31076baSMarc-André Lureau return k->reset_tpm_established_flag ? 147d31076baSMarc-André Lureau k->reset_tpm_established_flag(s, locty) : 0; 148116694c3SStefan Berger } 149116694c3SStefan Berger 150116694c3SStefan Berger TPMVersion tpm_backend_get_tpm_version(TPMBackend *s) 151116694c3SStefan Berger { 152116694c3SStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 153116694c3SStefan Berger 154d31076baSMarc-André Lureau return k->get_tpm_version(s); 155116694c3SStefan Berger } 156116694c3SStefan Berger 157b21e6aafSStefan Berger size_t tpm_backend_get_buffer_size(TPMBackend *s) 158b21e6aafSStefan Berger { 159b21e6aafSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 160b21e6aafSStefan Berger 161b21e6aafSStefan Berger return k->get_buffer_size(s); 162b21e6aafSStefan Berger } 163b21e6aafSStefan Berger 164f59864baSAmarnath Valluri TPMInfo *tpm_backend_query_tpm(TPMBackend *s) 165f59864baSAmarnath Valluri { 166f59864baSAmarnath Valluri TPMInfo *info = g_new0(TPMInfo, 1); 167f59864baSAmarnath Valluri TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 168191adc94SMarc-André Lureau TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif); 169f59864baSAmarnath Valluri 170f59864baSAmarnath Valluri info->id = g_strdup(s->id); 171191adc94SMarc-André Lureau info->model = tic->model; 172d31076baSMarc-André Lureau info->options = k->get_tpm_options(s); 173f59864baSAmarnath Valluri 174f59864baSAmarnath Valluri return info; 175f59864baSAmarnath Valluri } 176f59864baSAmarnath Valluri 177b19a5eeaSAmarnath Valluri static void tpm_backend_instance_finalize(Object *obj) 178bdee56f5SPaolo Bonzini { 179b19a5eeaSAmarnath Valluri TPMBackend *s = TPM_BACKEND(obj); 180bdee56f5SPaolo Bonzini 1818a89c9acSMarc-André Lureau object_unref(OBJECT(s->tpmif)); 182f35fe5cbSAmarnath Valluri g_free(s->id); 183bdee56f5SPaolo Bonzini } 184bdee56f5SPaolo Bonzini 1858f0605ccSStefan Berger static const TypeInfo tpm_backend_info = { 1868f0605ccSStefan Berger .name = TYPE_TPM_BACKEND, 1878f0605ccSStefan Berger .parent = TYPE_OBJECT, 1888f0605ccSStefan Berger .instance_size = sizeof(TPMBackend), 189b19a5eeaSAmarnath Valluri .instance_finalize = tpm_backend_instance_finalize, 1908f0605ccSStefan Berger .class_size = sizeof(TPMBackendClass), 1918f0605ccSStefan Berger .abstract = true, 1928f0605ccSStefan Berger }; 1938f0605ccSStefan Berger 194698f5daaSMarc-André Lureau static const TypeInfo tpm_if_info = { 195698f5daaSMarc-André Lureau .name = TYPE_TPM_IF, 196698f5daaSMarc-André Lureau .parent = TYPE_INTERFACE, 197698f5daaSMarc-André Lureau .class_size = sizeof(TPMIfClass), 198698f5daaSMarc-André Lureau }; 199698f5daaSMarc-André Lureau 2008f0605ccSStefan Berger static void register_types(void) 2018f0605ccSStefan Berger { 2028f0605ccSStefan Berger type_register_static(&tpm_backend_info); 203698f5daaSMarc-André Lureau type_register_static(&tpm_if_info); 2048f0605ccSStefan Berger } 2058f0605ccSStefan Berger 2068f0605ccSStefan Berger type_init(register_types); 207