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" 22*c4fb8561SMarc-André Lureau #include "block/thread-pool.h" 23*c4fb8561SMarc-André Lureau #include "qemu/error-report.h" 2468999059SMarc-André Lureau 25*c4fb8561SMarc-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 3068999059SMarc-André Lureau tic->request_completed(s->tpmif); 31*c4fb8561SMarc-André Lureau 32*c4fb8561SMarc-André Lureau /* no need for atomic, as long the BQL is taken */ 33*c4fb8561SMarc-André Lureau s->cmd = NULL; 34*c4fb8561SMarc-André Lureau object_unref(OBJECT(s)); 3568999059SMarc-André Lureau } 36b19a5eeaSAmarnath Valluri 37*c4fb8561SMarc-André Lureau static int tpm_backend_worker_thread(gpointer data) 38b19a5eeaSAmarnath Valluri { 39*c4fb8561SMarc-André Lureau TPMBackend *s = TPM_BACKEND(data); 40b19a5eeaSAmarnath Valluri TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 41b19a5eeaSAmarnath Valluri 42*c4fb8561SMarc-André Lureau k->handle_request(s, s->cmd); 4368999059SMarc-André Lureau 44*c4fb8561SMarc-André Lureau return 0; 45b19a5eeaSAmarnath Valluri } 46b19a5eeaSAmarnath Valluri 47*c4fb8561SMarc-André Lureau void tpm_backend_finish_sync(TPMBackend *s) 48b19a5eeaSAmarnath Valluri { 49*c4fb8561SMarc-André Lureau while (s->cmd) { 50*c4fb8561SMarc-André Lureau aio_poll(qemu_get_aio_context(), true); 51b19a5eeaSAmarnath Valluri } 52b19a5eeaSAmarnath Valluri } 538f0605ccSStefan Berger 548f0605ccSStefan Berger enum TpmType tpm_backend_get_type(TPMBackend *s) 558f0605ccSStefan Berger { 568f0605ccSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 578f0605ccSStefan Berger 58d31076baSMarc-André Lureau return k->type; 598f0605ccSStefan Berger } 608f0605ccSStefan Berger 610bd6c8a9SMarc-André Lureau int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp) 628f0605ccSStefan Berger { 638a89c9acSMarc-André Lureau if (s->tpmif) { 640bd6c8a9SMarc-André Lureau error_setg(errp, "TPM backend '%s' is already initialized", s->id); 658a89c9acSMarc-André Lureau return -1; 668a89c9acSMarc-André Lureau } 678a89c9acSMarc-André Lureau 688a89c9acSMarc-André Lureau s->tpmif = tpmif; 698a89c9acSMarc-André Lureau object_ref(OBJECT(tpmif)); 708a89c9acSMarc-André Lureau 7193330cf5SAmarnath Valluri s->had_startup_error = false; 72b19a5eeaSAmarnath Valluri 7327a79d96SMarc-André Lureau return 0; 748f0605ccSStefan Berger } 758f0605ccSStefan Berger 769375c44fSStefan Berger int tpm_backend_startup_tpm(TPMBackend *s, size_t buffersize) 778f0605ccSStefan Berger { 7893330cf5SAmarnath Valluri int res = 0; 798f0605ccSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 808f0605ccSStefan Berger 81b19a5eeaSAmarnath Valluri /* terminate a running TPM */ 82*c4fb8561SMarc-André Lureau tpm_backend_finish_sync(s); 83b19a5eeaSAmarnath Valluri 849375c44fSStefan Berger res = k->startup_tpm ? k->startup_tpm(s, buffersize) : 0; 8593330cf5SAmarnath Valluri 8693330cf5SAmarnath Valluri s->had_startup_error = (res != 0); 8793330cf5SAmarnath Valluri 8893330cf5SAmarnath Valluri return res; 898f0605ccSStefan Berger } 908f0605ccSStefan Berger 918f0605ccSStefan Berger bool tpm_backend_had_startup_error(TPMBackend *s) 928f0605ccSStefan Berger { 9393330cf5SAmarnath Valluri return s->had_startup_error; 948f0605ccSStefan Berger } 958f0605ccSStefan Berger 960e43b7e6SMarc-André Lureau void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd) 978f0605ccSStefan Berger { 98*c4fb8561SMarc-André Lureau ThreadPool *pool = aio_get_thread_pool(qemu_get_aio_context()); 99*c4fb8561SMarc-André Lureau 100*c4fb8561SMarc-André Lureau if (s->cmd != NULL) { 101*c4fb8561SMarc-André Lureau error_report("There is a TPM request pending"); 102*c4fb8561SMarc-André Lureau return; 103*c4fb8561SMarc-André Lureau } 104*c4fb8561SMarc-André Lureau 105*c4fb8561SMarc-André Lureau s->cmd = cmd; 106*c4fb8561SMarc-André Lureau object_ref(OBJECT(s)); 107*c4fb8561SMarc-André Lureau thread_pool_submit_aio(pool, tpm_backend_worker_thread, s, 108*c4fb8561SMarc-André Lureau tpm_backend_request_completed, s); 1098f0605ccSStefan Berger } 1108f0605ccSStefan Berger 1118f0605ccSStefan Berger void tpm_backend_reset(TPMBackend *s) 1128f0605ccSStefan Berger { 1138f0605ccSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 1148f0605ccSStefan Berger 115d31076baSMarc-André Lureau if (k->reset) { 116d31076baSMarc-André Lureau k->reset(s); 11793330cf5SAmarnath Valluri } 118b19a5eeaSAmarnath Valluri 119*c4fb8561SMarc-André Lureau tpm_backend_finish_sync(s); 12093330cf5SAmarnath Valluri 12193330cf5SAmarnath Valluri s->had_startup_error = false; 1228f0605ccSStefan Berger } 1238f0605ccSStefan Berger 1248f0605ccSStefan Berger void tpm_backend_cancel_cmd(TPMBackend *s) 1258f0605ccSStefan Berger { 1268f0605ccSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 1278f0605ccSStefan Berger 128d31076baSMarc-André Lureau k->cancel_cmd(s); 1298f0605ccSStefan Berger } 1308f0605ccSStefan Berger 1318f0605ccSStefan Berger bool tpm_backend_get_tpm_established_flag(TPMBackend *s) 1328f0605ccSStefan Berger { 1338f0605ccSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 1348f0605ccSStefan Berger 135d31076baSMarc-André Lureau return k->get_tpm_established_flag ? 136d31076baSMarc-André Lureau k->get_tpm_established_flag(s) : false; 1378f0605ccSStefan Berger } 1388f0605ccSStefan Berger 139116694c3SStefan Berger int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty) 140116694c3SStefan Berger { 141116694c3SStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 142116694c3SStefan Berger 143d31076baSMarc-André Lureau return k->reset_tpm_established_flag ? 144d31076baSMarc-André Lureau k->reset_tpm_established_flag(s, locty) : 0; 145116694c3SStefan Berger } 146116694c3SStefan Berger 147116694c3SStefan Berger TPMVersion tpm_backend_get_tpm_version(TPMBackend *s) 148116694c3SStefan Berger { 149116694c3SStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 150116694c3SStefan Berger 151d31076baSMarc-André Lureau return k->get_tpm_version(s); 152116694c3SStefan Berger } 153116694c3SStefan Berger 154b21e6aafSStefan Berger size_t tpm_backend_get_buffer_size(TPMBackend *s) 155b21e6aafSStefan Berger { 156b21e6aafSStefan Berger TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 157b21e6aafSStefan Berger 158b21e6aafSStefan Berger return k->get_buffer_size(s); 159b21e6aafSStefan Berger } 160b21e6aafSStefan Berger 161f59864baSAmarnath Valluri TPMInfo *tpm_backend_query_tpm(TPMBackend *s) 162f59864baSAmarnath Valluri { 163f59864baSAmarnath Valluri TPMInfo *info = g_new0(TPMInfo, 1); 164f59864baSAmarnath Valluri TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 165191adc94SMarc-André Lureau TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif); 166f59864baSAmarnath Valluri 167f59864baSAmarnath Valluri info->id = g_strdup(s->id); 168191adc94SMarc-André Lureau info->model = tic->model; 169d31076baSMarc-André Lureau info->options = k->get_tpm_options(s); 170f59864baSAmarnath Valluri 171f59864baSAmarnath Valluri return info; 172f59864baSAmarnath Valluri } 173f59864baSAmarnath Valluri 174b19a5eeaSAmarnath Valluri static void tpm_backend_instance_finalize(Object *obj) 175bdee56f5SPaolo Bonzini { 176b19a5eeaSAmarnath Valluri TPMBackend *s = TPM_BACKEND(obj); 177bdee56f5SPaolo Bonzini 1788a89c9acSMarc-André Lureau object_unref(OBJECT(s->tpmif)); 179f35fe5cbSAmarnath Valluri g_free(s->id); 180bdee56f5SPaolo Bonzini } 181bdee56f5SPaolo Bonzini 1828f0605ccSStefan Berger static const TypeInfo tpm_backend_info = { 1838f0605ccSStefan Berger .name = TYPE_TPM_BACKEND, 1848f0605ccSStefan Berger .parent = TYPE_OBJECT, 1858f0605ccSStefan Berger .instance_size = sizeof(TPMBackend), 186b19a5eeaSAmarnath Valluri .instance_finalize = tpm_backend_instance_finalize, 1878f0605ccSStefan Berger .class_size = sizeof(TPMBackendClass), 1888f0605ccSStefan Berger .abstract = true, 1898f0605ccSStefan Berger }; 1908f0605ccSStefan Berger 191698f5daaSMarc-André Lureau static const TypeInfo tpm_if_info = { 192698f5daaSMarc-André Lureau .name = TYPE_TPM_IF, 193698f5daaSMarc-André Lureau .parent = TYPE_INTERFACE, 194698f5daaSMarc-André Lureau .class_size = sizeof(TPMIfClass), 195698f5daaSMarc-André Lureau }; 196698f5daaSMarc-André Lureau 1978f0605ccSStefan Berger static void register_types(void) 1988f0605ccSStefan Berger { 1998f0605ccSStefan Berger type_register_static(&tpm_backend_info); 200698f5daaSMarc-André Lureau type_register_static(&tpm_if_info); 2018f0605ccSStefan Berger } 2028f0605ccSStefan Berger 2038f0605ccSStefan Berger type_init(register_types); 204