xref: /qemu/backends/tpm/tpm_backend.c (revision c4fb8561bcec5f3ae3ae2d8a688d1e1aeb247a91)
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