xref: /qemu/backends/tpm/tpm_backend.c (revision 0bd6c8a9cfa4fd5c25a32ed39f3b8cb786b75b58)
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"
2268999059SMarc-André Lureau 
2368999059SMarc-André Lureau static void tpm_backend_request_completed_bh(void *opaque)
2468999059SMarc-André Lureau {
2568999059SMarc-André Lureau     TPMBackend *s = TPM_BACKEND(opaque);
2668999059SMarc-André Lureau     TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif);
2768999059SMarc-André Lureau 
2868999059SMarc-André Lureau     tic->request_completed(s->tpmif);
2968999059SMarc-André Lureau }
30b19a5eeaSAmarnath Valluri 
31b19a5eeaSAmarnath Valluri static void tpm_backend_worker_thread(gpointer data, gpointer user_data)
32b19a5eeaSAmarnath Valluri {
33b19a5eeaSAmarnath Valluri     TPMBackend *s = TPM_BACKEND(user_data);
34b19a5eeaSAmarnath Valluri     TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
35b19a5eeaSAmarnath Valluri 
36b19a5eeaSAmarnath Valluri     assert(k->handle_request != NULL);
370e43b7e6SMarc-André Lureau     k->handle_request(s, (TPMBackendCmd *)data);
3868999059SMarc-André Lureau 
3968999059SMarc-André Lureau     qemu_bh_schedule(s->bh);
40b19a5eeaSAmarnath Valluri }
41b19a5eeaSAmarnath Valluri 
42b19a5eeaSAmarnath Valluri static void tpm_backend_thread_end(TPMBackend *s)
43b19a5eeaSAmarnath Valluri {
44b19a5eeaSAmarnath Valluri     if (s->thread_pool) {
45b19a5eeaSAmarnath Valluri         g_thread_pool_free(s->thread_pool, FALSE, TRUE);
46b19a5eeaSAmarnath Valluri         s->thread_pool = NULL;
47b19a5eeaSAmarnath Valluri     }
48b19a5eeaSAmarnath Valluri }
498f0605ccSStefan Berger 
508f0605ccSStefan Berger enum TpmType tpm_backend_get_type(TPMBackend *s)
518f0605ccSStefan Berger {
528f0605ccSStefan Berger     TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
538f0605ccSStefan Berger 
54d31076baSMarc-André Lureau     return k->type;
558f0605ccSStefan Berger }
568f0605ccSStefan Berger 
57*0bd6c8a9SMarc-André Lureau int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp)
588f0605ccSStefan Berger {
598a89c9acSMarc-André Lureau     if (s->tpmif) {
60*0bd6c8a9SMarc-André Lureau         error_setg(errp, "TPM backend '%s' is already initialized", s->id);
618a89c9acSMarc-André Lureau         return -1;
628a89c9acSMarc-André Lureau     }
638a89c9acSMarc-André Lureau 
648a89c9acSMarc-André Lureau     s->tpmif = tpmif;
658a89c9acSMarc-André Lureau     object_ref(OBJECT(tpmif));
668a89c9acSMarc-André Lureau 
6793330cf5SAmarnath Valluri     s->had_startup_error = false;
68b19a5eeaSAmarnath Valluri 
6927a79d96SMarc-André Lureau     return 0;
708f0605ccSStefan Berger }
718f0605ccSStefan Berger 
728f0605ccSStefan Berger int tpm_backend_startup_tpm(TPMBackend *s)
738f0605ccSStefan Berger {
7493330cf5SAmarnath Valluri     int res = 0;
758f0605ccSStefan Berger     TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
768f0605ccSStefan Berger 
77b19a5eeaSAmarnath Valluri     /* terminate a running TPM */
78b19a5eeaSAmarnath Valluri     tpm_backend_thread_end(s);
79b19a5eeaSAmarnath Valluri 
80b19a5eeaSAmarnath Valluri     s->thread_pool = g_thread_pool_new(tpm_backend_worker_thread, s, 1, TRUE,
81b19a5eeaSAmarnath Valluri                                        NULL);
82b19a5eeaSAmarnath Valluri 
83d31076baSMarc-André Lureau     res = k->startup_tpm ? k->startup_tpm(s) : 0;
8493330cf5SAmarnath Valluri 
8593330cf5SAmarnath Valluri     s->had_startup_error = (res != 0);
8693330cf5SAmarnath Valluri 
8793330cf5SAmarnath Valluri     return res;
888f0605ccSStefan Berger }
898f0605ccSStefan Berger 
908f0605ccSStefan Berger bool tpm_backend_had_startup_error(TPMBackend *s)
918f0605ccSStefan Berger {
9293330cf5SAmarnath Valluri     return s->had_startup_error;
938f0605ccSStefan Berger }
948f0605ccSStefan Berger 
950e43b7e6SMarc-André Lureau void tpm_backend_deliver_request(TPMBackend *s, TPMBackendCmd *cmd)
968f0605ccSStefan Berger {
970e43b7e6SMarc-André Lureau     g_thread_pool_push(s->thread_pool, cmd, NULL);
988f0605ccSStefan Berger }
998f0605ccSStefan Berger 
1008f0605ccSStefan Berger void tpm_backend_reset(TPMBackend *s)
1018f0605ccSStefan Berger {
1028f0605ccSStefan Berger     TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
1038f0605ccSStefan Berger 
104d31076baSMarc-André Lureau     if (k->reset) {
105d31076baSMarc-André Lureau         k->reset(s);
10693330cf5SAmarnath Valluri     }
107b19a5eeaSAmarnath Valluri 
108b19a5eeaSAmarnath Valluri     tpm_backend_thread_end(s);
10993330cf5SAmarnath Valluri 
11093330cf5SAmarnath Valluri     s->had_startup_error = false;
1118f0605ccSStefan Berger }
1128f0605ccSStefan Berger 
1138f0605ccSStefan Berger void tpm_backend_cancel_cmd(TPMBackend *s)
1148f0605ccSStefan Berger {
1158f0605ccSStefan Berger     TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
1168f0605ccSStefan Berger 
117d31076baSMarc-André Lureau     assert(k->cancel_cmd);
11893330cf5SAmarnath Valluri 
119d31076baSMarc-André Lureau     k->cancel_cmd(s);
1208f0605ccSStefan Berger }
1218f0605ccSStefan Berger 
1228f0605ccSStefan Berger bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
1238f0605ccSStefan Berger {
1248f0605ccSStefan Berger     TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
1258f0605ccSStefan Berger 
126d31076baSMarc-André Lureau     return k->get_tpm_established_flag ?
127d31076baSMarc-André Lureau            k->get_tpm_established_flag(s) : false;
1288f0605ccSStefan Berger }
1298f0605ccSStefan Berger 
130116694c3SStefan Berger int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty)
131116694c3SStefan Berger {
132116694c3SStefan Berger     TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
133116694c3SStefan Berger 
134d31076baSMarc-André Lureau     return k->reset_tpm_established_flag ?
135d31076baSMarc-André Lureau            k->reset_tpm_established_flag(s, locty) : 0;
136116694c3SStefan Berger }
137116694c3SStefan Berger 
138116694c3SStefan Berger TPMVersion tpm_backend_get_tpm_version(TPMBackend *s)
139116694c3SStefan Berger {
140116694c3SStefan Berger     TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
141116694c3SStefan Berger 
142d31076baSMarc-André Lureau     assert(k->get_tpm_version);
14393330cf5SAmarnath Valluri 
144d31076baSMarc-André Lureau     return k->get_tpm_version(s);
145116694c3SStefan Berger }
146116694c3SStefan Berger 
147f59864baSAmarnath Valluri TPMInfo *tpm_backend_query_tpm(TPMBackend *s)
148f59864baSAmarnath Valluri {
149f59864baSAmarnath Valluri     TPMInfo *info = g_new0(TPMInfo, 1);
150f59864baSAmarnath Valluri     TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
151f59864baSAmarnath Valluri 
152f59864baSAmarnath Valluri     info->id = g_strdup(s->id);
153f59864baSAmarnath Valluri     info->model = s->fe_model;
154d31076baSMarc-André Lureau     if (k->get_tpm_options) {
155d31076baSMarc-André Lureau         info->options = k->get_tpm_options(s);
156d31076baSMarc-André Lureau     }
157f59864baSAmarnath Valluri 
158f59864baSAmarnath Valluri     return info;
159f59864baSAmarnath Valluri }
160f59864baSAmarnath Valluri 
1618f0605ccSStefan Berger static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
1628f0605ccSStefan Berger {
1638f0605ccSStefan Berger     TPMBackend *s = TPM_BACKEND(obj);
1648f0605ccSStefan Berger 
1658f0605ccSStefan Berger     return s->opened;
1668f0605ccSStefan Berger }
1678f0605ccSStefan Berger 
1688f0605ccSStefan Berger void tpm_backend_open(TPMBackend *s, Error **errp)
1698f0605ccSStefan Berger {
1708f0605ccSStefan Berger     object_property_set_bool(OBJECT(s), true, "opened", errp);
1718f0605ccSStefan Berger }
1728f0605ccSStefan Berger 
1738f0605ccSStefan Berger static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp)
1748f0605ccSStefan Berger {
1758f0605ccSStefan Berger     TPMBackend *s = TPM_BACKEND(obj);
1768f0605ccSStefan Berger     TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
17765cd9064SMarkus Armbruster     Error *local_err = NULL;
1788f0605ccSStefan Berger 
1798f0605ccSStefan Berger     if (value == s->opened) {
1808f0605ccSStefan Berger         return;
1818f0605ccSStefan Berger     }
1828f0605ccSStefan Berger 
1838f0605ccSStefan Berger     if (!value && s->opened) {
184c6bd8c70SMarkus Armbruster         error_setg(errp, QERR_PERMISSION_DENIED);
1858f0605ccSStefan Berger         return;
1868f0605ccSStefan Berger     }
1878f0605ccSStefan Berger 
1888f0605ccSStefan Berger     if (k->opened) {
18965cd9064SMarkus Armbruster         k->opened(s, &local_err);
19065cd9064SMarkus Armbruster         if (local_err) {
19165cd9064SMarkus Armbruster             error_propagate(errp, local_err);
19265cd9064SMarkus Armbruster             return;
19365cd9064SMarkus Armbruster         }
1948f0605ccSStefan Berger     }
1958f0605ccSStefan Berger 
19665cd9064SMarkus Armbruster     s->opened = true;
1978f0605ccSStefan Berger }
1988f0605ccSStefan Berger 
1998f0605ccSStefan Berger static void tpm_backend_instance_init(Object *obj)
2008f0605ccSStefan Berger {
201f35fe5cbSAmarnath Valluri     TPMBackend *s = TPM_BACKEND(obj);
202f35fe5cbSAmarnath Valluri 
2038f0605ccSStefan Berger     object_property_add_bool(obj, "opened",
2048f0605ccSStefan Berger                              tpm_backend_prop_get_opened,
2058f0605ccSStefan Berger                              tpm_backend_prop_set_opened,
2068f0605ccSStefan Berger                              NULL);
207f35fe5cbSAmarnath Valluri     s->fe_model = -1;
20868999059SMarc-André Lureau     s->bh = qemu_bh_new(tpm_backend_request_completed_bh, s);
2098f0605ccSStefan Berger }
2108f0605ccSStefan Berger 
211b19a5eeaSAmarnath Valluri static void tpm_backend_instance_finalize(Object *obj)
212bdee56f5SPaolo Bonzini {
213b19a5eeaSAmarnath Valluri     TPMBackend *s = TPM_BACKEND(obj);
214bdee56f5SPaolo Bonzini 
2158a89c9acSMarc-André Lureau     object_unref(OBJECT(s->tpmif));
216f35fe5cbSAmarnath Valluri     g_free(s->id);
217b19a5eeaSAmarnath Valluri     tpm_backend_thread_end(s);
21868999059SMarc-André Lureau     qemu_bh_delete(s->bh);
219bdee56f5SPaolo Bonzini }
220bdee56f5SPaolo Bonzini 
2218f0605ccSStefan Berger static const TypeInfo tpm_backend_info = {
2228f0605ccSStefan Berger     .name = TYPE_TPM_BACKEND,
2238f0605ccSStefan Berger     .parent = TYPE_OBJECT,
2248f0605ccSStefan Berger     .instance_size = sizeof(TPMBackend),
2258f0605ccSStefan Berger     .instance_init = tpm_backend_instance_init,
226b19a5eeaSAmarnath Valluri     .instance_finalize = tpm_backend_instance_finalize,
2278f0605ccSStefan Berger     .class_size = sizeof(TPMBackendClass),
2288f0605ccSStefan Berger     .abstract = true,
2298f0605ccSStefan Berger };
2308f0605ccSStefan Berger 
231698f5daaSMarc-André Lureau static const TypeInfo tpm_if_info = {
232698f5daaSMarc-André Lureau     .name = TYPE_TPM_IF,
233698f5daaSMarc-André Lureau     .parent = TYPE_INTERFACE,
234698f5daaSMarc-André Lureau     .class_size = sizeof(TPMIfClass),
235698f5daaSMarc-André Lureau };
236698f5daaSMarc-André Lureau 
2378f0605ccSStefan Berger static void register_types(void)
2388f0605ccSStefan Berger {
2398f0605ccSStefan Berger     type_register_static(&tpm_backend_info);
240698f5daaSMarc-André Lureau     type_register_static(&tpm_if_info);
2418f0605ccSStefan Berger }
2428f0605ccSStefan Berger 
2438f0605ccSStefan Berger type_init(register_types);
244