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"
16*32cad1ffSPhilippe Mathieu-Daudé #include "system/tpm_backend.h"
17da34e65cSMarkus Armbruster #include "qapi/error.h"
18*32cad1ffSPhilippe Mathieu-Daudé #include "system/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
tpm_backend_request_completed(void * opaque,int ret)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
tpm_backend_worker_thread(gpointer data)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
tpm_backend_finish_sync(TPMBackend * s)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
tpm_backend_get_type(TPMBackend * s)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
tpm_backend_init(TPMBackend * s,TPMIf * tpmif,Error ** errp)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
tpm_backend_startup_tpm(TPMBackend * s,size_t buffersize)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
tpm_backend_had_startup_error(TPMBackend * s)968f0605ccSStefan Berger bool tpm_backend_had_startup_error(TPMBackend *s)
978f0605ccSStefan Berger {
9893330cf5SAmarnath Valluri return s->had_startup_error;
998f0605ccSStefan Berger }
1008f0605ccSStefan Berger
tpm_backend_deliver_request(TPMBackend * s,TPMBackendCmd * cmd)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));
110aef04fc7SEmanuele Giuseppe Esposito thread_pool_submit_aio(tpm_backend_worker_thread, s,
111c4fb8561SMarc-André Lureau tpm_backend_request_completed, s);
1128f0605ccSStefan Berger }
1138f0605ccSStefan Berger
tpm_backend_reset(TPMBackend * s)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
tpm_backend_cancel_cmd(TPMBackend * s)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
tpm_backend_get_tpm_established_flag(TPMBackend * s)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
tpm_backend_reset_tpm_established_flag(TPMBackend * s,uint8_t locty)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
tpm_backend_get_tpm_version(TPMBackend * s)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
tpm_backend_get_buffer_size(TPMBackend * s)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
tpm_backend_query_tpm(TPMBackend * s)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
tpm_backend_instance_finalize(Object * obj)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
register_types(void)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