* [Qemu-devel] [PATCH 1/7] tpm-backend: Remove unneeded member variable from backend class
2017-03-31 13:10 [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator Amarnath Valluri
@ 2017-03-31 13:10 ` Amarnath Valluri
2017-04-03 17:02 ` Marc-André Lureau
2017-04-04 13:14 ` Philippe Mathieu-Daudé
2017-03-31 13:10 ` [Qemu-devel] [PATCH 2/7] tpm-backend: Move thread handling inside TPMBackend Amarnath Valluri
` (8 subsequent siblings)
9 siblings, 2 replies; 37+ messages in thread
From: Amarnath Valluri @ 2017-03-31 13:10 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanb, patrick.ohly, Amarnath Valluri
TPMDriverOps inside TPMBackend is not required, as it is supposed to be a class
member. The only possible reason for keeping in TPMBackend was, to get the
backend type in tpm.c where dedicated backend api, tpm_backend_get_type() is
present.
Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
---
hw/tpm/tpm_passthrough.c | 4 ----
include/sysemu/tpm_backend.h | 1 -
tpm.c | 2 +-
3 files changed, 1 insertion(+), 6 deletions(-)
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index 9234eb3..a0baf5f 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -46,8 +46,6 @@
#define TPM_PASSTHROUGH(obj) \
OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
-static const TPMDriverOps tpm_passthrough_driver;
-
/* data structures */
typedef struct TPMPassthruThreadParams {
TPMState *tpm_state;
@@ -462,8 +460,6 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
/* let frontend set the fe_model to proper value */
tb->fe_model = -1;
- tb->ops = &tpm_passthrough_driver;
-
if (tpm_passthrough_handle_device_opts(opts, tb)) {
goto err_exit;
}
diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
index b58f52d..e7f590d 100644
--- a/include/sysemu/tpm_backend.h
+++ b/include/sysemu/tpm_backend.h
@@ -50,7 +50,6 @@ struct TPMBackend {
enum TpmModel fe_model;
char *path;
char *cancel_path;
- const TPMDriverOps *ops;
QLIST_ENTRY(TPMBackend) list;
};
diff --git a/tpm.c b/tpm.c
index 9a7c711..0ee021a 100644
--- a/tpm.c
+++ b/tpm.c
@@ -258,7 +258,7 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
res->model = drv->fe_model;
res->options = g_new0(TpmTypeOptions, 1);
- switch (drv->ops->type) {
+ switch (tpm_backend_get_type(drv)) {
case TPM_TYPE_PASSTHROUGH:
res->options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
tpo = g_new0(TPMPassthroughOptions, 1);
--
2.7.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 1/7] tpm-backend: Remove unneeded member variable from backend class
2017-03-31 13:10 ` [Qemu-devel] [PATCH 1/7] tpm-backend: Remove unneeded member variable from backend class Amarnath Valluri
@ 2017-04-03 17:02 ` Marc-André Lureau
2017-04-04 13:14 ` Philippe Mathieu-Daudé
1 sibling, 0 replies; 37+ messages in thread
From: Marc-André Lureau @ 2017-04-03 17:02 UTC (permalink / raw)
To: Amarnath Valluri, qemu-devel; +Cc: patrick.ohly, stefanb
Hi
On Fri, Mar 31, 2017 at 4:58 PM Amarnath Valluri <amarnath.valluri@intel.com>
wrote:
> TPMDriverOps inside TPMBackend is not required, as it is supposed to be a
> class
> member. The only possible reason for keeping in TPMBackend was, to get the
> backend type in tpm.c where dedicated backend api, tpm_backend_get_type()
> is
> present.
>
> Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
> hw/tpm/tpm_passthrough.c | 4 ----
> include/sysemu/tpm_backend.h | 1 -
> tpm.c | 2 +-
> 3 files changed, 1 insertion(+), 6 deletions(-)
>
> diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
> index 9234eb3..a0baf5f 100644
> --- a/hw/tpm/tpm_passthrough.c
> +++ b/hw/tpm/tpm_passthrough.c
> @@ -46,8 +46,6 @@
> #define TPM_PASSTHROUGH(obj) \
> OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
>
> -static const TPMDriverOps tpm_passthrough_driver;
> -
> /* data structures */
> typedef struct TPMPassthruThreadParams {
> TPMState *tpm_state;
> @@ -462,8 +460,6 @@ static TPMBackend *tpm_passthrough_create(QemuOpts
> *opts, const char *id)
> /* let frontend set the fe_model to proper value */
> tb->fe_model = -1;
>
> - tb->ops = &tpm_passthrough_driver;
> -
> if (tpm_passthrough_handle_device_opts(opts, tb)) {
> goto err_exit;
> }
> diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
> index b58f52d..e7f590d 100644
> --- a/include/sysemu/tpm_backend.h
> +++ b/include/sysemu/tpm_backend.h
> @@ -50,7 +50,6 @@ struct TPMBackend {
> enum TpmModel fe_model;
> char *path;
> char *cancel_path;
> - const TPMDriverOps *ops;
>
> QLIST_ENTRY(TPMBackend) list;
> };
> diff --git a/tpm.c b/tpm.c
> index 9a7c711..0ee021a 100644
> --- a/tpm.c
> +++ b/tpm.c
> @@ -258,7 +258,7 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
> res->model = drv->fe_model;
> res->options = g_new0(TpmTypeOptions, 1);
>
> - switch (drv->ops->type) {
> + switch (tpm_backend_get_type(drv)) {
> case TPM_TYPE_PASSTHROUGH:
> res->options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
> tpo = g_new0(TPMPassthroughOptions, 1);
> --
> 2.7.4
>
>
> --
Marc-André Lureau
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 1/7] tpm-backend: Remove unneeded member variable from backend class
2017-03-31 13:10 ` [Qemu-devel] [PATCH 1/7] tpm-backend: Remove unneeded member variable from backend class Amarnath Valluri
2017-04-03 17:02 ` Marc-André Lureau
@ 2017-04-04 13:14 ` Philippe Mathieu-Daudé
1 sibling, 0 replies; 37+ messages in thread
From: Philippe Mathieu-Daudé @ 2017-04-04 13:14 UTC (permalink / raw)
To: Amarnath Valluri, qemu-devel; +Cc: patrick.ohly, stefanb
On 03/31/2017 10:10 AM, Amarnath Valluri wrote:
> TPMDriverOps inside TPMBackend is not required, as it is supposed to be a class
> member. The only possible reason for keeping in TPMBackend was, to get the
> backend type in tpm.c where dedicated backend api, tpm_backend_get_type() is
> present.
>
> Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> ---
> hw/tpm/tpm_passthrough.c | 4 ----
> include/sysemu/tpm_backend.h | 1 -
> tpm.c | 2 +-
> 3 files changed, 1 insertion(+), 6 deletions(-)
>
> diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
> index 9234eb3..a0baf5f 100644
> --- a/hw/tpm/tpm_passthrough.c
> +++ b/hw/tpm/tpm_passthrough.c
> @@ -46,8 +46,6 @@
> #define TPM_PASSTHROUGH(obj) \
> OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
>
> -static const TPMDriverOps tpm_passthrough_driver;
> -
> /* data structures */
> typedef struct TPMPassthruThreadParams {
> TPMState *tpm_state;
> @@ -462,8 +460,6 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
> /* let frontend set the fe_model to proper value */
> tb->fe_model = -1;
>
> - tb->ops = &tpm_passthrough_driver;
> -
> if (tpm_passthrough_handle_device_opts(opts, tb)) {
> goto err_exit;
> }
> diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
> index b58f52d..e7f590d 100644
> --- a/include/sysemu/tpm_backend.h
> +++ b/include/sysemu/tpm_backend.h
> @@ -50,7 +50,6 @@ struct TPMBackend {
> enum TpmModel fe_model;
> char *path;
> char *cancel_path;
> - const TPMDriverOps *ops;
>
> QLIST_ENTRY(TPMBackend) list;
> };
> diff --git a/tpm.c b/tpm.c
> index 9a7c711..0ee021a 100644
> --- a/tpm.c
> +++ b/tpm.c
> @@ -258,7 +258,7 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
> res->model = drv->fe_model;
> res->options = g_new0(TpmTypeOptions, 1);
>
> - switch (drv->ops->type) {
> + switch (tpm_backend_get_type(drv)) {
> case TPM_TYPE_PASSTHROUGH:
> res->options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
> tpo = g_new0(TPMPassthroughOptions, 1);
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH 2/7] tpm-backend: Move thread handling inside TPMBackend
2017-03-31 13:10 [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator Amarnath Valluri
2017-03-31 13:10 ` [Qemu-devel] [PATCH 1/7] tpm-backend: Remove unneeded member variable from backend class Amarnath Valluri
@ 2017-03-31 13:10 ` Amarnath Valluri
2017-04-04 10:56 ` Marc-André Lureau
2017-03-31 13:10 ` [Qemu-devel] [PATCH 3/7] tpm-backend: Initialize and free data members in it's own methods Amarnath Valluri
` (7 subsequent siblings)
9 siblings, 1 reply; 37+ messages in thread
From: Amarnath Valluri @ 2017-03-31 13:10 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanb, patrick.ohly, Amarnath Valluri
Move thread handling inside TPMBackend, this way backend implementations need
not to maintain their own thread life cycle, instead they needs to implement
'handle_request()' class method that always been called from a thread.
This change also demands to move TPMBackendClass definition to
tpm_backend_int.h. As handle_request() method is internal to TPMBackend and its
derived classes, and shall not be visible for others.
Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
---
backends/tpm.c | 66 ++++++++++++++++++++++++++--------------
hw/tpm/tpm_passthrough.c | 57 +++++-----------------------------
include/sysemu/tpm_backend.h | 19 +++---------
include/sysemu/tpm_backend_int.h | 19 ++++++------
4 files changed, 67 insertions(+), 94 deletions(-)
diff --git a/backends/tpm.c b/backends/tpm.c
index 536f262..50a7809 100644
--- a/backends/tpm.c
+++ b/backends/tpm.c
@@ -20,6 +20,25 @@
#include "qemu/thread.h"
#include "sysemu/tpm_backend_int.h"
+static void tpm_backend_worker_thread(gpointer data, gpointer user_data)
+{
+ TPMBackend *s = TPM_BACKEND(user_data);
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ if (k->handle_request) {
+ k->handle_request(s, (TPMBackendCmd)data);
+ }
+}
+
+static void tpm_backend_thread_end(TPMBackend *s)
+{
+ if (s->thread_pool) {
+ g_thread_pool_push(s->thread_pool, (gpointer)TPM_BACKEND_CMD_END, NULL);
+ g_thread_pool_free(s->thread_pool, FALSE, TRUE);
+ s->thread_pool = NULL;
+ }
+}
+
enum TpmType tpm_backend_get_type(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
@@ -39,6 +58,8 @@ void tpm_backend_destroy(TPMBackend *s)
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
k->ops->destroy(s);
+
+ tpm_backend_thread_end(s);
}
int tpm_backend_init(TPMBackend *s, TPMState *state,
@@ -46,13 +67,26 @@ int tpm_backend_init(TPMBackend *s, TPMState *state,
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
- return k->ops->init(s, state, datacb);
+ s->tpm_state = state;
+ s->recv_data_callback = datacb;
+
+ return k->ops->init(s);
}
int tpm_backend_startup_tpm(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+ /* terminate a running TPM */
+ tpm_backend_thread_end(s);
+
+ if (!s->thread_pool) {
+ s->thread_pool = g_thread_pool_new(tpm_backend_worker_thread, s, 1,
+ TRUE, NULL);
+ g_thread_pool_push(s->thread_pool, (gpointer)TPM_BACKEND_CMD_INIT,
+ NULL);
+ }
+
return k->ops->startup_tpm(s);
}
@@ -72,9 +106,8 @@ size_t tpm_backend_realloc_buffer(TPMBackend *s, TPMSizedBuffer *sb)
void tpm_backend_deliver_request(TPMBackend *s)
{
- TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
-
- k->ops->deliver_request(s);
+ g_thread_pool_push(s->thread_pool, (gpointer)TPM_BACKEND_CMD_PROCESS_CMD,
+ NULL);
}
void tpm_backend_reset(TPMBackend *s)
@@ -82,6 +115,8 @@ void tpm_backend_reset(TPMBackend *s)
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
k->ops->reset(s);
+
+ tpm_backend_thread_end(s);
}
void tpm_backend_cancel_cmd(TPMBackend *s)
@@ -156,29 +191,15 @@ static void tpm_backend_instance_init(Object *obj)
tpm_backend_prop_get_opened,
tpm_backend_prop_set_opened,
NULL);
-}
-void tpm_backend_thread_deliver_request(TPMBackendThread *tbt)
-{
- g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_PROCESS_CMD, NULL);
}
-void tpm_backend_thread_create(TPMBackendThread *tbt,
- GFunc func, gpointer user_data)
+static void tpm_backend_instance_finalize(Object *obj)
{
- if (!tbt->pool) {
- tbt->pool = g_thread_pool_new(func, user_data, 1, TRUE, NULL);
- g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_INIT, NULL);
- }
-}
+ TPMBackend *s = TPM_BACKEND(obj);
-void tpm_backend_thread_end(TPMBackendThread *tbt)
-{
- if (tbt->pool) {
- g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_END, NULL);
- g_thread_pool_free(tbt->pool, FALSE, TRUE);
- tbt->pool = NULL;
- }
+ g_free(s->id);
+ tpm_backend_thread_end(s);
}
static const TypeInfo tpm_backend_info = {
@@ -186,6 +207,7 @@ static const TypeInfo tpm_backend_info = {
.parent = TYPE_OBJECT,
.instance_size = sizeof(TPMBackend),
.instance_init = tpm_backend_instance_init,
+ .instance_finalize = tpm_backend_instance_finalize,
.class_size = sizeof(TPMBackendClass),
.abstract = true,
};
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index a0baf5f..606e064 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -47,20 +47,9 @@
OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
/* data structures */
-typedef struct TPMPassthruThreadParams {
- TPMState *tpm_state;
-
- TPMRecvDataCB *recv_data_callback;
- TPMBackend *tb;
-} TPMPassthruThreadParams;
-
struct TPMPassthruState {
TPMBackend parent;
- TPMBackendThread tbt;
-
- TPMPassthruThreadParams tpm_thread_params;
-
char *tpm_dev;
int tpm_fd;
bool tpm_executing;
@@ -214,12 +203,9 @@ static int tpm_passthrough_unix_transfer(TPMPassthruState *tpm_pt,
selftest_done);
}
-static void tpm_passthrough_worker_thread(gpointer data,
- gpointer user_data)
+static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd cmd)
{
- TPMPassthruThreadParams *thr_parms = user_data;
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(thr_parms->tb);
- TPMBackendCmd cmd = (TPMBackendCmd)data;
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
bool selftest_done = false;
DPRINTF("tpm_passthrough: processing command type %d\n", cmd);
@@ -227,12 +213,12 @@ static void tpm_passthrough_worker_thread(gpointer data,
switch (cmd) {
case TPM_BACKEND_CMD_PROCESS_CMD:
tpm_passthrough_unix_transfer(tpm_pt,
- thr_parms->tpm_state->locty_data,
+ tb->tpm_state->locty_data,
&selftest_done);
- thr_parms->recv_data_callback(thr_parms->tpm_state,
- thr_parms->tpm_state->locty_number,
- selftest_done);
+ tb->recv_data_callback(tb->tpm_state,
+ tb->tpm_state->locty_number,
+ selftest_done);
break;
case TPM_BACKEND_CMD_INIT:
case TPM_BACKEND_CMD_END:
@@ -248,15 +234,6 @@ static void tpm_passthrough_worker_thread(gpointer data,
*/
static int tpm_passthrough_startup_tpm(TPMBackend *tb)
{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
- /* terminate a running TPM */
- tpm_backend_thread_end(&tpm_pt->tbt);
-
- tpm_backend_thread_create(&tpm_pt->tbt,
- tpm_passthrough_worker_thread,
- &tpm_pt->tpm_thread_params);
-
return 0;
}
@@ -268,20 +245,11 @@ static void tpm_passthrough_reset(TPMBackend *tb)
tpm_passthrough_cancel_cmd(tb);
- tpm_backend_thread_end(&tpm_pt->tbt);
-
tpm_pt->had_startup_error = false;
}
-static int tpm_passthrough_init(TPMBackend *tb, TPMState *s,
- TPMRecvDataCB *recv_data_cb)
+static int tpm_passthrough_init(TPMBackend *tb)
{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
- tpm_pt->tpm_thread_params.tpm_state = s;
- tpm_pt->tpm_thread_params.recv_data_callback = recv_data_cb;
- tpm_pt->tpm_thread_params.tb = tb;
-
return 0;
}
@@ -315,13 +283,6 @@ static size_t tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb)
return sb->size;
}
-static void tpm_passthrough_deliver_request(TPMBackend *tb)
-{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
-
- tpm_backend_thread_deliver_request(&tpm_pt->tbt);
-}
-
static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
{
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
@@ -483,8 +444,6 @@ static void tpm_passthrough_destroy(TPMBackend *tb)
tpm_passthrough_cancel_cmd(tb);
- tpm_backend_thread_end(&tpm_pt->tbt);
-
qemu_close(tpm_pt->tpm_fd);
qemu_close(tpm_pt->cancel_fd);
@@ -520,7 +479,6 @@ static const TPMDriverOps tpm_passthrough_driver = {
.realloc_buffer = tpm_passthrough_realloc_buffer,
.reset = tpm_passthrough_reset,
.had_startup_error = tpm_passthrough_get_startup_error,
- .deliver_request = tpm_passthrough_deliver_request,
.cancel_cmd = tpm_passthrough_cancel_cmd,
.get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag,
.reset_tpm_established_flag = tpm_passthrough_reset_tpm_established_flag,
@@ -540,6 +498,7 @@ static void tpm_passthrough_class_init(ObjectClass *klass, void *data)
TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
tbc->ops = &tpm_passthrough_driver;
+ tbc->handle_request = tpm_passthrough_handle_request;
}
static const TypeInfo tpm_passthrough_info = {
diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
index e7f590d..98b6112 100644
--- a/include/sysemu/tpm_backend.h
+++ b/include/sysemu/tpm_backend.h
@@ -29,22 +29,17 @@
typedef struct TPMBackendClass TPMBackendClass;
typedef struct TPMBackend TPMBackend;
-
typedef struct TPMDriverOps TPMDriverOps;
-
-struct TPMBackendClass {
- ObjectClass parent_class;
-
- const TPMDriverOps *ops;
-
- void (*opened)(TPMBackend *s, Error **errp);
-};
+typedef void (TPMRecvDataCB)(TPMState *, uint8_t locty, bool selftest_done);
struct TPMBackend {
Object parent;
/*< protected >*/
bool opened;
+ TPMState *tpm_state;
+ GThreadPool *thread_pool;
+ TPMRecvDataCB *recv_data_callback;
char *id;
enum TpmModel fe_model;
@@ -54,8 +49,6 @@ struct TPMBackend {
QLIST_ENTRY(TPMBackend) list;
};
-typedef void (TPMRecvDataCB)(TPMState *, uint8_t locty, bool selftest_done);
-
typedef struct TPMSizedBuffer {
uint32_t size;
uint8_t *buffer;
@@ -71,7 +64,7 @@ struct TPMDriverOps {
void (*destroy)(TPMBackend *t);
/* initialize the backend */
- int (*init)(TPMBackend *t, TPMState *s, TPMRecvDataCB *datacb);
+ int (*init)(TPMBackend *t);
/* start up the TPM on the backend */
int (*startup_tpm)(TPMBackend *t);
/* returns true if nothing will ever answer TPM requests */
@@ -79,8 +72,6 @@ struct TPMDriverOps {
size_t (*realloc_buffer)(TPMSizedBuffer *sb);
- void (*deliver_request)(TPMBackend *t);
-
void (*reset)(TPMBackend *t);
void (*cancel_cmd)(TPMBackend *t);
diff --git a/include/sysemu/tpm_backend_int.h b/include/sysemu/tpm_backend_int.h
index 00639dd..9b48a35 100644
--- a/include/sysemu/tpm_backend_int.h
+++ b/include/sysemu/tpm_backend_int.h
@@ -22,15 +22,6 @@
#ifndef TPM_BACKEND_INT_H
#define TPM_BACKEND_INT_H
-typedef struct TPMBackendThread {
- GThreadPool *pool;
-} TPMBackendThread;
-
-void tpm_backend_thread_deliver_request(TPMBackendThread *tbt);
-void tpm_backend_thread_create(TPMBackendThread *tbt,
- GFunc func, gpointer user_data);
-void tpm_backend_thread_end(TPMBackendThread *tbt);
-
typedef enum TPMBackendCmd {
TPM_BACKEND_CMD_INIT = 1,
TPM_BACKEND_CMD_PROCESS_CMD,
@@ -38,4 +29,14 @@ typedef enum TPMBackendCmd {
TPM_BACKEND_CMD_TPM_RESET,
} TPMBackendCmd;
+struct TPMBackendClass {
+ ObjectClass parent_class;
+
+ const TPMDriverOps *ops;
+
+ void (*opened)(TPMBackend *s, Error **errp);
+
+ void (*handle_request)(TPMBackend *s, TPMBackendCmd cmd);
+};
+
#endif /* TPM_BACKEND_INT_H */
--
2.7.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 2/7] tpm-backend: Move thread handling inside TPMBackend
2017-03-31 13:10 ` [Qemu-devel] [PATCH 2/7] tpm-backend: Move thread handling inside TPMBackend Amarnath Valluri
@ 2017-04-04 10:56 ` Marc-André Lureau
2017-04-04 11:21 ` Amarnath Valluri
0 siblings, 1 reply; 37+ messages in thread
From: Marc-André Lureau @ 2017-04-04 10:56 UTC (permalink / raw)
To: Amarnath Valluri, qemu-devel; +Cc: patrick.ohly, stefanb
Hi
On Fri, Mar 31, 2017 at 5:04 PM Amarnath Valluri <amarnath.valluri@intel.com>
wrote:
> Move thread handling inside TPMBackend, this way backend implementations
> need
> not to maintain their own thread life cycle, instead they needs to
> implement
> 'handle_request()' class method that always been called from a thread.
>
> This change also demands to move TPMBackendClass definition to
> tpm_backend_int.h. As handle_request() method is internal to TPMBackend
> and its
> derived classes, and shall not be visible for others.
>
Alternatively, I think you could remove tpm_backend_int.h, it doesn't
bring much.
> Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
> ---
> backends/tpm.c | 66
> ++++++++++++++++++++++++++--------------
> hw/tpm/tpm_passthrough.c | 57 +++++-----------------------------
> include/sysemu/tpm_backend.h | 19 +++---------
> include/sysemu/tpm_backend_int.h | 19 ++++++------
> 4 files changed, 67 insertions(+), 94 deletions(-)
>
> diff --git a/backends/tpm.c b/backends/tpm.c
> index 536f262..50a7809 100644
> --- a/backends/tpm.c
> +++ b/backends/tpm.c
> @@ -20,6 +20,25 @@
> #include "qemu/thread.h"
> #include "sysemu/tpm_backend_int.h"
>
> +static void tpm_backend_worker_thread(gpointer data, gpointer user_data)
> +{
> + TPMBackend *s = TPM_BACKEND(user_data);
> + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
> +
> + if (k->handle_request) {
> + k->handle_request(s, (TPMBackendCmd)data);
> + }
> +}
>
Shouldn't handle_request be required by subclasses? I would have an assert()
> +
> +static void tpm_backend_thread_end(TPMBackend *s)
> +{
> + if (s->thread_pool) {
> + g_thread_pool_push(s->thread_pool, (gpointer)TPM_BACKEND_CMD_END,
> NULL);
> + g_thread_pool_free(s->thread_pool, FALSE, TRUE);
> + s->thread_pool = NULL;
> + }
> +}
> +
> enum TpmType tpm_backend_get_type(TPMBackend *s)
> {
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
> @@ -39,6 +58,8 @@ void tpm_backend_destroy(TPMBackend *s)
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
>
> k->ops->destroy(s);
> +
> + tpm_backend_thread_end(s);
> }
>
> int tpm_backend_init(TPMBackend *s, TPMState *state,
> @@ -46,13 +67,26 @@ int tpm_backend_init(TPMBackend *s, TPMState *state,
> {
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
>
> - return k->ops->init(s, state, datacb);
> + s->tpm_state = state;
> + s->recv_data_callback = datacb;
> +
> + return k->ops->init(s);
> }
>
> int tpm_backend_startup_tpm(TPMBackend *s)
> {
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
>
> + /* terminate a running TPM */
> + tpm_backend_thread_end(s);
> +
> + if (!s->thread_pool) {
>
That check seems pointless to me, after thread_end() s->thread_pool is
always NULL
+ s->thread_pool = g_thread_pool_new(tpm_backend_worker_thread, s, 1,
> + TRUE, NULL);
> + g_thread_pool_push(s->thread_pool, (gpointer)TPM_BACKEND_CMD_INIT,
> + NULL);
> + }
> +
> return k->ops->startup_tpm(s);
> }
>
> @@ -72,9 +106,8 @@ size_t tpm_backend_realloc_buffer(TPMBackend *s,
> TPMSizedBuffer *sb)
>
> void tpm_backend_deliver_request(TPMBackend *s)
> {
> - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
> -
> - k->ops->deliver_request(s);
> + g_thread_pool_push(s->thread_pool,
> (gpointer)TPM_BACKEND_CMD_PROCESS_CMD,
> + NULL);
> }
>
> void tpm_backend_reset(TPMBackend *s)
> @@ -82,6 +115,8 @@ void tpm_backend_reset(TPMBackend *s)
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
>
> k->ops->reset(s);
> +
> + tpm_backend_thread_end(s);
> }
>
> void tpm_backend_cancel_cmd(TPMBackend *s)
> @@ -156,29 +191,15 @@ static void tpm_backend_instance_init(Object *obj)
> tpm_backend_prop_get_opened,
> tpm_backend_prop_set_opened,
> NULL);
> -}
>
> -void tpm_backend_thread_deliver_request(TPMBackendThread *tbt)
> -{
> - g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_PROCESS_CMD,
> NULL);
> }
>
> -void tpm_backend_thread_create(TPMBackendThread *tbt,
> - GFunc func, gpointer user_data)
> +static void tpm_backend_instance_finalize(Object *obj)
> {
> - if (!tbt->pool) {
> - tbt->pool = g_thread_pool_new(func, user_data, 1, TRUE, NULL);
> - g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_INIT,
> NULL);
> - }
> -}
> + TPMBackend *s = TPM_BACKEND(obj);
>
> -void tpm_backend_thread_end(TPMBackendThread *tbt)
> -{
> - if (tbt->pool) {
> - g_thread_pool_push(tbt->pool, (gpointer)TPM_BACKEND_CMD_END,
> NULL);
> - g_thread_pool_free(tbt->pool, FALSE, TRUE);
> - tbt->pool = NULL;
> - }
> + g_free(s->id);
> + tpm_backend_thread_end(s);
> }
>
> static const TypeInfo tpm_backend_info = {
> @@ -186,6 +207,7 @@ static const TypeInfo tpm_backend_info = {
> .parent = TYPE_OBJECT,
> .instance_size = sizeof(TPMBackend),
> .instance_init = tpm_backend_instance_init,
> + .instance_finalize = tpm_backend_instance_finalize,
> .class_size = sizeof(TPMBackendClass),
> .abstract = true,
> };
> diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
> index a0baf5f..606e064 100644
> --- a/hw/tpm/tpm_passthrough.c
> +++ b/hw/tpm/tpm_passthrough.c
> @@ -47,20 +47,9 @@
> OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
>
> /* data structures */
> -typedef struct TPMPassthruThreadParams {
> - TPMState *tpm_state;
> -
> - TPMRecvDataCB *recv_data_callback;
> - TPMBackend *tb;
> -} TPMPassthruThreadParams;
> -
> struct TPMPassthruState {
> TPMBackend parent;
>
> - TPMBackendThread tbt;
> -
> - TPMPassthruThreadParams tpm_thread_params;
> -
> char *tpm_dev;
> int tpm_fd;
> bool tpm_executing;
> @@ -214,12 +203,9 @@ static int
> tpm_passthrough_unix_transfer(TPMPassthruState *tpm_pt,
> selftest_done);
> }
>
> -static void tpm_passthrough_worker_thread(gpointer data,
> - gpointer user_data)
> +static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd
> cmd)
> {
> - TPMPassthruThreadParams *thr_parms = user_data;
> - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(thr_parms->tb);
> - TPMBackendCmd cmd = (TPMBackendCmd)data;
> + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
> bool selftest_done = false;
>
> DPRINTF("tpm_passthrough: processing command type %d\n", cmd);
> @@ -227,12 +213,12 @@ static void tpm_passthrough_worker_thread(gpointer
> data,
> switch (cmd) {
> case TPM_BACKEND_CMD_PROCESS_CMD:
> tpm_passthrough_unix_transfer(tpm_pt,
> - thr_parms->tpm_state->locty_data,
> + tb->tpm_state->locty_data,
> &selftest_done);
>
> - thr_parms->recv_data_callback(thr_parms->tpm_state,
> - thr_parms->tpm_state->locty_number,
> - selftest_done);
> + tb->recv_data_callback(tb->tpm_state,
> + tb->tpm_state->locty_number,
> + selftest_done);
> break;
> case TPM_BACKEND_CMD_INIT:
> case TPM_BACKEND_CMD_END:
> @@ -248,15 +234,6 @@ static void tpm_passthrough_worker_thread(gpointer
> data,
> */
> static int tpm_passthrough_startup_tpm(TPMBackend *tb)
> {
> - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
> -
> - /* terminate a running TPM */
> - tpm_backend_thread_end(&tpm_pt->tbt);
> -
> - tpm_backend_thread_create(&tpm_pt->tbt,
> - tpm_passthrough_worker_thread,
> - &tpm_pt->tpm_thread_params);
> -
> return 0;
> }
>
>
I would remove startup_tpm callback (could be a seperate patch)
> @@ -268,20 +245,11 @@ static void tpm_passthrough_reset(TPMBackend *tb)
>
> tpm_passthrough_cancel_cmd(tb);
>
> - tpm_backend_thread_end(&tpm_pt->tbt);
> -
> tpm_pt->had_startup_error = false;
> }
>
> -static int tpm_passthrough_init(TPMBackend *tb, TPMState *s,
> - TPMRecvDataCB *recv_data_cb)
> +static int tpm_passthrough_init(TPMBackend *tb)
> {
> - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
> -
> - tpm_pt->tpm_thread_params.tpm_state = s;
> - tpm_pt->tpm_thread_params.recv_data_callback = recv_data_cb;
> - tpm_pt->tpm_thread_params.tb = tb;
> -
> return 0;
> }
>
> @@ -315,13 +283,6 @@ static size_t
> tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb)
> return sb->size;
> }
>
> -static void tpm_passthrough_deliver_request(TPMBackend *tb)
> -{
> - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
> -
> - tpm_backend_thread_deliver_request(&tpm_pt->tbt);
> -}
> -
> static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
> {
> TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
> @@ -483,8 +444,6 @@ static void tpm_passthrough_destroy(TPMBackend *tb)
>
> tpm_passthrough_cancel_cmd(tb);
>
> - tpm_backend_thread_end(&tpm_pt->tbt);
> -
> qemu_close(tpm_pt->tpm_fd);
> qemu_close(tpm_pt->cancel_fd);
>
> @@ -520,7 +479,6 @@ static const TPMDriverOps tpm_passthrough_driver = {
> .realloc_buffer = tpm_passthrough_realloc_buffer,
> .reset = tpm_passthrough_reset,
> .had_startup_error = tpm_passthrough_get_startup_error,
> - .deliver_request = tpm_passthrough_deliver_request,
> .cancel_cmd = tpm_passthrough_cancel_cmd,
> .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag,
> .reset_tpm_established_flag =
> tpm_passthrough_reset_tpm_established_flag,
> @@ -540,6 +498,7 @@ static void tpm_passthrough_class_init(ObjectClass
> *klass, void *data)
> TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
>
> tbc->ops = &tpm_passthrough_driver;
> + tbc->handle_request = tpm_passthrough_handle_request;
> }
>
> static const TypeInfo tpm_passthrough_info = {
> diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
> index e7f590d..98b6112 100644
> --- a/include/sysemu/tpm_backend.h
> +++ b/include/sysemu/tpm_backend.h
> @@ -29,22 +29,17 @@
>
> typedef struct TPMBackendClass TPMBackendClass;
> typedef struct TPMBackend TPMBackend;
> -
> typedef struct TPMDriverOps TPMDriverOps;
> -
> -struct TPMBackendClass {
> - ObjectClass parent_class;
> -
> - const TPMDriverOps *ops;
> -
> - void (*opened)(TPMBackend *s, Error **errp);
> -};
> +typedef void (TPMRecvDataCB)(TPMState *, uint8_t locty, bool
> selftest_done);
>
> struct TPMBackend {
> Object parent;
>
> /*< protected >*/
> bool opened;
> + TPMState *tpm_state;
> + GThreadPool *thread_pool;
> + TPMRecvDataCB *recv_data_callback;
>
> char *id;
> enum TpmModel fe_model;
> @@ -54,8 +49,6 @@ struct TPMBackend {
> QLIST_ENTRY(TPMBackend) list;
> };
>
> -typedef void (TPMRecvDataCB)(TPMState *, uint8_t locty, bool
> selftest_done);
> -
> typedef struct TPMSizedBuffer {
> uint32_t size;
> uint8_t *buffer;
> @@ -71,7 +64,7 @@ struct TPMDriverOps {
> void (*destroy)(TPMBackend *t);
>
> /* initialize the backend */
> - int (*init)(TPMBackend *t, TPMState *s, TPMRecvDataCB *datacb);
> + int (*init)(TPMBackend *t);
> /* start up the TPM on the backend */
> int (*startup_tpm)(TPMBackend *t);
> /* returns true if nothing will ever answer TPM requests */
> @@ -79,8 +72,6 @@ struct TPMDriverOps {
>
> size_t (*realloc_buffer)(TPMSizedBuffer *sb);
>
> - void (*deliver_request)(TPMBackend *t);
> -
> void (*reset)(TPMBackend *t);
>
> void (*cancel_cmd)(TPMBackend *t);
> diff --git a/include/sysemu/tpm_backend_int.h
> b/include/sysemu/tpm_backend_int.h
> index 00639dd..9b48a35 100644
> --- a/include/sysemu/tpm_backend_int.h
> +++ b/include/sysemu/tpm_backend_int.h
> @@ -22,15 +22,6 @@
> #ifndef TPM_BACKEND_INT_H
> #define TPM_BACKEND_INT_H
>
> -typedef struct TPMBackendThread {
> - GThreadPool *pool;
> -} TPMBackendThread;
> -
> -void tpm_backend_thread_deliver_request(TPMBackendThread *tbt);
> -void tpm_backend_thread_create(TPMBackendThread *tbt,
> - GFunc func, gpointer user_data);
> -void tpm_backend_thread_end(TPMBackendThread *tbt);
> -
> typedef enum TPMBackendCmd {
> TPM_BACKEND_CMD_INIT = 1,
> TPM_BACKEND_CMD_PROCESS_CMD,
> @@ -38,4 +29,14 @@ typedef enum TPMBackendCmd {
> TPM_BACKEND_CMD_TPM_RESET,
> } TPMBackendCmd;
>
> +struct TPMBackendClass {
> + ObjectClass parent_class;
> +
> + const TPMDriverOps *ops;
> +
> + void (*opened)(TPMBackend *s, Error **errp);
> +
> + void (*handle_request)(TPMBackend *s, TPMBackendCmd cmd);
> +};
> +
> #endif /* TPM_BACKEND_INT_H */
> --
> 2.7.4
>
looks good otherwise
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 2/7] tpm-backend: Move thread handling inside TPMBackend
2017-04-04 10:56 ` Marc-André Lureau
@ 2017-04-04 11:21 ` Amarnath Valluri
0 siblings, 0 replies; 37+ messages in thread
From: Amarnath Valluri @ 2017-04-04 11:21 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel; +Cc: patrick.ohly, stefanb
On 04.04.2017 13:56, Marc-André Lureau wrote:
> Hi
>
> On Fri, Mar 31, 2017 at 5:04 PM Amarnath Valluri
> <amarnath.valluri@intel.com <mailto:amarnath.valluri@intel.com>> wrote:
>
> Move thread handling inside TPMBackend, this way backend
> implementations need
> not to maintain their own thread life cycle, instead they needs to
> implement
> 'handle_request()' class method that always been called from a thread.
>
> This change also demands to move TPMBackendClass definition to
> tpm_backend_int.h. As handle_request() method is internal to
> TPMBackend and its
> derived classes, and shall not be visible for others.
>
>
> Alternatively, I think you could remove tpm_backend_int.h, it doesn't
> bring much.
Yes, initially i even thought the same. _int.h makes sense, if we could
move both TPMBackend, and TPMBackendClass _int.h, which shall be used by
TPM backend implementations. And the actual backend API is exposed by
tpm_backend.h, but the issue with QLIST member defined in TPMBackend
which is been used by
QLIST_FOREACH_SAFE in tpm.c
>
>
> Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com
> <mailto:amarnath.valluri@intel.com>>
> ---
> backends/tpm.c | 66
> ++++++++++++++++++++++++++--------------
> hw/tpm/tpm_passthrough.c | 57
> +++++-----------------------------
> include/sysemu/tpm_backend.h | 19 +++---------
> include/sysemu/tpm_backend_int.h | 19 ++++++------
> 4 files changed, 67 insertions(+), 94 deletions(-)
>
> diff --git a/backends/tpm.c b/backends/tpm.c
> index 536f262..50a7809 100644
> --- a/backends/tpm.c
> +++ b/backends/tpm.c
> @@ -20,6 +20,25 @@
> #include "qemu/thread.h"
> #include "sysemu/tpm_backend_int.h"
>
> +static void tpm_backend_worker_thread(gpointer data, gpointer
> user_data)
> +{
> + TPMBackend *s = TPM_BACKEND(user_data);
> + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
> +
> + if (k->handle_request) {
> + k->handle_request(s, (TPMBackendCmd)data);
> + }
> +}
>
>
> Shouldn't handle_request be required by subclasses? I would have an
> assert()
Yes, i agree, i will do the change
>
> +
> +static void tpm_backend_thread_end(TPMBackend *s)
> +{
> + if (s->thread_pool) {
> + g_thread_pool_push(s->thread_pool,
> (gpointer)TPM_BACKEND_CMD_END, NULL);
> + g_thread_pool_free(s->thread_pool, FALSE, TRUE);
> + s->thread_pool = NULL;
> + }
> +}
> +
> enum TpmType tpm_backend_get_type(TPMBackend *s)
> {
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
> @@ -39,6 +58,8 @@ void tpm_backend_destroy(TPMBackend *s)
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
>
> k->ops->destroy(s);
> +
> + tpm_backend_thread_end(s);
> }
>
> int tpm_backend_init(TPMBackend *s, TPMState *state,
> @@ -46,13 +67,26 @@ int tpm_backend_init(TPMBackend *s, TPMState
> *state,
> {
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
>
> - return k->ops->init(s, state, datacb);
> + s->tpm_state = state;
> + s->recv_data_callback = datacb;
> +
> + return k->ops->init(s);
> }
>
> int tpm_backend_startup_tpm(TPMBackend *s)
> {
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
>
> + /* terminate a running TPM */
> + tpm_backend_thread_end(s);
> +
> + if (!s->thread_pool) {
>
>
> That check seems pointless to me, after thread_end() s->thread_pool is
> always NULL
Ok, I will remove the check.
>
> + s->thread_pool =
> g_thread_pool_new(tpm_backend_worker_thread, s, 1,
> + TRUE, NULL);
> + g_thread_pool_push(s->thread_pool,
> (gpointer)TPM_BACKEND_CMD_INIT,
> + NULL);
> + }
> +
> return k->ops->startup_tpm(s);
> }
>
> @@ -72,9 +106,8 @@ size_t tpm_backend_realloc_buffer(TPMBackend
> *s, TPMSizedBuffer *sb)
>
> void tpm_backend_deliver_request(TPMBackend *s)
> {
> - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
> -
> - k->ops->deliver_request(s);
> + g_thread_pool_push(s->thread_pool,
> (gpointer)TPM_BACKEND_CMD_PROCESS_CMD,
> + NULL);
> }
>
> void tpm_backend_reset(TPMBackend *s)
> @@ -82,6 +115,8 @@ void tpm_backend_reset(TPMBackend *s)
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
>
> k->ops->reset(s);
> +
> + tpm_backend_thread_end(s);
> }
>
> void tpm_backend_cancel_cmd(TPMBackend *s)
> @@ -156,29 +191,15 @@ static void tpm_backend_instance_init(Object
> *obj)
> tpm_backend_prop_get_opened,
> tpm_backend_prop_set_opened,
> NULL);
> -}
>
> -void tpm_backend_thread_deliver_request(TPMBackendThread *tbt)
> -{
> - g_thread_pool_push(tbt->pool,
> (gpointer)TPM_BACKEND_CMD_PROCESS_CMD, NULL);
> }
>
> -void tpm_backend_thread_create(TPMBackendThread *tbt,
> - GFunc func, gpointer user_data)
> +static void tpm_backend_instance_finalize(Object *obj)
> {
> - if (!tbt->pool) {
> - tbt->pool = g_thread_pool_new(func, user_data, 1, TRUE,
> NULL);
> - g_thread_pool_push(tbt->pool,
> (gpointer)TPM_BACKEND_CMD_INIT, NULL);
> - }
> -}
> + TPMBackend *s = TPM_BACKEND(obj);
>
> -void tpm_backend_thread_end(TPMBackendThread *tbt)
> -{
> - if (tbt->pool) {
> - g_thread_pool_push(tbt->pool,
> (gpointer)TPM_BACKEND_CMD_END, NULL);
> - g_thread_pool_free(tbt->pool, FALSE, TRUE);
> - tbt->pool = NULL;
> - }
> + g_free(s->id);
> + tpm_backend_thread_end(s);
> }
>
> static const TypeInfo tpm_backend_info = {
> @@ -186,6 +207,7 @@ static const TypeInfo tpm_backend_info = {
> .parent = TYPE_OBJECT,
> .instance_size = sizeof(TPMBackend),
> .instance_init = tpm_backend_instance_init,
> + .instance_finalize = tpm_backend_instance_finalize,
> .class_size = sizeof(TPMBackendClass),
> .abstract = true,
> };
> diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
> index a0baf5f..606e064 100644
> --- a/hw/tpm/tpm_passthrough.c
> +++ b/hw/tpm/tpm_passthrough.c
> @@ -47,20 +47,9 @@
> OBJECT_CHECK(TPMPassthruState, (obj), TYPE_TPM_PASSTHROUGH)
>
> /* data structures */
> -typedef struct TPMPassthruThreadParams {
> - TPMState *tpm_state;
> -
> - TPMRecvDataCB *recv_data_callback;
> - TPMBackend *tb;
> -} TPMPassthruThreadParams;
> -
> struct TPMPassthruState {
> TPMBackend parent;
>
> - TPMBackendThread tbt;
> -
> - TPMPassthruThreadParams tpm_thread_params;
> -
> char *tpm_dev;
> int tpm_fd;
> bool tpm_executing;
> @@ -214,12 +203,9 @@ static int
> tpm_passthrough_unix_transfer(TPMPassthruState *tpm_pt,
> selftest_done);
> }
>
> -static void tpm_passthrough_worker_thread(gpointer data,
> - gpointer user_data)
> +static void tpm_passthrough_handle_request(TPMBackend *tb,
> TPMBackendCmd cmd)
> {
> - TPMPassthruThreadParams *thr_parms = user_data;
> - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(thr_parms->tb);
> - TPMBackendCmd cmd = (TPMBackendCmd)data;
> + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
> bool selftest_done = false;
>
> DPRINTF("tpm_passthrough: processing command type %d\n", cmd);
> @@ -227,12 +213,12 @@ static void
> tpm_passthrough_worker_thread(gpointer data,
> switch (cmd) {
> case TPM_BACKEND_CMD_PROCESS_CMD:
> tpm_passthrough_unix_transfer(tpm_pt,
> - thr_parms->tpm_state->locty_data,
> + tb->tpm_state->locty_data,
> &selftest_done);
>
> - thr_parms->recv_data_callback(thr_parms->tpm_state,
> - thr_parms->tpm_state->locty_number,
> - selftest_done);
> + tb->recv_data_callback(tb->tpm_state,
> + tb->tpm_state->locty_number,
> + selftest_done);
> break;
> case TPM_BACKEND_CMD_INIT:
> case TPM_BACKEND_CMD_END:
> @@ -248,15 +234,6 @@ static void
> tpm_passthrough_worker_thread(gpointer data,
> */
> static int tpm_passthrough_startup_tpm(TPMBackend *tb)
> {
> - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
> -
> - /* terminate a running TPM */
> - tpm_backend_thread_end(&tpm_pt->tbt);
> -
> - tpm_backend_thread_create(&tpm_pt->tbt,
> - tpm_passthrough_worker_thread,
> - &tpm_pt->tpm_thread_params);
> -
> return 0;
> }
>
>
> I would remove startup_tpm callback (could be a seperate patch)
Do you mean, remove the method from TPMDriverOps interface itself, of
just the empty method here. The empty method is removed in 4/7 where we
made them optional methods.
>
> @@ -268,20 +245,11 @@ static void tpm_passthrough_reset(TPMBackend
> *tb)
>
> tpm_passthrough_cancel_cmd(tb);
>
> - tpm_backend_thread_end(&tpm_pt->tbt);
> -
> tpm_pt->had_startup_error = false;
> }
>
> -static int tpm_passthrough_init(TPMBackend *tb, TPMState *s,
> - TPMRecvDataCB *recv_data_cb)
> +static int tpm_passthrough_init(TPMBackend *tb)
> {
> - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
> -
> - tpm_pt->tpm_thread_params.tpm_state = s;
> - tpm_pt->tpm_thread_params.recv_data_callback = recv_data_cb;
> - tpm_pt->tpm_thread_params.tb = tb;
> -
> return 0;
> }
>
> @@ -315,13 +283,6 @@ static size_t
> tpm_passthrough_realloc_buffer(TPMSizedBuffer *sb)
> return sb->size;
> }
>
> -static void tpm_passthrough_deliver_request(TPMBackend *tb)
> -{
> - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
> -
> - tpm_backend_thread_deliver_request(&tpm_pt->tbt);
> -}
> -
> static void tpm_passthrough_cancel_cmd(TPMBackend *tb)
> {
> TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
> @@ -483,8 +444,6 @@ static void tpm_passthrough_destroy(TPMBackend
> *tb)
>
> tpm_passthrough_cancel_cmd(tb);
>
> - tpm_backend_thread_end(&tpm_pt->tbt);
> -
> qemu_close(tpm_pt->tpm_fd);
> qemu_close(tpm_pt->cancel_fd);
>
> @@ -520,7 +479,6 @@ static const TPMDriverOps
> tpm_passthrough_driver = {
> .realloc_buffer = tpm_passthrough_realloc_buffer,
> .reset = tpm_passthrough_reset,
> .had_startup_error = tpm_passthrough_get_startup_error,
> - .deliver_request = tpm_passthrough_deliver_request,
> .cancel_cmd = tpm_passthrough_cancel_cmd,
> .get_tpm_established_flag =
> tpm_passthrough_get_tpm_established_flag,
> .reset_tpm_established_flag =
> tpm_passthrough_reset_tpm_established_flag,
> @@ -540,6 +498,7 @@ static void
> tpm_passthrough_class_init(ObjectClass *klass, void *data)
> TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
>
> tbc->ops = &tpm_passthrough_driver;
> + tbc->handle_request = tpm_passthrough_handle_request;
> }
>
> static const TypeInfo tpm_passthrough_info = {
> diff --git a/include/sysemu/tpm_backend.h
> b/include/sysemu/tpm_backend.h
> index e7f590d..98b6112 100644
> --- a/include/sysemu/tpm_backend.h
> +++ b/include/sysemu/tpm_backend.h
> @@ -29,22 +29,17 @@
>
> typedef struct TPMBackendClass TPMBackendClass;
> typedef struct TPMBackend TPMBackend;
> -
> typedef struct TPMDriverOps TPMDriverOps;
> -
> -struct TPMBackendClass {
> - ObjectClass parent_class;
> -
> - const TPMDriverOps *ops;
> -
> - void (*opened)(TPMBackend *s, Error **errp);
> -};
> +typedef void (TPMRecvDataCB)(TPMState *, uint8_t locty, bool
> selftest_done);
>
> struct TPMBackend {
> Object parent;
>
> /*< protected >*/
> bool opened;
> + TPMState *tpm_state;
> + GThreadPool *thread_pool;
> + TPMRecvDataCB *recv_data_callback;
>
> char *id;
> enum TpmModel fe_model;
> @@ -54,8 +49,6 @@ struct TPMBackend {
> QLIST_ENTRY(TPMBackend) list;
> };
>
> -typedef void (TPMRecvDataCB)(TPMState *, uint8_t locty, bool
> selftest_done);
> -
> typedef struct TPMSizedBuffer {
> uint32_t size;
> uint8_t *buffer;
> @@ -71,7 +64,7 @@ struct TPMDriverOps {
> void (*destroy)(TPMBackend *t);
>
> /* initialize the backend */
> - int (*init)(TPMBackend *t, TPMState *s, TPMRecvDataCB *datacb);
> + int (*init)(TPMBackend *t);
> /* start up the TPM on the backend */
> int (*startup_tpm)(TPMBackend *t);
> /* returns true if nothing will ever answer TPM requests */
> @@ -79,8 +72,6 @@ struct TPMDriverOps {
>
> size_t (*realloc_buffer)(TPMSizedBuffer *sb);
>
> - void (*deliver_request)(TPMBackend *t);
> -
> void (*reset)(TPMBackend *t);
>
> void (*cancel_cmd)(TPMBackend *t);
> diff --git a/include/sysemu/tpm_backend_int.h
> b/include/sysemu/tpm_backend_int.h
> index 00639dd..9b48a35 100644
> --- a/include/sysemu/tpm_backend_int.h
> +++ b/include/sysemu/tpm_backend_int.h
> @@ -22,15 +22,6 @@
> #ifndef TPM_BACKEND_INT_H
> #define TPM_BACKEND_INT_H
>
> -typedef struct TPMBackendThread {
> - GThreadPool *pool;
> -} TPMBackendThread;
> -
> -void tpm_backend_thread_deliver_request(TPMBackendThread *tbt);
> -void tpm_backend_thread_create(TPMBackendThread *tbt,
> - GFunc func, gpointer user_data);
> -void tpm_backend_thread_end(TPMBackendThread *tbt);
> -
> typedef enum TPMBackendCmd {
> TPM_BACKEND_CMD_INIT = 1,
> TPM_BACKEND_CMD_PROCESS_CMD,
> @@ -38,4 +29,14 @@ typedef enum TPMBackendCmd {
> TPM_BACKEND_CMD_TPM_RESET,
> } TPMBackendCmd;
>
> +struct TPMBackendClass {
> + ObjectClass parent_class;
> +
> + const TPMDriverOps *ops;
> +
> + void (*opened)(TPMBackend *s, Error **errp);
> +
> + void (*handle_request)(TPMBackend *s, TPMBackendCmd cmd);
> +};
> +
> #endif /* TPM_BACKEND_INT_H */
> --
> 2.7.4
>
>
> looks good otherwise
> --
> Marc-André Lureau
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH 3/7] tpm-backend: Initialize and free data members in it's own methods
2017-03-31 13:10 [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator Amarnath Valluri
2017-03-31 13:10 ` [Qemu-devel] [PATCH 1/7] tpm-backend: Remove unneeded member variable from backend class Amarnath Valluri
2017-03-31 13:10 ` [Qemu-devel] [PATCH 2/7] tpm-backend: Move thread handling inside TPMBackend Amarnath Valluri
@ 2017-03-31 13:10 ` Amarnath Valluri
2017-04-04 12:57 ` Marc-André Lureau
2017-03-31 13:10 ` [Qemu-devel] [PATCH 4/7] tpm-backend: Call interface methods only if backend implements them Amarnath Valluri
` (6 subsequent siblings)
9 siblings, 1 reply; 37+ messages in thread
From: Amarnath Valluri @ 2017-03-31 13:10 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanb, patrick.ohly, Amarnath Valluri
Initialize and free TPMBackend data members in it's own instance_init() and
instance_finalize methods.
Took the opportunity to fix object cleanup in tpm_backend_destroy() method
Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
---
backends/tpm.c | 14 +++++++++++++-
hw/tpm/tpm_passthrough.c | 8 +-------
2 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/backends/tpm.c b/backends/tpm.c
index 50a7809..00c82d7 100644
--- a/backends/tpm.c
+++ b/backends/tpm.c
@@ -59,7 +59,7 @@ void tpm_backend_destroy(TPMBackend *s)
k->ops->destroy(s);
- tpm_backend_thread_end(s);
+ object_unref(OBJECT(s));
}
int tpm_backend_init(TPMBackend *s, TPMState *state,
@@ -187,10 +187,20 @@ static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp)
static void tpm_backend_instance_init(Object *obj)
{
+ TPMBackend *s = TPM_BACKEND(obj);
+
object_property_add_bool(obj, "opened",
tpm_backend_prop_get_opened,
tpm_backend_prop_set_opened,
NULL);
+ s->id = NULL;
+ s->fe_model = -1;
+ s->opened = false;
+ s->tpm_state = NULL;
+ s->thread_pool = NULL;
+ s->recv_data_callback = NULL;
+ s->path = NULL;
+ s->cancel_path = NULL;
}
@@ -199,6 +209,8 @@ static void tpm_backend_instance_finalize(Object *obj)
TPMBackend *s = TPM_BACKEND(obj);
g_free(s->id);
+ g_free(s->path);
+ g_free(s->cancel_path);
tpm_backend_thread_end(s);
}
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index 606e064..cb63079 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -418,8 +418,6 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
tb->id = g_strdup(id);
- /* let frontend set the fe_model to proper value */
- tb->fe_model = -1;
if (tpm_passthrough_handle_device_opts(opts, tb)) {
goto err_exit;
@@ -433,7 +431,7 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
return tb;
err_exit:
- g_free(tb->id);
+ object_unref(obj);
return NULL;
}
@@ -446,10 +444,6 @@ static void tpm_passthrough_destroy(TPMBackend *tb)
qemu_close(tpm_pt->tpm_fd);
qemu_close(tpm_pt->cancel_fd);
-
- g_free(tb->id);
- g_free(tb->path);
- g_free(tb->cancel_path);
g_free(tpm_pt->tpm_dev);
}
--
2.7.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 3/7] tpm-backend: Initialize and free data members in it's own methods
2017-03-31 13:10 ` [Qemu-devel] [PATCH 3/7] tpm-backend: Initialize and free data members in it's own methods Amarnath Valluri
@ 2017-04-04 12:57 ` Marc-André Lureau
0 siblings, 0 replies; 37+ messages in thread
From: Marc-André Lureau @ 2017-04-04 12:57 UTC (permalink / raw)
To: Amarnath Valluri, qemu-devel; +Cc: patrick.ohly, stefanb
Hi
On Fri, Mar 31, 2017 at 5:01 PM Amarnath Valluri <amarnath.valluri@intel.com>
wrote:
> Initialize and free TPMBackend data members in it's own instance_init() and
> instance_finalize methods.
>
> Took the opportunity to fix object cleanup in tpm_backend_destroy() method
>
> Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
> ---
> backends/tpm.c | 14 +++++++++++++-
> hw/tpm/tpm_passthrough.c | 8 +-------
> 2 files changed, 14 insertions(+), 8 deletions(-)
>
> diff --git a/backends/tpm.c b/backends/tpm.c
> index 50a7809..00c82d7 100644
> --- a/backends/tpm.c
> +++ b/backends/tpm.c
> @@ -59,7 +59,7 @@ void tpm_backend_destroy(TPMBackend *s)
>
> k->ops->destroy(s);
>
> - tpm_backend_thread_end(s);
> + object_unref(OBJECT(s));
> }
>
tpm_backend_destroy() wrapping object_unref().. I think we could do it the
correct way instead, caller use object_unref() and implementation can use
finalizers.
>
> int tpm_backend_init(TPMBackend *s, TPMState *state,
> @@ -187,10 +187,20 @@ static void tpm_backend_prop_set_opened(Object *obj,
> bool value, Error **errp)
>
> static void tpm_backend_instance_init(Object *obj)
> {
> + TPMBackend *s = TPM_BACKEND(obj);
> +
> object_property_add_bool(obj, "opened",
> tpm_backend_prop_get_opened,
> tpm_backend_prop_set_opened,
> NULL);
> + s->id = NULL;
> + s->fe_model = -1;
> + s->opened = false;
> + s->tpm_state = NULL;
> + s->thread_pool = NULL;
> + s->recv_data_callback = NULL;
> + s->path = NULL;
> + s->cancel_path = NULL;
>
I don't see much point in initializing again those fields to 0, since
object creation do it already.
>
> }
>
> @@ -199,6 +209,8 @@ static void tpm_backend_instance_finalize(Object *obj)
> TPMBackend *s = TPM_BACKEND(obj);
>
> g_free(s->id);
> + g_free(s->path);
> + g_free(s->cancel_path);
> tpm_backend_thread_end(s);
> }
>
> diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
> index 606e064..cb63079 100644
> --- a/hw/tpm/tpm_passthrough.c
> +++ b/hw/tpm/tpm_passthrough.c
> @@ -418,8 +418,6 @@ static TPMBackend *tpm_passthrough_create(QemuOpts
> *opts, const char *id)
> TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
>
> tb->id = g_strdup(id);
> - /* let frontend set the fe_model to proper value */
> - tb->fe_model = -1;
>
> if (tpm_passthrough_handle_device_opts(opts, tb)) {
> goto err_exit;
> @@ -433,7 +431,7 @@ static TPMBackend *tpm_passthrough_create(QemuOpts
> *opts, const char *id)
> return tb;
>
> err_exit:
> - g_free(tb->id);
> + object_unref(obj);
>
ok, that's a leak fix
>
> return NULL;
> }
> @@ -446,10 +444,6 @@ static void tpm_passthrough_destroy(TPMBackend *tb)
>
> qemu_close(tpm_pt->tpm_fd);
> qemu_close(tpm_pt->cancel_fd);
> -
> - g_free(tb->id);
> - g_free(tb->path);
> - g_free(tb->cancel_path);
> g_free(tpm_pt->tpm_dev);
> }
>
> --
> 2.7.4
>
>
> --
Marc-André Lureau
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH 4/7] tpm-backend: Call interface methods only if backend implements them
2017-03-31 13:10 [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator Amarnath Valluri
` (2 preceding siblings ...)
2017-03-31 13:10 ` [Qemu-devel] [PATCH 3/7] tpm-backend: Initialize and free data members in it's own methods Amarnath Valluri
@ 2017-03-31 13:10 ` Amarnath Valluri
2017-04-04 13:15 ` Marc-André Lureau
2017-03-31 13:10 ` [Qemu-devel] [PATCH 5/7] tmp backend: Add new api to read backend tpm options Amarnath Valluri
` (5 subsequent siblings)
9 siblings, 1 reply; 37+ messages in thread
From: Amarnath Valluri @ 2017-03-31 13:10 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanb, patrick.ohly, Amarnath Valluri
This allows backend implementations left optional interface methods.
Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
---
backends/tpm.c | 22 ++++++++++++++--------
hw/tpm/tpm_passthrough.c | 16 ----------------
2 files changed, 14 insertions(+), 24 deletions(-)
diff --git a/backends/tpm.c b/backends/tpm.c
index 00c82d7..0bdc5af 100644
--- a/backends/tpm.c
+++ b/backends/tpm.c
@@ -50,14 +50,16 @@ const char *tpm_backend_get_desc(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
- return k->ops->desc();
+ return k->ops->desc ? k->ops->desc() : "";
}
void tpm_backend_destroy(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
- k->ops->destroy(s);
+ if (k->ops->destroy) {
+ k->ops->destroy(s);
+ }
object_unref(OBJECT(s));
}
@@ -70,7 +72,7 @@ int tpm_backend_init(TPMBackend *s, TPMState *state,
s->tpm_state = state;
s->recv_data_callback = datacb;
- return k->ops->init(s);
+ return k->ops->init ? k->ops->init(s) : 0;
}
int tpm_backend_startup_tpm(TPMBackend *s)
@@ -87,21 +89,21 @@ int tpm_backend_startup_tpm(TPMBackend *s)
NULL);
}
- return k->ops->startup_tpm(s);
+ return k->ops->startup_tpm ? k->ops->startup_tpm(s) : 0;
}
bool tpm_backend_had_startup_error(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
- return k->ops->had_startup_error(s);
+ return k->ops->had_startup_error ? k->ops->had_startup_error(s) : 0;
}
size_t tpm_backend_realloc_buffer(TPMBackend *s, TPMSizedBuffer *sb)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
- return k->ops->realloc_buffer(sb);
+ return k->ops->realloc_buffer ? k->ops->realloc_buffer(sb) : (size_t)0;
}
void tpm_backend_deliver_request(TPMBackend *s)
@@ -114,7 +116,9 @@ void tpm_backend_reset(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
- k->ops->reset(s);
+ if (k->ops->reset) {
+ k->ops->reset(s);
+ }
tpm_backend_thread_end(s);
}
@@ -123,7 +127,9 @@ void tpm_backend_cancel_cmd(TPMBackend *s)
{
TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
- k->ops->cancel_cmd(s);
+ if (k->ops->cancel_cmd) {
+ k->ops->cancel_cmd(s);
+ }
}
bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index cb63079..5b3bf1c 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -228,15 +228,6 @@ static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd cmd)
}
}
-/*
- * Start the TPM (thread). If it had been started before, then terminate
- * and start it again.
- */
-static int tpm_passthrough_startup_tpm(TPMBackend *tb)
-{
- return 0;
-}
-
static void tpm_passthrough_reset(TPMBackend *tb)
{
TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
@@ -248,11 +239,6 @@ static void tpm_passthrough_reset(TPMBackend *tb)
tpm_pt->had_startup_error = false;
}
-static int tpm_passthrough_init(TPMBackend *tb)
-{
- return 0;
-}
-
static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
{
return false;
@@ -468,8 +454,6 @@ static const TPMDriverOps tpm_passthrough_driver = {
.desc = tpm_passthrough_create_desc,
.create = tpm_passthrough_create,
.destroy = tpm_passthrough_destroy,
- .init = tpm_passthrough_init,
- .startup_tpm = tpm_passthrough_startup_tpm,
.realloc_buffer = tpm_passthrough_realloc_buffer,
.reset = tpm_passthrough_reset,
.had_startup_error = tpm_passthrough_get_startup_error,
--
2.7.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 4/7] tpm-backend: Call interface methods only if backend implements them
2017-03-31 13:10 ` [Qemu-devel] [PATCH 4/7] tpm-backend: Call interface methods only if backend implements them Amarnath Valluri
@ 2017-04-04 13:15 ` Marc-André Lureau
0 siblings, 0 replies; 37+ messages in thread
From: Marc-André Lureau @ 2017-04-04 13:15 UTC (permalink / raw)
To: Amarnath Valluri, qemu-devel; +Cc: patrick.ohly, stefanb
Hi
On Fri, Mar 31, 2017 at 4:57 PM Amarnath Valluri <amarnath.valluri@intel.com>
wrote:
> This allows backend implementations left optional interface methods.
>
>
Does that make sense to make them optional? instead I would add asserts.
Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
> ---
> backends/tpm.c | 22 ++++++++++++++--------
> hw/tpm/tpm_passthrough.c | 16 ----------------
> 2 files changed, 14 insertions(+), 24 deletions(-)
>
> diff --git a/backends/tpm.c b/backends/tpm.c
> index 00c82d7..0bdc5af 100644
> --- a/backends/tpm.c
> +++ b/backends/tpm.c
> @@ -50,14 +50,16 @@ const char *tpm_backend_get_desc(TPMBackend *s)
> {
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
>
> - return k->ops->desc();
> + return k->ops->desc ? k->ops->desc() : "";
> }
>
> void tpm_backend_destroy(TPMBackend *s)
> {
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
>
> - k->ops->destroy(s);
> + if (k->ops->destroy) {
> + k->ops->destroy(s);
> + }
>
> object_unref(OBJECT(s));
> }
> @@ -70,7 +72,7 @@ int tpm_backend_init(TPMBackend *s, TPMState *state,
> s->tpm_state = state;
> s->recv_data_callback = datacb;
>
> - return k->ops->init(s);
> + return k->ops->init ? k->ops->init(s) : 0;
> }
>
> int tpm_backend_startup_tpm(TPMBackend *s)
> @@ -87,21 +89,21 @@ int tpm_backend_startup_tpm(TPMBackend *s)
> NULL);
> }
>
> - return k->ops->startup_tpm(s);
> + return k->ops->startup_tpm ? k->ops->startup_tpm(s) : 0;
> }
>
> bool tpm_backend_had_startup_error(TPMBackend *s)
> {
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
>
> - return k->ops->had_startup_error(s);
> + return k->ops->had_startup_error ? k->ops->had_startup_error(s) : 0;
> }
>
> size_t tpm_backend_realloc_buffer(TPMBackend *s, TPMSizedBuffer *sb)
> {
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
>
> - return k->ops->realloc_buffer(sb);
> + return k->ops->realloc_buffer ? k->ops->realloc_buffer(sb) :
> (size_t)0;
> }
>
> void tpm_backend_deliver_request(TPMBackend *s)
> @@ -114,7 +116,9 @@ void tpm_backend_reset(TPMBackend *s)
> {
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
>
> - k->ops->reset(s);
> + if (k->ops->reset) {
> + k->ops->reset(s);
> + }
>
> tpm_backend_thread_end(s);
> }
> @@ -123,7 +127,9 @@ void tpm_backend_cancel_cmd(TPMBackend *s)
> {
> TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
>
> - k->ops->cancel_cmd(s);
> + if (k->ops->cancel_cmd) {
> + k->ops->cancel_cmd(s);
> + }
> }
>
> bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
> diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
> index cb63079..5b3bf1c 100644
> --- a/hw/tpm/tpm_passthrough.c
> +++ b/hw/tpm/tpm_passthrough.c
> @@ -228,15 +228,6 @@ static void tpm_passthrough_handle_request(TPMBackend
> *tb, TPMBackendCmd cmd)
> }
> }
>
> -/*
> - * Start the TPM (thread). If it had been started before, then terminate
> - * and start it again.
> - */
> -static int tpm_passthrough_startup_tpm(TPMBackend *tb)
> -{
> - return 0;
> -}
> -
> static void tpm_passthrough_reset(TPMBackend *tb)
> {
> TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
> @@ -248,11 +239,6 @@ static void tpm_passthrough_reset(TPMBackend *tb)
> tpm_pt->had_startup_error = false;
> }
>
> -static int tpm_passthrough_init(TPMBackend *tb)
> -{
> - return 0;
> -}
> -
>
These two hunks could be squashed in earlier patch
> static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
> {
> return false;
> @@ -468,8 +454,6 @@ static const TPMDriverOps tpm_passthrough_driver = {
> .desc = tpm_passthrough_create_desc,
> .create = tpm_passthrough_create,
> .destroy = tpm_passthrough_destroy,
> - .init = tpm_passthrough_init,
> - .startup_tpm = tpm_passthrough_startup_tpm,
> .realloc_buffer = tpm_passthrough_realloc_buffer,
> .reset = tpm_passthrough_reset,
> .had_startup_error = tpm_passthrough_get_startup_error,
> --
> 2.7.4
>
>
> --
Marc-André Lureau
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH 5/7] tmp backend: Add new api to read backend tpm options
2017-03-31 13:10 [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator Amarnath Valluri
` (3 preceding siblings ...)
2017-03-31 13:10 ` [Qemu-devel] [PATCH 4/7] tpm-backend: Call interface methods only if backend implements them Amarnath Valluri
@ 2017-03-31 13:10 ` Amarnath Valluri
2017-04-03 19:24 ` Eric Blake
2017-03-31 13:10 ` [Qemu-devel] [PATCH 6/7] tpm-passthrough: move reusable code to utils Amarnath Valluri
` (4 subsequent siblings)
9 siblings, 1 reply; 37+ messages in thread
From: Amarnath Valluri @ 2017-03-31 13:10 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanb, patrick.ohly, Amarnath Valluri
TPM configuration options are backend implementation details and shall not be
part of base TPMBackend object, and these shall not be accessed directly outside
of the class, hence added a new tpm backend api, tpm_backend_get_tpm_options()
to read the backend configured options.
Added new method, get_tpm_options() to TPMDriverOps., which shall be implemented
by the derived classes to return configured tpm options.
Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
---
backends/tpm.c | 12 ++++++----
hw/tpm/tpm_passthrough.c | 55 +++++++++++++++++++++++++++++++++++---------
include/sysemu/tpm_backend.h | 15 ++++++++++--
qapi-schema.json | 12 ++++++++--
tpm.c | 13 ++---------
5 files changed, 76 insertions(+), 31 deletions(-)
diff --git a/backends/tpm.c b/backends/tpm.c
index 0bdc5af..98aafd8 100644
--- a/backends/tpm.c
+++ b/backends/tpm.c
@@ -153,6 +153,13 @@ TPMVersion tpm_backend_get_tpm_version(TPMBackend *s)
return k->ops->get_tpm_version(s);
}
+TPMOptions *tpm_backend_get_tpm_options(TPMBackend *s)
+{
+ TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+ return k->ops->get_tpm_options ? k->ops->get_tpm_options(s) : NULL;
+}
+
static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
{
TPMBackend *s = TPM_BACKEND(obj);
@@ -205,9 +212,6 @@ static void tpm_backend_instance_init(Object *obj)
s->tpm_state = NULL;
s->thread_pool = NULL;
s->recv_data_callback = NULL;
- s->path = NULL;
- s->cancel_path = NULL;
-
}
static void tpm_backend_instance_finalize(Object *obj)
@@ -215,8 +219,6 @@ static void tpm_backend_instance_finalize(Object *obj)
TPMBackend *s = TPM_BACKEND(obj);
g_free(s->id);
- g_free(s->path);
- g_free(s->cancel_path);
tpm_backend_thread_end(s);
}
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index 5b3bf1c..fce1163 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -50,6 +50,7 @@
struct TPMPassthruState {
TPMBackend parent;
+ TPMPassthroughOptions ops;
char *tpm_dev;
int tpm_fd;
bool tpm_executing;
@@ -314,15 +315,14 @@ static TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
* in Documentation/ABI/stable/sysfs-class-tpm.
* From /dev/tpm0 create /sys/class/misc/tpm0/device/cancel
*/
-static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb)
+static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt)
{
- TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
int fd = -1;
char *dev;
char path[PATH_MAX];
- if (tb->cancel_path) {
- fd = qemu_open(tb->cancel_path, O_WRONLY);
+ if (tpm_pt->ops.cancel_path) {
+ fd = qemu_open(tpm_pt->ops.cancel_path, O_WRONLY);
if (fd < 0) {
error_report("Could not open TPM cancel path : %s",
strerror(errno));
@@ -337,7 +337,7 @@ static int tpm_passthrough_open_sysfs_cancel(TPMBackend *tb)
dev) < sizeof(path)) {
fd = qemu_open(path, O_WRONLY);
if (fd >= 0) {
- tb->cancel_path = g_strdup(path);
+ tpm_pt->ops.cancel_path = g_strdup(path);
} else {
error_report("tpm_passthrough: Could not open TPM cancel "
"path %s : %s", path, strerror(errno));
@@ -357,17 +357,24 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
const char *value;
value = qemu_opt_get(opts, "cancel-path");
- tb->cancel_path = g_strdup(value);
+ if (value) {
+ tpm_pt->ops.cancel_path = g_strdup(value);
+ tpm_pt->ops.has_cancel_path = true;
+ } else {
+ tpm_pt->ops.has_cancel_path = false;
+ }
value = qemu_opt_get(opts, "path");
if (!value) {
value = TPM_PASSTHROUGH_DEFAULT_DEVICE;
+ tpm_pt->ops.has_path = false;
+ } else {
+ tpm_pt->ops.has_path = true;
}
+ tpm_pt->ops.path = g_strdup(value);
tpm_pt->tpm_dev = g_strdup(value);
- tb->path = g_strdup(tpm_pt->tpm_dev);
-
tpm_pt->tpm_fd = qemu_open(tpm_pt->tpm_dev, O_RDWR);
if (tpm_pt->tpm_fd < 0) {
error_report("Cannot access TPM device using '%s': %s",
@@ -388,8 +395,8 @@ static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb)
tpm_pt->tpm_fd = -1;
err_free_parameters:
- g_free(tb->path);
- tb->path = NULL;
+ g_free(tpm_pt->ops.path);
+ tpm_pt->ops.path = NULL;
g_free(tpm_pt->tpm_dev);
tpm_pt->tpm_dev = NULL;
@@ -409,7 +416,7 @@ static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id)
goto err_exit;
}
- tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tb);
+ tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt);
if (tpm_pt->cancel_fd < 0) {
goto err_exit;
}
@@ -430,9 +437,34 @@ static void tpm_passthrough_destroy(TPMBackend *tb)
qemu_close(tpm_pt->tpm_fd);
qemu_close(tpm_pt->cancel_fd);
+
+ g_free(tpm_pt->ops.path);
+ g_free(tpm_pt->ops.cancel_path);
g_free(tpm_pt->tpm_dev);
}
+static TPMOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb)
+{
+ TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
+ TPMPassthroughOptions *ops = g_new0(TPMPassthroughOptions, 1);
+
+ if (!ops) {
+ return NULL;
+ }
+
+ if (tpm_pt->ops.has_path) {
+ ops->has_path = true;
+ ops->path = g_strdup(tpm_pt->ops.path);
+ }
+
+ if (tpm_pt->ops.has_cancel_path) {
+ ops->has_cancel_path = true;
+ ops->cancel_path = g_strdup(tpm_pt->ops.cancel_path);
+ }
+
+ return (TPMOptions *)ops;
+}
+
static const QemuOptDesc tpm_passthrough_cmdline_opts[] = {
TPM_STANDARD_CMDLINE_OPTS,
{
@@ -461,6 +493,7 @@ static const TPMDriverOps tpm_passthrough_driver = {
.get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag,
.reset_tpm_established_flag = tpm_passthrough_reset_tpm_established_flag,
.get_tpm_version = tpm_passthrough_get_tpm_version,
+ .get_tpm_options = tpm_passthrough_get_tpm_options,
};
static void tpm_passthrough_inst_init(Object *obj)
diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
index 98b6112..82348a3 100644
--- a/include/sysemu/tpm_backend.h
+++ b/include/sysemu/tpm_backend.h
@@ -41,10 +41,9 @@ struct TPMBackend {
GThreadPool *thread_pool;
TPMRecvDataCB *recv_data_callback;
+ /* <public> */
char *id;
enum TpmModel fe_model;
- char *path;
- char *cancel_path;
QLIST_ENTRY(TPMBackend) list;
};
@@ -81,6 +80,8 @@ struct TPMDriverOps {
int (*reset_tpm_established_flag)(TPMBackend *t, uint8_t locty);
TPMVersion (*get_tpm_version)(TPMBackend *t);
+
+ TPMOptions* (*get_tpm_options)(TPMBackend *t);
};
@@ -213,6 +214,16 @@ void tpm_backend_open(TPMBackend *s, Error **errp);
*/
TPMVersion tpm_backend_get_tpm_version(TPMBackend *s);
+/**
+ * tpm_backend_get_tpm_options:
+ * @s: the backend
+ *
+ * Get the backend configuration options
+ *
+ * Returns newly allocated TPMOptions
+ */
+TPMOptions *tpm_backend_get_tpm_options(TPMBackend *s);
+
TPMBackend *qemu_find_tpm(const char *id);
const TPMDriverOps *tpm_get_backend_driver(const char *type);
diff --git a/qapi-schema.json b/qapi-schema.json
index b921994..5faf1ac 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -5140,6 +5140,14 @@
{ 'command': 'query-tpm-types', 'returns': ['TpmType'] }
##
+# @TPMOptions:
+#
+# Base type for TPM options
+##
+{ 'struct': 'TPMOptions',
+ 'data': { } }
+
+##
# @TPMPassthroughOptions:
#
# Information about the TPM passthrough type
@@ -5151,8 +5159,8 @@
#
# Since: 1.5
##
-{ 'struct': 'TPMPassthroughOptions', 'data': { '*path' : 'str',
- '*cancel-path' : 'str'} }
+{ 'struct': 'TPMPassthroughOptions', 'base': 'TPMOptions',
+ 'data': { '*path' : 'str', '*cancel-path' : 'str'} }
##
# @TpmTypeOptions:
diff --git a/tpm.c b/tpm.c
index 0ee021a..c221000 100644
--- a/tpm.c
+++ b/tpm.c
@@ -252,7 +252,6 @@ static const TPMDriverOps *tpm_driver_find_by_type(enum TpmType type)
static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
{
TPMInfo *res = g_new0(TPMInfo, 1);
- TPMPassthroughOptions *tpo;
res->id = g_strdup(drv->id);
res->model = drv->fe_model;
@@ -261,16 +260,8 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
switch (tpm_backend_get_type(drv)) {
case TPM_TYPE_PASSTHROUGH:
res->options->type = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
- tpo = g_new0(TPMPassthroughOptions, 1);
- res->options->u.passthrough.data = tpo;
- if (drv->path) {
- tpo->path = g_strdup(drv->path);
- tpo->has_path = true;
- }
- if (drv->cancel_path) {
- tpo->cancel_path = g_strdup(drv->cancel_path);
- tpo->has_cancel_path = true;
- }
+ res->options->u.passthrough.data =
+ (TPMPassthroughOptions *)tpm_backend_get_tpm_options(drv);
break;
case TPM_TYPE__MAX:
break;
--
2.7.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 5/7] tmp backend: Add new api to read backend tpm options
2017-03-31 13:10 ` [Qemu-devel] [PATCH 5/7] tmp backend: Add new api to read backend tpm options Amarnath Valluri
@ 2017-04-03 19:24 ` Eric Blake
0 siblings, 0 replies; 37+ messages in thread
From: Eric Blake @ 2017-04-03 19:24 UTC (permalink / raw)
To: Amarnath Valluri, qemu-devel; +Cc: patrick.ohly, stefanb
[-- Attachment #1: Type: text/plain, Size: 1829 bytes --]
On 03/31/2017 08:10 AM, Amarnath Valluri wrote:
> TPM configuration options are backend implementation details and shall not be
> part of base TPMBackend object, and these shall not be accessed directly outside
> of the class, hence added a new tpm backend api, tpm_backend_get_tpm_options()
> to read the backend configured options.
>
> Added new method, get_tpm_options() to TPMDriverOps., which shall be implemented
> by the derived classes to return configured tpm options.
>
> Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
> ---
Just an interface review for now:
> +++ b/qapi-schema.json
> @@ -5140,6 +5140,14 @@
> { 'command': 'query-tpm-types', 'returns': ['TpmType'] }
>
> ##
> +# @TPMOptions:
> +#
> +# Base type for TPM options
> +##
Missing a 'Since: 2.10' designation
> +{ 'struct': 'TPMOptions',
> + 'data': { } }
This class feels pointless (at least for now; I haven't checked if you
expand it later in the series - but if so, define it where you first
need it). It has no members, and you are only using it...
> +
> +##
> # @TPMPassthroughOptions:
> #
> # Information about the TPM passthrough type
> @@ -5151,8 +5159,8 @@
> #
> # Since: 1.5
> ##
> -{ 'struct': 'TPMPassthroughOptions', 'data': { '*path' : 'str',
> - '*cancel-path' : 'str'} }
> +{ 'struct': 'TPMPassthroughOptions', 'base': 'TPMOptions',
...as a base class. A base class makes sense only if it is consolidating
common members, or if it is the base to at least two different
structures where having a common C type to pass around is handy.
> + 'data': { '*path' : 'str', '*cancel-path' : 'str'} }
>
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH 6/7] tpm-passthrough: move reusable code to utils
2017-03-31 13:10 [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator Amarnath Valluri
` (4 preceding siblings ...)
2017-03-31 13:10 ` [Qemu-devel] [PATCH 5/7] tmp backend: Add new api to read backend tpm options Amarnath Valluri
@ 2017-03-31 13:10 ` Amarnath Valluri
2017-04-04 13:53 ` Marc-André Lureau
2017-03-31 13:10 ` [Qemu-devel] [PATCH 7/7] Added support for TPM emulator Amarnath Valluri
` (3 subsequent siblings)
9 siblings, 1 reply; 37+ messages in thread
From: Amarnath Valluri @ 2017-03-31 13:10 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanb, patrick.ohly, Amarnath Valluri
Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
---
hw/tpm/tpm_passthrough.c | 77 ++++--------------------------------------------
hw/tpm/tpm_util.c | 60 +++++++++++++++++++++++++++++++++++++
hw/tpm/tpm_util.h | 8 +++++
3 files changed, 73 insertions(+), 72 deletions(-)
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index fce1163..fc60914 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -69,73 +69,6 @@ typedef struct TPMPassthruState TPMPassthruState;
static void tpm_passthrough_cancel_cmd(TPMBackend *tb);
-static int tpm_passthrough_unix_write(int fd, const uint8_t *buf, uint32_t len)
-{
- int ret, remain;
-
- remain = len;
- while (remain > 0) {
- ret = write(fd, buf, remain);
- if (ret < 0) {
- if (errno != EINTR && errno != EAGAIN) {
- return -1;
- }
- } else if (ret == 0) {
- break;
- } else {
- buf += ret;
- remain -= ret;
- }
- }
- return len - remain;
-}
-
-static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len)
-{
- int ret;
- reread:
- ret = read(fd, buf, len);
- if (ret < 0) {
- if (errno != EINTR && errno != EAGAIN) {
- return -1;
- }
- goto reread;
- }
- return ret;
-}
-
-static uint32_t tpm_passthrough_get_size_from_buffer(const uint8_t *buf)
-{
- struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)buf;
-
- return be32_to_cpu(resp->len);
-}
-
-/*
- * Write an error message in the given output buffer.
- */
-static void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len)
-{
- if (out_len >= sizeof(struct tpm_resp_hdr)) {
- struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)out;
-
- resp->tag = cpu_to_be16(TPM_TAG_RSP_COMMAND);
- resp->len = cpu_to_be32(sizeof(struct tpm_resp_hdr));
- resp->errcode = cpu_to_be32(TPM_FAIL);
- }
-}
-
-static bool tpm_passthrough_is_selftest(const uint8_t *in, uint32_t in_len)
-{
- struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
-
- if (in_len >= sizeof(*hdr)) {
- return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
- }
-
- return false;
-}
-
static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
const uint8_t *in, uint32_t in_len,
uint8_t *out, uint32_t out_len,
@@ -149,9 +82,9 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
tpm_pt->tpm_executing = true;
*selftest_done = false;
- is_selftest = tpm_passthrough_is_selftest(in, in_len);
+ is_selftest = tpm_util_is_selftest(in, in_len);
- ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len);
+ ret = tpm_util_unix_write(tpm_pt->tpm_fd, in, in_len);
if (ret != in_len) {
if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) {
error_report("tpm_passthrough: error while transmitting data "
@@ -163,7 +96,7 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
tpm_pt->tpm_executing = false;
- ret = tpm_passthrough_unix_read(tpm_pt->tpm_fd, out, out_len);
+ ret = tpm_util_unix_read(tpm_pt->tpm_fd, out, out_len);
if (ret < 0) {
if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) {
error_report("tpm_passthrough: error while reading data from "
@@ -171,7 +104,7 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
strerror(errno), errno);
}
} else if (ret < sizeof(struct tpm_resp_hdr) ||
- tpm_passthrough_get_size_from_buffer(out) != ret) {
+ ((struct tpm_resp_hdr *)out)->len != ret) {
ret = -1;
error_report("tpm_passthrough: received invalid response "
"packet from TPM");
@@ -184,7 +117,7 @@ static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
err_exit:
if (ret < 0) {
- tpm_write_fatal_error_response(out, out_len);
+ tpm_util_write_fatal_error_response(out, out_len);
}
tpm_pt->tpm_executing = false;
diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c
index 7b35429..5475acf 100644
--- a/hw/tpm/tpm_util.c
+++ b/hw/tpm/tpm_util.c
@@ -23,6 +23,66 @@
#include "tpm_util.h"
#include "tpm_int.h"
+int tpm_util_unix_write(int fd, const uint8_t *buf, uint32_t len)
+{
+ int ret, remain;
+
+ remain = len;
+ while (remain > 0) {
+ ret = write(fd, buf, remain);
+ if (ret < 0) {
+ if (errno != EINTR && errno != EAGAIN) {
+ return -1;
+ }
+ } else if (ret == 0) {
+ break;
+ } else {
+ buf += ret;
+ remain -= ret;
+ }
+ }
+ return len - remain;
+}
+
+int tpm_util_unix_read(int fd, uint8_t *buf, uint32_t len)
+{
+ int ret;
+ reread:
+ ret = read(fd, buf, len);
+ if (ret < 0) {
+ if (errno != EINTR && errno != EAGAIN) {
+ return -1;
+ }
+ goto reread;
+ }
+ return ret;
+}
+
+/*
+ * Write an error message in the given output buffer.
+ */
+void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len)
+{
+ if (out_len >= sizeof(struct tpm_resp_hdr)) {
+ struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)out;
+
+ resp->tag = cpu_to_be16(TPM_TAG_RSP_COMMAND);
+ resp->len = cpu_to_be32(sizeof(struct tpm_resp_hdr));
+ resp->errcode = cpu_to_be32(TPM_FAIL);
+ }
+}
+
+bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len)
+{
+ struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
+
+ if (in_len >= sizeof(*hdr)) {
+ return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
+ }
+
+ return false;
+}
+
/*
* A basic test of a TPM device. We expect a well formatted response header
* (error response is fine) within one second.
diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h
index df76245..c2feca7 100644
--- a/hw/tpm/tpm_util.h
+++ b/hw/tpm/tpm_util.h
@@ -24,6 +24,14 @@
#include "sysemu/tpm_backend.h"
+int tpm_util_unix_write(int fd, const uint8_t *buf, uint32_t len);
+
+int tpm_util_unix_read(int fd, uint8_t *buf, uint32_t len);
+
+void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len);
+
+bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len);
+
int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version);
#endif /* TPM_TPM_UTIL_H */
--
2.7.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 6/7] tpm-passthrough: move reusable code to utils
2017-03-31 13:10 ` [Qemu-devel] [PATCH 6/7] tpm-passthrough: move reusable code to utils Amarnath Valluri
@ 2017-04-04 13:53 ` Marc-André Lureau
0 siblings, 0 replies; 37+ messages in thread
From: Marc-André Lureau @ 2017-04-04 13:53 UTC (permalink / raw)
To: Amarnath Valluri, qemu-devel; +Cc: patrick.ohly, stefanb
Hi
On Fri, Mar 31, 2017 at 4:57 PM Amarnath Valluri <amarnath.valluri@intel.com>
wrote:
> Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
>
Nothing really controversial here. You could point out in the commit
message that those functions will be used in the new backend perhaps.
> ---
> hw/tpm/tpm_passthrough.c | 77
> ++++--------------------------------------------
> hw/tpm/tpm_util.c | 60 +++++++++++++++++++++++++++++++++++++
> hw/tpm/tpm_util.h | 8 +++++
> 3 files changed, 73 insertions(+), 72 deletions(-)
>
> diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
> index fce1163..fc60914 100644
> --- a/hw/tpm/tpm_passthrough.c
> +++ b/hw/tpm/tpm_passthrough.c
> @@ -69,73 +69,6 @@ typedef struct TPMPassthruState TPMPassthruState;
>
> static void tpm_passthrough_cancel_cmd(TPMBackend *tb);
>
> -static int tpm_passthrough_unix_write(int fd, const uint8_t *buf,
> uint32_t len)
> -{
> - int ret, remain;
> -
> - remain = len;
> - while (remain > 0) {
> - ret = write(fd, buf, remain);
> - if (ret < 0) {
> - if (errno != EINTR && errno != EAGAIN) {
> - return -1;
> - }
> - } else if (ret == 0) {
> - break;
> - } else {
> - buf += ret;
> - remain -= ret;
> - }
> - }
> - return len - remain;
> -}
>
that looks like qemu_write_full()
> -
> -static int tpm_passthrough_unix_read(int fd, uint8_t *buf, uint32_t len)
> -{
> - int ret;
> - reread:
> - ret = read(fd, buf, len);
> - if (ret < 0) {
> - if (errno != EINTR && errno != EAGAIN) {
> - return -1;
> - }
> - goto reread;
> - }
> - return ret;
> -}
> -
>
Eventually, we may want to switch to QIOChannel.. just some thoughts
-static uint32_t tpm_passthrough_get_size_from_buffer(const uint8_t *buf)
> -{
> - struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)buf;
> -
> - return be32_to_cpu(resp->len);
> -}
> -
> -/*
> - * Write an error message in the given output buffer.
> - */
> -static void tpm_write_fatal_error_response(uint8_t *out, uint32_t out_len)
> -{
> - if (out_len >= sizeof(struct tpm_resp_hdr)) {
> - struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)out;
> -
> - resp->tag = cpu_to_be16(TPM_TAG_RSP_COMMAND);
> - resp->len = cpu_to_be32(sizeof(struct tpm_resp_hdr));
> - resp->errcode = cpu_to_be32(TPM_FAIL);
> - }
> -}
> -
> -static bool tpm_passthrough_is_selftest(const uint8_t *in, uint32_t
> in_len)
> -{
> - struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
> -
> - if (in_len >= sizeof(*hdr)) {
> - return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
> - }
> -
> - return false;
> -}
> -
> static int tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
> const uint8_t *in, uint32_t
> in_len,
> uint8_t *out, uint32_t out_len,
> @@ -149,9 +82,9 @@ static int
> tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
> tpm_pt->tpm_executing = true;
> *selftest_done = false;
>
> - is_selftest = tpm_passthrough_is_selftest(in, in_len);
> + is_selftest = tpm_util_is_selftest(in, in_len);
>
> - ret = tpm_passthrough_unix_write(tpm_pt->tpm_fd, in, in_len);
> + ret = tpm_util_unix_write(tpm_pt->tpm_fd, in, in_len);
> if (ret != in_len) {
> if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) {
> error_report("tpm_passthrough: error while transmitting data "
> @@ -163,7 +96,7 @@ static int
> tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
>
> tpm_pt->tpm_executing = false;
>
> - ret = tpm_passthrough_unix_read(tpm_pt->tpm_fd, out, out_len);
> + ret = tpm_util_unix_read(tpm_pt->tpm_fd, out, out_len);
> if (ret < 0) {
> if (!tpm_pt->tpm_op_canceled || errno != ECANCELED) {
> error_report("tpm_passthrough: error while reading data from "
> @@ -171,7 +104,7 @@ static int
> tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
> strerror(errno), errno);
> }
> } else if (ret < sizeof(struct tpm_resp_hdr) ||
> - tpm_passthrough_get_size_from_buffer(out) != ret) {
> + ((struct tpm_resp_hdr *)out)->len != ret) {
> ret = -1;
> error_report("tpm_passthrough: received invalid response "
> "packet from TPM");
> @@ -184,7 +117,7 @@ static int
> tpm_passthrough_unix_tx_bufs(TPMPassthruState *tpm_pt,
>
> err_exit:
> if (ret < 0) {
> - tpm_write_fatal_error_response(out, out_len);
> + tpm_util_write_fatal_error_response(out, out_len);
> }
>
> tpm_pt->tpm_executing = false;
> diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c
> index 7b35429..5475acf 100644
> --- a/hw/tpm/tpm_util.c
> +++ b/hw/tpm/tpm_util.c
> @@ -23,6 +23,66 @@
> #include "tpm_util.h"
> #include "tpm_int.h"
>
> +int tpm_util_unix_write(int fd, const uint8_t *buf, uint32_t len)
> +{
> + int ret, remain;
> +
> + remain = len;
> + while (remain > 0) {
> + ret = write(fd, buf, remain);
> + if (ret < 0) {
> + if (errno != EINTR && errno != EAGAIN) {
> + return -1;
> + }
> + } else if (ret == 0) {
> + break;
> + } else {
> + buf += ret;
> + remain -= ret;
> + }
> + }
> + return len - remain;
> +}
> +
> +int tpm_util_unix_read(int fd, uint8_t *buf, uint32_t len)
> +{
> + int ret;
> + reread:
> + ret = read(fd, buf, len);
> + if (ret < 0) {
> + if (errno != EINTR && errno != EAGAIN) {
> + return -1;
> + }
> + goto reread;
> + }
> + return ret;
> +}
> +
> +/*
> + * Write an error message in the given output buffer.
> + */
> +void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len)
> +{
> + if (out_len >= sizeof(struct tpm_resp_hdr)) {
> + struct tpm_resp_hdr *resp = (struct tpm_resp_hdr *)out;
> +
> + resp->tag = cpu_to_be16(TPM_TAG_RSP_COMMAND);
> + resp->len = cpu_to_be32(sizeof(struct tpm_resp_hdr));
> + resp->errcode = cpu_to_be32(TPM_FAIL);
> + }
> +}
> +
> +bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len)
> +{
> + struct tpm_req_hdr *hdr = (struct tpm_req_hdr *)in;
> +
> + if (in_len >= sizeof(*hdr)) {
> + return (be32_to_cpu(hdr->ordinal) == TPM_ORD_ContinueSelfTest);
> + }
> +
> + return false;
> +}
> +
> /*
> * A basic test of a TPM device. We expect a well formatted response
> header
> * (error response is fine) within one second.
> diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h
> index df76245..c2feca7 100644
> --- a/hw/tpm/tpm_util.h
> +++ b/hw/tpm/tpm_util.h
> @@ -24,6 +24,14 @@
>
> #include "sysemu/tpm_backend.h"
>
> +int tpm_util_unix_write(int fd, const uint8_t *buf, uint32_t len);
> +
> +int tpm_util_unix_read(int fd, uint8_t *buf, uint32_t len);
> +
> +void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len);
> +
> +bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len);
> +
> int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version);
>
> #endif /* TPM_TPM_UTIL_H */
> --
> 2.7.4
>
>
> --
Marc-André Lureau
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH 7/7] Added support for TPM emulator
2017-03-31 13:10 [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator Amarnath Valluri
` (5 preceding siblings ...)
2017-03-31 13:10 ` [Qemu-devel] [PATCH 6/7] tpm-passthrough: move reusable code to utils Amarnath Valluri
@ 2017-03-31 13:10 ` Amarnath Valluri
2017-04-03 19:30 ` Eric Blake
2017-03-31 13:10 ` [Qemu-devel] [PATCH 7/7] tpm: New backend driver to support " Amarnath Valluri
` (2 subsequent siblings)
9 siblings, 1 reply; 37+ messages in thread
From: Amarnath Valluri @ 2017-03-31 13:10 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanb, patrick.ohly, Amarnath Valluri
This change introduces a new TPM backend driver that can communicates with
swtpm(software TPM emulator) using unix domain socket interface.
Swtpm uses two unix sockets, one for plain TPM commands and responses, and one
for out-of-band control messages.
The swtpm and associated tools can be found here:
https://github.com/stefanberger/swtpm
Usage:
# setup TPM state directory
mkdir /tmp/mytpm
chown -R tss:root /tmp/mytpm
/usr/bin/swtpm_setup --tpm-state /tmp/mytpm --createek
# Ask qeum to use TPM emulator with given tpm state directory
qemu-system-x86_64 \
[...] \
-tpmdev emulator,id=tpm0,tpmstatedir=/tmp/mytpm,logfile=/tmp/swtpm.log \
-device tpm-tis,tpmdev=tpm0 \
[...]
Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
---
configure | 6 +
hmp.c | 14 +
hw/tpm/Makefile.objs | 1 +
hw/tpm/tpm_emulator.c | 740 ++++++++++++++++++++++++++++++++++++++++++++++++++
hw/tpm/tpm_ioctl.h | 243 +++++++++++++++++
hw/tpm/tpm_util.c | 34 +++
hw/tpm/tpm_util.h | 3 +
qapi-schema.json | 22 +-
qemu-options.hx | 25 +-
tpm.c | 7 +-
10 files changed, 1089 insertions(+), 6 deletions(-)
create mode 100644 hw/tpm/tpm_emulator.c
create mode 100644 hw/tpm/tpm_ioctl.h
diff --git a/configure b/configure
index 4901b9a..9089546 100755
--- a/configure
+++ b/configure
@@ -3349,8 +3349,10 @@ fi
if test "$targetos" = Linux && test "$cpu" = i386 -o "$cpu" = x86_64; then
tpm_passthrough=$tpm
+ tpm_emulator=$tpm
else
tpm_passthrough=no
+ tpm_emulator=no
fi
##########################################
@@ -5125,6 +5127,7 @@ echo "gcov enabled $gcov"
echo "TPM support $tpm"
echo "libssh2 support $libssh2"
echo "TPM passthrough $tpm_passthrough"
+echo "TPM emulator $tpm_emulator"
echo "QOM debugging $qom_cast_debug"
echo "lzo support $lzo"
echo "snappy support $snappy"
@@ -5704,6 +5707,9 @@ if test "$tpm" = "yes"; then
if test "$tpm_passthrough" = "yes"; then
echo "CONFIG_TPM_PASSTHROUGH=y" >> $config_host_mak
fi
+ if test "$tpm_emulator" = "yes"; then
+ echo "CONFIG_TPM_EMULATOR=y" >> $config_host_mak
+ fi
fi
echo "TRACE_BACKENDS=$trace_backends" >> $config_host_mak
diff --git a/hmp.c b/hmp.c
index edb8970..03a47e2 100644
--- a/hmp.c
+++ b/hmp.c
@@ -937,6 +937,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
Error *err = NULL;
unsigned int c = 0;
TPMPassthroughOptions *tpo;
+ TPMEmulatorOptions *teo;
info_list = qmp_query_tpm(&err);
if (err) {
@@ -966,6 +967,19 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
tpo->has_cancel_path ? ",cancel-path=" : "",
tpo->has_cancel_path ? tpo->cancel_path : "");
break;
+ case TPM_TYPE_OPTIONS_KIND_EMULATOR:
+ teo = ti->options->u.emulator.data;
+ monitor_printf(mon, ",tmpstatedir=%s", teo->tpmstatedir);
+ if (teo->has_path) {
+ monitor_printf(mon, ",path=%s", teo->path);
+ }
+ if (teo->has_logfile) {
+ monitor_printf(mon, ",logfile=%s", teo->logfile);
+ }
+ if (teo->has_loglevel) {
+ monitor_printf(mon, ",loglevel=%ld", teo->loglevel);
+ }
+ break;
case TPM_TYPE_OPTIONS_KIND__MAX:
break;
}
diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index 64cecc3..41f0b7a 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,2 +1,3 @@
common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o
+common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o tpm_util.o
diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c
new file mode 100644
index 0000000..5b1dcfa
--- /dev/null
+++ b/hw/tpm/tpm_emulator.c
@@ -0,0 +1,740 @@
+/*
+ * emulator TPM driver
+ *
+ * Copyright (c) 2017 Intel Corporation
+ * Author: Amarnath Valluri <amarnath.valluri@intel.com>
+ *
+ * Copyright (c) 2010 - 2013 IBM Corporation
+ * Authors:
+ * Stefan Berger <stefanb@us.ibm.com>
+ *
+ * Copyright (C) 2011 IAIK, Graz University of Technology
+ * Author: Andreas Niederl
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ *
+ * The origin of the code is from CUSE driver posed by Stefan Berger:
+ * https://github.com/stefanberger/qemu-tpm
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "sysemu/tpm_backend.h"
+#include "tpm_int.h"
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "sysemu/tpm_backend_int.h"
+#include "tpm_util.h"
+#include "tpm_ioctl.h"
+#include "qapi/error.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+
+#define DEBUG_TPM 0
+
+#define DPRINT(fmt, ...) do { \
+ if (DEBUG_TPM) { \
+ fprintf(stderr, fmt, ## __VA_ARGS__); \
+ } \
+} while (0);
+
+#define DPRINTF(fmt, ...) DPRINT(fmt"\n", __VA_ARGS__)
+
+#define TYPE_TPM_EMULATOR "emulator"
+#define TPM_EMULATOR(obj) \
+ OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)
+
+static const TPMDriverOps tpm_emulator_driver;
+
+/* data structures */
+typedef struct TPMEmulator {
+ TPMBackend parent;
+
+ TPMEmulatorOptions ops;
+ int tpm_fd;
+ int tpm_ctrl_fd;
+ bool op_executing;
+ bool op_canceled;
+ bool child_running;
+ TPMVersion tpm_version;
+ ptm_cap caps; /* capabilities of the TPM */
+ uint8_t cur_locty_number; /* last set locality */
+} TPMEmulator;
+
+#define TPM_DEFAULT_EMULATOR "swtpm"
+#define TPM_DEFAULT_LOGLEVEL 5
+#define TPM_EUMLATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap))
+
+static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_pt,
+ const uint8_t *in, uint32_t in_len,
+ uint8_t *out, uint32_t out_len,
+ bool *selftest_done)
+{
+ int ret;
+ bool is_selftest;
+ const struct tpm_resp_hdr *hdr;
+
+ if (!tpm_pt->child_running) {
+ return -1;
+ }
+
+ tpm_pt->op_canceled = false;
+ tpm_pt->op_executing = true;
+ *selftest_done = false;
+
+ is_selftest = tpm_util_is_selftest(in, in_len);
+
+ ret = tpm_util_unix_write(tpm_pt->tpm_fd, in, in_len);
+ if (ret != in_len) {
+ if (!tpm_pt->op_canceled || errno != ECANCELED) {
+ error_report("tpm_emulator: error while transmitting data "
+ "to TPM: %s (%i)", strerror(errno), errno);
+ }
+ goto err_exit;
+ }
+
+ tpm_pt->op_executing = false;
+
+ ret = tpm_util_unix_read(tpm_pt->tpm_fd, out, out_len);
+ if (ret < 0) {
+ if (!tpm_pt->op_canceled || errno != ECANCELED) {
+ error_report("tpm_emulator: error while reading data from "
+ "TPM: %s (%i)", strerror(errno), errno);
+ }
+ } else if (ret < sizeof(struct tpm_resp_hdr) ||
+ be32_to_cpu(((struct tpm_resp_hdr *)out)->len) != ret) {
+ ret = -1;
+ error_report("tpm_emulator: received invalid response "
+ "packet from TPM");
+ }
+
+ if (is_selftest && (ret >= sizeof(struct tpm_resp_hdr))) {
+ hdr = (struct tpm_resp_hdr *)out;
+ *selftest_done = (be32_to_cpu(hdr->errcode) == 0);
+ }
+
+err_exit:
+ if (ret < 0) {
+ tpm_util_write_fatal_error_response(out, out_len);
+ }
+
+ tpm_pt->op_executing = false;
+
+ return ret;
+}
+
+static int tpm_emulator_set_locality(TPMEmulator *tpm_pt,
+ uint8_t locty_number)
+{
+ ptm_loc loc;
+
+ if (!tpm_pt->child_running) {
+ return -1;
+ }
+
+ DPRINTF("tpm_emulator: %s : locality: 0x%x", __func__, locty_number);
+
+ if (tpm_pt->cur_locty_number != locty_number) {
+ DPRINTF("tpm-emulator: setting locality : 0x%x", locty_number);
+ loc.u.req.loc = cpu_to_be32(locty_number);
+ if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_SET_LOCALITY, &loc,
+ sizeof(loc), sizeof(loc)) < 0) {
+ error_report("tpm-emulator: could not set locality : %s",
+ strerror(errno));
+ return -1;
+ }
+ loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result);
+ if (loc.u.resp.tpm_result != 0) {
+ error_report("tpm-emulator: TPM result for set locality : 0x%x",
+ loc.u.resp.tpm_result);
+ return -1;
+ }
+ tpm_pt->cur_locty_number = locty_number;
+ }
+ return 0;
+}
+
+static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd cmd)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+ TPMLocality *locty = NULL;
+ bool selftest_done = false;
+
+ DPRINTF("tpm_emulator: processing command type %d", cmd);
+
+ switch (cmd) {
+ case TPM_BACKEND_CMD_PROCESS_CMD:
+ locty = tb->tpm_state->locty_data;
+ if (tpm_emulator_set_locality(tpm_pt,
+ tb->tpm_state->locty_number) < 0) {
+ tpm_util_write_fatal_error_response(locty->r_buffer.buffer,
+ locty->r_buffer.size);
+ } else {
+ tpm_emulator_unix_tx_bufs(tpm_pt, locty->w_buffer.buffer,
+ locty->w_offset, locty->r_buffer.buffer,
+ locty->r_buffer.size, &selftest_done);
+ }
+ tb->recv_data_callback(tb->tpm_state, tb->tpm_state->locty_number,
+ selftest_done);
+ break;
+ case TPM_BACKEND_CMD_INIT:
+ case TPM_BACKEND_CMD_END:
+ case TPM_BACKEND_CMD_TPM_RESET:
+ /* nothing to do */
+ break;
+ }
+}
+
+/*
+ * Gracefully shut down the external unixio TPM
+ */
+static void tpm_emulator_shutdown(TPMEmulator *tpm_pt)
+{
+ ptm_res res;
+
+ if (!tpm_pt->child_running) {
+ return;
+ }
+
+ if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_SHUTDOWN, &res, 0,
+ sizeof(res)) < 0) {
+ error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s",
+ strerror(errno));
+ } else if (res != 0) {
+ error_report("tpm-emulator: TPM result for sutdown: 0x%x",
+ be32_to_cpu(res));
+ }
+}
+
+static int tpm_emulator_probe_caps(TPMEmulator *tpm_pt)
+{
+ if (!tpm_pt->child_running) {
+ return -1;
+ }
+
+ DPRINTF("tpm_emulator: %s", __func__);
+ if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_GET_CAPABILITY,
+ &tpm_pt->caps, 0, sizeof(tpm_pt->caps)) < 0) {
+ error_report("tpm-emulator: probing failed : %s", strerror(errno));
+ return -1;
+ }
+
+ tpm_pt->caps = be64_to_cpu(tpm_pt->caps);
+
+ DPRINTF("tpm-emulator: capbilities : 0x%lx", tpm_pt->caps);
+
+ return 0;
+}
+
+static int tpm_emulator_check_caps(TPMEmulator *tpm_pt)
+{
+ ptm_cap caps = 0;
+ const char *tpm = NULL;
+
+ /* check for min. required capabilities */
+ switch (tpm_pt->tpm_version) {
+ case TPM_VERSION_1_2:
+ caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
+ PTM_CAP_SET_LOCALITY;
+ tpm = "1.2";
+ break;
+ case TPM_VERSION_2_0:
+ caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
+ PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED;
+ tpm = "2";
+ break;
+ case TPM_VERSION_UNSPEC:
+ error_report("tpm-emulator: TPM version has not been set");
+ return -1;
+ }
+
+ if (!TPM_EUMLATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, caps)) {
+ error_report("tpm-emulator: TPM does not implement minimum set of "
+ "required capabilities for TPM %s (0x%x)", tpm, (int)caps);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int tpm_emulator_init_tpm(TPMEmulator *tpm_pt, bool is_resume)
+{
+ ptm_init init;
+ ptm_res res;
+
+ if (!tpm_pt->child_running) {
+ return -1;
+ }
+
+ DPRINTF("tpm_emulator: %s", __func__);
+ if (is_resume) {
+ init.u.req.init_flags = cpu_to_be32(PTM_INIT_FLAG_DELETE_VOLATILE);
+ }
+
+ if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_INIT, &init, sizeof(init),
+ sizeof(init)) < 0) {
+ error_report("tpm-emulator: could not send INIT: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ res = be32_to_cpu(init.u.resp.tpm_result);
+ if (res) {
+ error_report("tpm-emulator: TPM result for PTM_INIT: 0x%x", res);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int tpm_emulator_startup_tpm(TPMBackend *tb)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+
+ DPRINTF("tpm_emulator: %s", __func__);
+
+ tpm_emulator_init_tpm(tpm_pt, false) ;
+
+ return 0;
+}
+
+static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+ ptm_est est;
+
+ DPRINTF("tpm_emulator: %s", __func__);
+ if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_GET_TPMESTABLISHED, &est, 0,
+ sizeof(est)) < 0) {
+ error_report("tpm-emulator: Could not get the TPM established flag: %s",
+ strerror(errno));
+ return false;
+ }
+ DPRINTF("tpm_emulator: established flag: %0x", est.u.resp.bit);
+
+ return (est.u.resp.bit != 0);
+}
+
+static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,
+ uint8_t locty)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+ ptm_reset_est reset_est;
+ ptm_res res;
+
+ /* only a TPM 2.0 will support this */
+ if (tpm_pt->tpm_version == TPM_VERSION_2_0) {
+ reset_est.u.req.loc = cpu_to_be32(tpm_pt->cur_locty_number);
+
+ if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_RESET_TPMESTABLISHED,
+ &reset_est, sizeof(reset_est),
+ sizeof(reset_est)) < 0) {
+ error_report("tpm-emulator: Could not reset the establishment bit: "
+ "%s", strerror(errno));
+ return -1;
+ }
+
+ res = be32_to_cpu(reset_est.u.resp.tpm_result);
+ if (res) {
+ error_report("tpm-emulator: TPM result for rest establixhed flag: "
+ "0x%x", res);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static bool tpm_emulator_get_startup_error(TPMBackend *tb)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+
+ return !tpm_pt->child_running;
+}
+
+static size_t tpm_emulator_realloc_buffer(TPMSizedBuffer *sb)
+{
+ size_t wanted_size = 4096; /* Linux tpm.c buffer size */
+
+ if (sb->size != wanted_size) {
+ sb->buffer = g_realloc(sb->buffer, wanted_size);
+ sb->size = wanted_size;
+ }
+ return sb->size;
+}
+
+static void tpm_emulator_cancel_cmd(TPMBackend *tb)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+ ptm_res res;
+
+ /*
+ * As of Linux 3.7 the tpm_tis driver does not properly cancel
+ * commands on all TPM manufacturers' TPMs.
+ * Only cancel if we're busy so we don't cancel someone else's
+ * command, e.g., a command executed on the host.
+ */
+ if (tpm_pt->op_executing) {
+ if (TPM_EUMLATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, PTM_CAP_CANCEL_TPM_CMD)) {
+ if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_CANCEL_TPM_CMD, &res,
+ 0, sizeof(res)) < 0) {
+ error_report("tpm-emulator: Could not cancel command: %s",
+ strerror(errno));
+ } else if (res != 0) {
+ error_report("tpm-emulator: Failed to cancel TPM: 0x%x",
+ be32_to_cpu(res));
+ } else {
+ tpm_pt->op_canceled = true;
+ }
+ }
+ }
+}
+
+static void tpm_emulator_reset(TPMBackend *tb)
+{
+ DPRINTF("tpm_emulator: %s", __func__);
+
+ tpm_emulator_cancel_cmd(tb);
+}
+
+static const char *tpm_emulator_desc(void)
+{
+ return "TPM emulator backend driver";
+}
+
+static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+
+ return tpm_pt->tpm_version;
+}
+
+static void tpm_emulator_fd_handler(void *opaque)
+{
+ TPMEmulator *tpm_pt = opaque;
+ char val = 0;
+ ssize_t size;
+
+ qemu_set_fd_handler(tpm_pt->tpm_fd, NULL, NULL, NULL);
+
+ size = qemu_recv(tpm_pt->tpm_fd, &val, 1, MSG_PEEK);
+ if (!size) {
+ error_report("TPM backend disappeared");
+ tpm_pt->child_running = false;
+ } else {
+ DPRINT("tpm-emulator: unexpected data on TPM\n");
+ }
+}
+
+static int tpm_emulator_spawn_emulator(TPMEmulator *tpm_pt)
+{
+ int fds[2];
+ int ctrl_fds[2];
+ pid_t cpid;
+
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) < 0) {
+ return -1;
+ }
+
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ctrl_fds) < 0) {
+ closesocket(fds[0]);
+ closesocket(fds[1]);
+ return -1;
+ }
+
+ cpid = fork();
+ if (cpid < 0) {
+ error_report("tpm-emulator: Fork failure: %s", strerror(errno));
+ closesocket(fds[0]); closesocket(fds[1]);
+ closesocket(ctrl_fds[0]); closesocket(ctrl_fds[1]);
+ return -1;
+ }
+
+ if (cpid == 0) { /* CHILD */
+ int i;
+ char fd_str[128] = "";
+ char ctrl_fd_str[128] = "";
+ char tpmstate_str[1024] = "";
+ char log_str[1024] = "";
+ const char *params[] = {
+ tpm_pt->ops.path, "socket",
+ "--fd", fd_str,
+ "--ctrl", ctrl_fd_str,
+ "--tpmstate", tpmstate_str,
+ "--log", log_str,
+ NULL /* End */
+ };
+
+ /* close all unused inherited sockets */
+ closesocket(fds[0]);
+ closesocket(ctrl_fds[0]);
+ for (i = STDERR_FILENO + 1; i < fds[1]; i++) {
+ closesocket(i);
+ }
+
+ sprintf(fd_str, "%d", fds[1]);
+ sprintf(ctrl_fd_str, "type=unixio,clientfd=%d", ctrl_fds[1]);
+ sprintf(tpmstate_str, "dir=%s", tpm_pt->ops.tpmstatedir);
+ if (tpm_pt->ops.has_logfile) {
+ sprintf(log_str, "file=%s,level=%d", tpm_pt->ops.logfile,
+ (int)tpm_pt->ops.loglevel);
+ } else {
+ /* truncate logs */
+ params[8] = NULL;
+ }
+ DPRINT("Running cmd: ")
+ for (i = 0; params[i]; i++) {
+ DPRINT(" %s", params[i])
+ }
+ DPRINT("\n")
+ if (execv(tpm_pt->ops.path, (char * const *)params) < 0) {
+ error_report("execv() failure : %s", strerror(errno));
+ }
+ closesocket(fds[1]);
+ closesocket(ctrl_fds[1]);
+ exit(0);
+ } else { /* self */
+ DPRINTF("tpm-emulator: child pid: %d", cpid);
+ /* FIXME: find better way of finding swtpm ready
+ maybe write 'ready'bit on socket ?
+ give some time to child to get ready */
+ sleep(1);
+
+ tpm_pt->tpm_fd = fds[0];
+ tpm_pt->tpm_ctrl_fd = ctrl_fds[0];
+ tpm_pt->child_running = true;
+
+ qemu_add_child_watch(cpid);
+
+ fcntl(tpm_pt->tpm_fd, F_SETFL, O_NONBLOCK);
+ qemu_set_fd_handler(tpm_pt->tpm_fd, tpm_emulator_fd_handler, NULL,
+ tpm_pt);
+
+ /* close unsed sockets */
+ closesocket(fds[1]);
+ closesocket(ctrl_fds[1]);
+ }
+
+ return 0;
+}
+
+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_pt, QemuOpts *opts)
+{
+ const char *value;
+
+ value = qemu_opt_get(opts, "tpmstatedir");
+ if (!value) {
+ error_report("tpm-emulator: Missing tpm state directory");
+ return -1;
+ }
+ tpm_pt->ops.tpmstatedir = g_strdup(value);
+
+ value = qemu_opt_get(opts, "path");
+ if (!value) {
+ value = TPM_DEFAULT_EMULATOR;
+ tpm_pt->ops.has_path = false;
+ } else {
+ tpm_pt->ops.has_path = true;
+ if (value[0] == '/') {
+ struct stat st;
+ if (stat(value, &st) < 0 || !(S_ISREG(st.st_mode)
+ || S_ISLNK(st.st_mode))) {
+ error_report("tpm-emulator: Invalid emulator path: %s", value);
+ return -1;
+ }
+ }
+ }
+ tpm_pt->ops.path = g_strdup(value);
+
+ value = qemu_opt_get(opts, "logfile");
+ if (value) {
+ DPRINTF("tpm-emulator: LogFile: %s", value);
+ tpm_pt->ops.has_logfile = true;
+ tpm_pt->ops.logfile = g_strdup(value);
+ tpm_pt->ops.loglevel = qemu_opt_get_number(opts, "loglevel",
+ TPM_DEFAULT_LOGLEVEL);
+ tpm_pt->ops.has_loglevel = tpm_pt->ops.loglevel !=
+ TPM_DEFAULT_LOGLEVEL;
+ }
+
+ if (tpm_emulator_spawn_emulator(tpm_pt) < 0) {
+ goto err_close_dev;
+ }
+
+ tpm_pt->cur_locty_number = ~0;
+
+ if (tpm_emulator_probe_caps(tpm_pt) ||
+ tpm_emulator_init_tpm(tpm_pt, false)) {
+ goto err_close_dev;
+ }
+
+ if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) {
+ error_report("'%s' is not emulating TPM device.", tpm_pt->ops.path);
+ goto err_close_dev;
+ }
+
+ DPRINTF("tpm_emulator: TPM Version %s",
+ tpm_pt->tpm_version == TPM_VERSION_1_2 ? "1.2" :
+ (tpm_pt->tpm_version == TPM_VERSION_2_0 ? "2.0" : "Unspecified"));
+
+ if (tpm_emulator_check_caps(tpm_pt)) {
+ goto err_close_dev;
+ }
+
+ return 0;
+
+err_close_dev:
+ tpm_emulator_shutdown(tpm_pt);
+ return -1;
+}
+
+static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id)
+{
+ TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
+
+ tb->id = g_strdup(id);
+
+ if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {
+ goto err_exit;
+ }
+
+ return tb;
+
+err_exit:
+ object_unref(OBJECT(tb));
+
+ return NULL;
+}
+
+static void tpm_emulator_destroy(TPMBackend *tb)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+
+ DPRINTF("tpm_emulator: %s", __func__);
+
+ tpm_emulator_cancel_cmd(tb);
+ tpm_emulator_shutdown(tpm_pt);
+
+ closesocket(tpm_pt->tpm_fd);
+ closesocket(tpm_pt->tpm_ctrl_fd);
+ g_free(tpm_pt->ops.tpmstatedir);
+ g_free(tpm_pt->ops.path);
+ g_free(tpm_pt->ops.logfile);
+}
+
+static TPMOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+ TPMEmulatorOptions *ops = g_new(TPMEmulatorOptions, 1);
+
+ if (!ops) {
+ return NULL;
+ }
+ DPRINTF("tpm_emulator: %s", __func__);
+
+ ops->tpmstatedir = g_strdup(tpm_pt->ops.tpmstatedir);
+ if (tpm_pt->ops.has_path) {
+ ops->has_path = true;
+ ops->path = g_strdup(tpm_pt->ops.path);
+ }
+ if (tpm_pt->ops.has_logfile) {
+ ops->has_logfile = true;
+ ops->logfile = g_strdup(tpm_pt->ops.logfile);
+ }
+ if (tpm_pt->ops.has_loglevel) {
+ ops->has_loglevel = true;
+ ops->loglevel = tpm_pt->ops.loglevel;
+ }
+
+ return (TPMOptions *)ops;
+}
+
+static const QemuOptDesc tpm_emulator_cmdline_opts[] = {
+ TPM_STANDARD_CMDLINE_OPTS,
+ {
+ .name = "tpmstatedir",
+ .type = QEMU_OPT_STRING,
+ .help = "TPM state directroy",
+ },
+ {
+ .name = "path",
+ .type = QEMU_OPT_STRING,
+ .help = "Path to TPM emulator binary",
+ },
+ {
+ .name = "logfile",
+ .type = QEMU_OPT_STRING,
+ .help = "Path to log file",
+ },
+ {
+ .name = "level",
+ .type = QEMU_OPT_STRING,
+ .help = "Log level number",
+ },
+ { /* end of list */ },
+};
+
+static const TPMDriverOps tpm_emulator_driver = {
+ .type = TPM_TYPE_EMULATOR,
+ .opts = tpm_emulator_cmdline_opts,
+ .desc = tpm_emulator_desc,
+ .create = tpm_emulator_create,
+ .destroy = tpm_emulator_destroy,
+ .startup_tpm = tpm_emulator_startup_tpm,
+ .realloc_buffer = tpm_emulator_realloc_buffer,
+ .reset = tpm_emulator_reset,
+ .had_startup_error = tpm_emulator_get_startup_error,
+ .cancel_cmd = tpm_emulator_cancel_cmd,
+ .get_tpm_established_flag = tpm_emulator_get_tpm_established_flag,
+ .reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag,
+ .get_tpm_version = tpm_emulator_get_tpm_version,
+ .get_tpm_options = tpm_emulator_get_tpm_options,
+};
+
+static void tpm_emulator_inst_init(Object *obj)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(obj);
+
+ DPRINTF("tpm_emulator: %s", __func__);
+ tpm_pt->tpm_fd = tpm_pt->tpm_ctrl_fd = -1;
+ tpm_pt->op_executing = tpm_pt->op_canceled = false;
+ tpm_pt->child_running = false;
+ tpm_pt->cur_locty_number = ~0;
+}
+
+static void tpm_emulator_class_init(ObjectClass *klass, void *data)
+{
+ TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
+ tbc->ops = &tpm_emulator_driver;
+ tbc->handle_request = tpm_emulator_handle_request;
+}
+
+static const TypeInfo tpm_emulator_info = {
+ .name = TYPE_TPM_EMULATOR,
+ .parent = TYPE_TPM_BACKEND,
+ .instance_size = sizeof(TPMEmulator),
+ .class_init = tpm_emulator_class_init,
+ .instance_init = tpm_emulator_inst_init,
+};
+
+static void tpm_emulator_register(void)
+{
+ type_register_static(&tpm_emulator_info);
+ tpm_register_driver(&tpm_emulator_driver);
+}
+
+type_init(tpm_emulator_register)
diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h
new file mode 100644
index 0000000..af49708
--- /dev/null
+++ b/hw/tpm/tpm_ioctl.h
@@ -0,0 +1,243 @@
+/*
+ * tpm_ioctl.h
+ *
+ * (c) Copyright IBM Corporation 2014, 2015.
+ *
+ * This file is licensed under the terms of the 3-clause BSD license
+ */
+#ifndef _TPM_IOCTL_H_
+#define _TPM_IOCTL_H_
+
+#include <stdint.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+/*
+ * Every response from a command involving a TPM command execution must hold
+ * the ptm_res as the first element.
+ * ptm_res corresponds to the error code of a command executed by the TPM.
+ */
+
+typedef uint32_t ptm_res;
+
+/* PTM_GET_TPMESTABLISHED: get the establishment bit */
+struct ptm_est {
+ union {
+ struct {
+ ptm_res tpm_result;
+ unsigned char bit; /* TPM established bit */
+ } resp; /* response */
+ } u;
+};
+
+/* PTM_RESET_TPMESTABLISHED: reset establishment bit */
+struct ptm_reset_est {
+ union {
+ struct {
+ uint8_t loc; /* locality to use */
+ } req; /* request */
+ struct {
+ ptm_res tpm_result;
+ } resp; /* response */
+ } u;
+};
+
+/* PTM_INIT */
+struct ptm_init {
+ union {
+ struct {
+ uint32_t init_flags; /* see definitions below */
+ } req; /* request */
+ struct {
+ ptm_res tpm_result;
+ } resp; /* response */
+ } u;
+};
+
+/* above init_flags */
+#define PTM_INIT_FLAG_DELETE_VOLATILE (1 << 0)
+ /* delete volatile state file after reading it */
+
+/* PTM_SET_LOCALITY */
+struct ptm_loc {
+ union {
+ struct {
+ uint8_t loc; /* locality to set */
+ } req; /* request */
+ struct {
+ ptm_res tpm_result;
+ } resp; /* response */
+ } u;
+};
+
+/* PTM_HASH_DATA: hash given data */
+struct ptm_hdata {
+ union {
+ struct {
+ uint32_t length;
+ uint8_t data[4096];
+ } req; /* request */
+ struct {
+ ptm_res tpm_result;
+ } resp; /* response */
+ } u;
+};
+
+/*
+ * size of the TPM state blob to transfer; x86_64 can handle 8k,
+ * ppc64le only ~7k; keep the response below a 4k page size
+ */
+#define PTM_STATE_BLOB_SIZE (3 * 1024)
+
+/*
+ * The following is the data structure to get state blobs from the TPM.
+ * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple reads
+ * with this ioctl and with adjusted offset are necessary. All bytes
+ * must be transferred and the transfer is done once the last byte has been
+ * returned.
+ * It is possible to use the read() interface for reading the data; however, the
+ * first bytes of the state blob will be part of the response to the ioctl(); a
+ * subsequent read() is only necessary if the total length (totlength) exceeds
+ * the number of received bytes. seek() is not supported.
+ */
+struct ptm_getstate {
+ union {
+ struct {
+ uint32_t state_flags; /* may be: PTM_STATE_FLAG_DECRYPTED */
+ uint32_t type; /* which blob to pull */
+ uint32_t offset; /* offset from where to read */
+ } req; /* request */
+ struct {
+ ptm_res tpm_result;
+ uint32_t state_flags; /* may be: PTM_STATE_FLAG_ENCRYPTED */
+ uint32_t totlength; /* total length that will be transferred */
+ uint32_t length; /* number of bytes in following buffer */
+ uint8_t data[PTM_STATE_BLOB_SIZE];
+ } resp; /* response */
+ } u;
+};
+
+/* TPM state blob types */
+#define PTM_BLOB_TYPE_PERMANENT 1
+#define PTM_BLOB_TYPE_VOLATILE 2
+#define PTM_BLOB_TYPE_SAVESTATE 3
+
+/* state_flags above : */
+#define PTM_STATE_FLAG_DECRYPTED 1 /* on input: get decrypted state */
+#define PTM_STATE_FLAG_ENCRYPTED 2 /* on output: state is encrypted */
+
+/*
+ * The following is the data structure to set state blobs in the TPM.
+ * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple
+ * 'writes' using this ioctl are necessary. The last packet is indicated
+ * by the length being smaller than the PTM_STATE_BLOB_SIZE.
+ * The very first packet may have a length indicator of '0' enabling
+ * a write() with all the bytes from a buffer. If the write() interface
+ * is used, a final ioctl with a non-full buffer must be made to indicate
+ * that all data were transferred (a write with 0 bytes would not work).
+ */
+struct ptm_setstate {
+ union {
+ struct {
+ uint32_t state_flags; /* may be PTM_STATE_FLAG_ENCRYPTED */
+ uint32_t type; /* which blob to set */
+ uint32_t length; /* length of the data;
+ use 0 on the first packet to
+ transfer using write() */
+ uint8_t data[PTM_STATE_BLOB_SIZE];
+ } req; /* request */
+ struct {
+ ptm_res tpm_result;
+ } resp; /* response */
+ } u;
+};
+
+/*
+ * PTM_GET_CONFIG: Data structure to get runtime configuration information
+ * such as which keys are applied.
+ */
+struct ptm_getconfig {
+ union {
+ struct {
+ ptm_res tpm_result;
+ uint32_t flags;
+ } resp; /* response */
+ } u;
+};
+
+#define PTM_CONFIG_FLAG_FILE_KEY 0x1
+#define PTM_CONFIG_FLAG_MIGRATION_KEY 0x2
+
+
+typedef uint64_t ptm_cap;
+typedef struct ptm_est ptm_est;
+typedef struct ptm_reset_est ptm_reset_est;
+typedef struct ptm_loc ptm_loc;
+typedef struct ptm_hdata ptm_hdata;
+typedef struct ptm_init ptm_init;
+typedef struct ptm_getstate ptm_getstate;
+typedef struct ptm_setstate ptm_setstate;
+typedef struct ptm_getconfig ptm_getconfig;
+
+/* capability flags returned by PTM_GET_CAPABILITY */
+#define PTM_CAP_INIT (1)
+#define PTM_CAP_SHUTDOWN (1 << 1)
+#define PTM_CAP_GET_TPMESTABLISHED (1 << 2)
+#define PTM_CAP_SET_LOCALITY (1 << 3)
+#define PTM_CAP_HASHING (1 << 4)
+#define PTM_CAP_CANCEL_TPM_CMD (1 << 5)
+#define PTM_CAP_STORE_VOLATILE (1 << 6)
+#define PTM_CAP_RESET_TPMESTABLISHED (1 << 7)
+#define PTM_CAP_GET_STATEBLOB (1 << 8)
+#define PTM_CAP_SET_STATEBLOB (1 << 9)
+#define PTM_CAP_STOP (1 << 10)
+#define PTM_CAP_GET_CONFIG (1 << 11)
+
+enum {
+ PTM_GET_CAPABILITY = _IOR('P', 0, ptm_cap),
+ PTM_INIT = _IOWR('P', 1, ptm_init),
+ PTM_SHUTDOWN = _IOR('P', 2, ptm_res),
+ PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptm_est),
+ PTM_SET_LOCALITY = _IOWR('P', 4, ptm_loc),
+ PTM_HASH_START = _IOR('P', 5, ptm_res),
+ PTM_HASH_DATA = _IOWR('P', 6, ptm_hdata),
+ PTM_HASH_END = _IOR('P', 7, ptm_res),
+ PTM_CANCEL_TPM_CMD = _IOR('P', 8, ptm_res),
+ PTM_STORE_VOLATILE = _IOR('P', 9, ptm_res),
+ PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptm_reset_est),
+ PTM_GET_STATEBLOB = _IOWR('P', 11, ptm_getstate),
+ PTM_SET_STATEBLOB = _IOWR('P', 12, ptm_setstate),
+ PTM_STOP = _IOR('P', 13, ptm_res),
+ PTM_GET_CONFIG = _IOR('P', 14, ptm_getconfig),
+};
+
+/*
+ * Commands used by the non-CUSE TPMs
+ *
+ * All messages container big-endian data.
+ *
+ * The return messages only contain the 'resp' part of the unions
+ * in the data structures above. Besides that the limits in the
+ * buffers above (ptm_hdata:u.req.data and ptm_get_state:u.resp.data
+ * and ptm_set_state:u.req.data) are 0xffffffff.
+ */
+enum {
+ CMD_GET_CAPABILITY = 1,
+ CMD_INIT,
+ CMD_SHUTDOWN,
+ CMD_GET_TPMESTABLISHED,
+ CMD_SET_LOCALITY,
+ CMD_HASH_START,
+ CMD_HASH_DATA,
+ CMD_HASH_END,
+ CMD_CANCEL_TPM_CMD,
+ CMD_STORE_VOLATILE,
+ CMD_RESET_TPMESTABLISHED,
+ CMD_GET_STATEBLOB,
+ CMD_SET_STATEBLOB,
+ CMD_STOP,
+ CMD_GET_CONFIG,
+};
+
+#endif /* _TPM_IOCTL_H */
diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c
index 5475acf..34b1d59 100644
--- a/hw/tpm/tpm_util.c
+++ b/hw/tpm/tpm_util.c
@@ -22,6 +22,7 @@
#include "qemu/osdep.h"
#include "tpm_util.h"
#include "tpm_int.h"
+#include "tpm_ioctl.h"
int tpm_util_unix_write(int fd, const uint8_t *buf, uint32_t len)
{
@@ -185,3 +186,36 @@ int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version)
return 1;
}
+
+static unsigned long ioctl_to_cmd(unsigned long ioctlnum)
+{
+ /* the ioctl number contains the command number - 1 */
+ return ((ioctlnum >> _IOC_NRSHIFT) & _IOC_NRMASK) + 1;
+}
+
+int tpm_util_ctrlcmd(int fd, unsigned long cmd, void *msg, size_t msg_len_in,
+ size_t msg_len_out)
+{
+ int n;
+
+ uint32_t cmd_no = cpu_to_be32(ioctl_to_cmd(cmd));
+ struct iovec iov[2] = {
+ { .iov_base = &cmd_no, .iov_len = sizeof(cmd_no), },
+ { .iov_base = msg, .iov_len = msg_len_in, },
+ };
+
+ n = writev(fd, iov, 2);
+ if (n > 0) {
+ if (msg_len_out > 0) {
+ n = read(fd, msg, msg_len_out);
+ /* simulate ioctl return value */
+ if (n > 0) {
+ n = 0;
+ }
+ } else {
+ n = 0;
+ }
+ }
+ return n;
+}
+
diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h
index c2feca7..b93d484 100644
--- a/hw/tpm/tpm_util.h
+++ b/hw/tpm/tpm_util.h
@@ -34,4 +34,7 @@ bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len);
int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version);
+int tpm_util_ctrlcmd(int fd, unsigned long cmd, void *msg,
+ size_t msg_len_in, size_t msg_len_out);
+
#endif /* TPM_TPM_UTIL_H */
diff --git a/qapi-schema.json b/qapi-schema.json
index 5faf1ac..e8ddbc6 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -5117,10 +5117,11 @@
# An enumeration of TPM types
#
# @passthrough: TPM passthrough type
+# @emulator: Software Emulator TPM type
#
# Since: 1.5
##
-{ 'enum': 'TpmType', 'data': [ 'passthrough' ] }
+{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ] }
##
# @query-tpm-types:
@@ -5163,6 +5164,22 @@
'data': { '*path' : 'str', '*cancel-path' : 'str'} }
##
+# @TPMEmulatorOptions:
+#
+# Information about the TPM emulator
+#
+# @tpmstatedir: TPM emilator state dir
+# @path: TPM emulator binary path to use
+# @logfile: file to use to place TPM emulator logs
+# @loglevel: log level number
+#
+# Since: 2.6
+##
+{ 'struct': 'TPMEmulatorOptions', 'base': 'TPMOptions',
+ 'data': { 'tpmstatedir' : 'str', '*path': 'str',
+ '*logfile' : 'str', '*loglevel' : 'int' } }
+
+##
# @TpmTypeOptions:
#
# A union referencing different TPM backend types' configuration options
@@ -5172,7 +5189,8 @@
# Since: 1.5
##
{ 'union': 'TpmTypeOptions',
- 'data': { 'passthrough' : 'TPMPassthroughOptions' } }
+ 'data': { 'passthrough' : 'TPMPassthroughOptions',
+ 'emulator' : 'TPMEmulatorOptions' } }
##
# @TPMInfo:
diff --git a/qemu-options.hx b/qemu-options.hx
index 99af8ed..5bbf187 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2846,7 +2846,12 @@ DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \
"-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n"
" use path to provide path to a character device; default is /dev/tpm0\n"
" use cancel-path to provide path to TPM's cancel sysfs entry; if\n"
- " not provided it will be searched for in /sys/class/misc/tpm?/device\n",
+ " not provided it will be searched for in /sys/class/misc/tpm?/device\n"
+ "-tpmdev emulator,id=id,tpmstatedir=dir[,path=emulator-path,logfile=path,loglevel=level]\n"
+ " use tpmstatedir to provide path to the tpm state dirctory\n"
+ " use path to provide the emulator binary to launch; default is 'swtpm'\n"
+ " use logfile to provide where to place the swtpm logs\n"
+ " use loglevel to controls the swtpm log level\n",
QEMU_ARCH_ALL)
STEXI
@@ -2855,8 +2860,8 @@ The general form of a TPM device option is:
@item -tpmdev @var{backend} ,id=@var{id} [,@var{options}]
@findex -tpmdev
-Backend type must be:
-@option{passthrough}.
+Backend type must be either one of the following:
+@option{passthrough}, @option{emulator}.
The specific backend type will determine the applicable options.
The @code{-tpmdev} option creates the TPM backend and requires a
@@ -2906,6 +2911,20 @@ To create a passthrough TPM use the following two options:
Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by
@code{tpmdev=tpm0} in the device option.
+@item -tpmdev emulator, id=@var{id}, tpmstatedir=@var{path}, path=@var{emulator-binary-path}, logfile=@var{path}, logevel=@var{level}
+
+(Linux-host only) Enable access to a TPM emulator.
+
+@option{tpmstatedir} specifies the tpm state directory
+@option{path} specifies the emulator binary path to use
+@option{logfile} optional log file to use to place log messages
+@option{loglevel} specifies the log level to use
+
+To create a TPM emulator backend device:
+@example
+-tpmdev emulator,id=tpm0,tpmstatedir=/tmp/my-tpm,path=/usr/local/bin/swtpm,logfile=/tmp/qemu-tpm.log,logevel=5 -device tpm-tis,tpmdev=tpm0
+@end example
+
@end table
ETEXI
diff --git a/tpm.c b/tpm.c
index c221000..ed110d2 100644
--- a/tpm.c
+++ b/tpm.c
@@ -25,7 +25,7 @@ static QLIST_HEAD(, TPMBackend) tpm_backends =
#define TPM_MAX_MODELS 1
-#define TPM_MAX_DRIVERS 1
+#define TPM_MAX_DRIVERS 2
static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = {
NULL,
@@ -263,6 +263,11 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
res->options->u.passthrough.data =
(TPMPassthroughOptions *)tpm_backend_get_tpm_options(drv);
break;
+ case TPM_TYPE_EMULATOR:
+ res->options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR;
+ res->options->u.emulator.data =
+ (TPMEmulatorOptions *) tpm_backend_get_tpm_options(drv);
+ break;
case TPM_TYPE__MAX:
break;
}
--
2.7.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 7/7] Added support for TPM emulator
2017-03-31 13:10 ` [Qemu-devel] [PATCH 7/7] Added support for TPM emulator Amarnath Valluri
@ 2017-04-03 19:30 ` Eric Blake
0 siblings, 0 replies; 37+ messages in thread
From: Eric Blake @ 2017-04-03 19:30 UTC (permalink / raw)
To: Amarnath Valluri, qemu-devel; +Cc: patrick.ohly, stefanb
[-- Attachment #1: Type: text/plain, Size: 2951 bytes --]
On 03/31/2017 08:10 AM, Amarnath Valluri wrote:
> This change introduces a new TPM backend driver that can communicates with
> swtpm(software TPM emulator) using unix domain socket interface.
>
> Swtpm uses two unix sockets, one for plain TPM commands and responses, and one
> for out-of-band control messages.
>
> The swtpm and associated tools can be found here:
> https://github.com/stefanberger/swtpm
>
> Usage:
> # setup TPM state directory
> mkdir /tmp/mytpm
> chown -R tss:root /tmp/mytpm
> /usr/bin/swtpm_setup --tpm-state /tmp/mytpm --createek
>
> # Ask qeum to use TPM emulator with given tpm state directory
> qemu-system-x86_64 \
> [...] \
> -tpmdev emulator,id=tpm0,tpmstatedir=/tmp/mytpm,logfile=/tmp/swtpm.log \
> -device tpm-tis,tpmdev=tpm0 \
> [...]
>
> Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
> ---
Just an interface review for now:
> +++ b/qapi-schema.json
> @@ -5117,10 +5117,11 @@
> # An enumeration of TPM types
> #
> # @passthrough: TPM passthrough type
> +# @emulator: Software Emulator TPM type
Missing a '(since 2.10)' designator on @emulator
> #
> # Since: 1.5
> ##
> -{ 'enum': 'TpmType', 'data': [ 'passthrough' ] }
> +{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ] }
>
> ##
> # @query-tpm-types:
> @@ -5163,6 +5164,22 @@
> 'data': { '*path' : 'str', '*cancel-path' : 'str'} }
>
> ##
> +# @TPMEmulatorOptions:
> +#
> +# Information about the TPM emulator
> +#
> +# @tpmstatedir: TPM emilator state dir
s/emilator/emulator/
> +# @path: TPM emulator binary path to use
> +# @logfile: file to use to place TPM emulator logs
What's the default when logfile is omitted?
> +# @loglevel: log level number
What's the default, or even the valid range of values? Is a larger
number noisier?
> +#
> +# Since: 2.6
You've missed 2.6 by a long shot. We are now working on 2.10 interfaces.
> +##
> +{ 'struct': 'TPMEmulatorOptions', 'base': 'TPMOptions',
Okay, the base class you added in 5/7 makes a bit more sense now, even
if it remains empty. But then that means you need to update the commit
message to call it out as intentional that it is empty and a second
derived class will be added later.
> + 'data': { 'tpmstatedir' : 'str', '*path': 'str',
> + '*logfile' : 'str', '*loglevel' : 'int' } }
> +
> +##
> # @TpmTypeOptions:
> #
> # A union referencing different TPM backend types' configuration options
> @@ -5172,7 +5189,8 @@
> # Since: 1.5
> ##
> { 'union': 'TpmTypeOptions',
> - 'data': { 'passthrough' : 'TPMPassthroughOptions' } }
> + 'data': { 'passthrough' : 'TPMPassthroughOptions',
> + 'emulator' : 'TPMEmulatorOptions' } }
>
> ##
> # @TPMInfo:
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]
^ permalink raw reply [flat|nested] 37+ messages in thread
* [Qemu-devel] [PATCH 7/7] tpm: New backend driver to support TPM emulator
2017-03-31 13:10 [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator Amarnath Valluri
` (6 preceding siblings ...)
2017-03-31 13:10 ` [Qemu-devel] [PATCH 7/7] Added support for TPM emulator Amarnath Valluri
@ 2017-03-31 13:10 ` Amarnath Valluri
2017-04-04 16:23 ` Marc-André Lureau
2017-04-05 15:30 ` Daniel P. Berrange
2017-04-02 8:33 ` [Qemu-devel] [PATCH 0/7] Provide support for the software " no-reply
2017-04-03 17:07 ` Daniel P. Berrange
9 siblings, 2 replies; 37+ messages in thread
From: Amarnath Valluri @ 2017-03-31 13:10 UTC (permalink / raw)
To: qemu-devel; +Cc: stefanb, patrick.ohly, Amarnath Valluri
This change introduces a new TPM backend driver that can communicates with
swtpm(software TPM emulator) using unix domain socket interface.
Swtpm uses two unix sockets, one for plain TPM commands and responses, and one
for out-of-band control messages.
The swtpm and associated tools can be found here:
https://github.com/stefanberger/swtpm
Usage:
# setup TPM state directory
mkdir /tmp/mytpm
chown -R tss:root /tmp/mytpm
/usr/bin/swtpm_setup --tpm-state /tmp/mytpm --createek
# Ask qeum to use TPM emulator with given tpm state directory
qemu-system-x86_64 \
[...] \
-tpmdev emulator,id=tpm0,tpmstatedir=/tmp/mytpm,logfile=/tmp/swtpm.log \
-device tpm-tis,tpmdev=tpm0 \
[...]
Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
---
configure | 6 +
hmp.c | 14 +
hw/tpm/Makefile.objs | 1 +
hw/tpm/tpm_emulator.c | 740 ++++++++++++++++++++++++++++++++++++++++++++++++++
hw/tpm/tpm_ioctl.h | 243 +++++++++++++++++
hw/tpm/tpm_util.c | 34 +++
hw/tpm/tpm_util.h | 3 +
qapi-schema.json | 22 +-
qemu-options.hx | 25 +-
tpm.c | 7 +-
10 files changed, 1089 insertions(+), 6 deletions(-)
create mode 100644 hw/tpm/tpm_emulator.c
create mode 100644 hw/tpm/tpm_ioctl.h
diff --git a/configure b/configure
index 4901b9a..9089546 100755
--- a/configure
+++ b/configure
@@ -3349,8 +3349,10 @@ fi
if test "$targetos" = Linux && test "$cpu" = i386 -o "$cpu" = x86_64; then
tpm_passthrough=$tpm
+ tpm_emulator=$tpm
else
tpm_passthrough=no
+ tpm_emulator=no
fi
##########################################
@@ -5125,6 +5127,7 @@ echo "gcov enabled $gcov"
echo "TPM support $tpm"
echo "libssh2 support $libssh2"
echo "TPM passthrough $tpm_passthrough"
+echo "TPM emulator $tpm_emulator"
echo "QOM debugging $qom_cast_debug"
echo "lzo support $lzo"
echo "snappy support $snappy"
@@ -5704,6 +5707,9 @@ if test "$tpm" = "yes"; then
if test "$tpm_passthrough" = "yes"; then
echo "CONFIG_TPM_PASSTHROUGH=y" >> $config_host_mak
fi
+ if test "$tpm_emulator" = "yes"; then
+ echo "CONFIG_TPM_EMULATOR=y" >> $config_host_mak
+ fi
fi
echo "TRACE_BACKENDS=$trace_backends" >> $config_host_mak
diff --git a/hmp.c b/hmp.c
index edb8970..03a47e2 100644
--- a/hmp.c
+++ b/hmp.c
@@ -937,6 +937,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
Error *err = NULL;
unsigned int c = 0;
TPMPassthroughOptions *tpo;
+ TPMEmulatorOptions *teo;
info_list = qmp_query_tpm(&err);
if (err) {
@@ -966,6 +967,19 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
tpo->has_cancel_path ? ",cancel-path=" : "",
tpo->has_cancel_path ? tpo->cancel_path : "");
break;
+ case TPM_TYPE_OPTIONS_KIND_EMULATOR:
+ teo = ti->options->u.emulator.data;
+ monitor_printf(mon, ",tmpstatedir=%s", teo->tpmstatedir);
+ if (teo->has_path) {
+ monitor_printf(mon, ",path=%s", teo->path);
+ }
+ if (teo->has_logfile) {
+ monitor_printf(mon, ",logfile=%s", teo->logfile);
+ }
+ if (teo->has_loglevel) {
+ monitor_printf(mon, ",loglevel=%ld", teo->loglevel);
+ }
+ break;
case TPM_TYPE_OPTIONS_KIND__MAX:
break;
}
diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index 64cecc3..41f0b7a 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,2 +1,3 @@
common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o
+common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o tpm_util.o
diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c
new file mode 100644
index 0000000..5b1dcfa
--- /dev/null
+++ b/hw/tpm/tpm_emulator.c
@@ -0,0 +1,740 @@
+/*
+ * emulator TPM driver
+ *
+ * Copyright (c) 2017 Intel Corporation
+ * Author: Amarnath Valluri <amarnath.valluri@intel.com>
+ *
+ * Copyright (c) 2010 - 2013 IBM Corporation
+ * Authors:
+ * Stefan Berger <stefanb@us.ibm.com>
+ *
+ * Copyright (C) 2011 IAIK, Graz University of Technology
+ * Author: Andreas Niederl
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ *
+ * The origin of the code is from CUSE driver posed by Stefan Berger:
+ * https://github.com/stefanberger/qemu-tpm
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/error-report.h"
+#include "sysemu/tpm_backend.h"
+#include "tpm_int.h"
+#include "hw/hw.h"
+#include "hw/i386/pc.h"
+#include "sysemu/tpm_backend_int.h"
+#include "tpm_util.h"
+#include "tpm_ioctl.h"
+#include "qapi/error.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+
+#define DEBUG_TPM 0
+
+#define DPRINT(fmt, ...) do { \
+ if (DEBUG_TPM) { \
+ fprintf(stderr, fmt, ## __VA_ARGS__); \
+ } \
+} while (0);
+
+#define DPRINTF(fmt, ...) DPRINT(fmt"\n", __VA_ARGS__)
+
+#define TYPE_TPM_EMULATOR "emulator"
+#define TPM_EMULATOR(obj) \
+ OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)
+
+static const TPMDriverOps tpm_emulator_driver;
+
+/* data structures */
+typedef struct TPMEmulator {
+ TPMBackend parent;
+
+ TPMEmulatorOptions ops;
+ int tpm_fd;
+ int tpm_ctrl_fd;
+ bool op_executing;
+ bool op_canceled;
+ bool child_running;
+ TPMVersion tpm_version;
+ ptm_cap caps; /* capabilities of the TPM */
+ uint8_t cur_locty_number; /* last set locality */
+} TPMEmulator;
+
+#define TPM_DEFAULT_EMULATOR "swtpm"
+#define TPM_DEFAULT_LOGLEVEL 5
+#define TPM_EUMLATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) == (cap))
+
+static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_pt,
+ const uint8_t *in, uint32_t in_len,
+ uint8_t *out, uint32_t out_len,
+ bool *selftest_done)
+{
+ int ret;
+ bool is_selftest;
+ const struct tpm_resp_hdr *hdr;
+
+ if (!tpm_pt->child_running) {
+ return -1;
+ }
+
+ tpm_pt->op_canceled = false;
+ tpm_pt->op_executing = true;
+ *selftest_done = false;
+
+ is_selftest = tpm_util_is_selftest(in, in_len);
+
+ ret = tpm_util_unix_write(tpm_pt->tpm_fd, in, in_len);
+ if (ret != in_len) {
+ if (!tpm_pt->op_canceled || errno != ECANCELED) {
+ error_report("tpm_emulator: error while transmitting data "
+ "to TPM: %s (%i)", strerror(errno), errno);
+ }
+ goto err_exit;
+ }
+
+ tpm_pt->op_executing = false;
+
+ ret = tpm_util_unix_read(tpm_pt->tpm_fd, out, out_len);
+ if (ret < 0) {
+ if (!tpm_pt->op_canceled || errno != ECANCELED) {
+ error_report("tpm_emulator: error while reading data from "
+ "TPM: %s (%i)", strerror(errno), errno);
+ }
+ } else if (ret < sizeof(struct tpm_resp_hdr) ||
+ be32_to_cpu(((struct tpm_resp_hdr *)out)->len) != ret) {
+ ret = -1;
+ error_report("tpm_emulator: received invalid response "
+ "packet from TPM");
+ }
+
+ if (is_selftest && (ret >= sizeof(struct tpm_resp_hdr))) {
+ hdr = (struct tpm_resp_hdr *)out;
+ *selftest_done = (be32_to_cpu(hdr->errcode) == 0);
+ }
+
+err_exit:
+ if (ret < 0) {
+ tpm_util_write_fatal_error_response(out, out_len);
+ }
+
+ tpm_pt->op_executing = false;
+
+ return ret;
+}
+
+static int tpm_emulator_set_locality(TPMEmulator *tpm_pt,
+ uint8_t locty_number)
+{
+ ptm_loc loc;
+
+ if (!tpm_pt->child_running) {
+ return -1;
+ }
+
+ DPRINTF("tpm_emulator: %s : locality: 0x%x", __func__, locty_number);
+
+ if (tpm_pt->cur_locty_number != locty_number) {
+ DPRINTF("tpm-emulator: setting locality : 0x%x", locty_number);
+ loc.u.req.loc = cpu_to_be32(locty_number);
+ if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_SET_LOCALITY, &loc,
+ sizeof(loc), sizeof(loc)) < 0) {
+ error_report("tpm-emulator: could not set locality : %s",
+ strerror(errno));
+ return -1;
+ }
+ loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result);
+ if (loc.u.resp.tpm_result != 0) {
+ error_report("tpm-emulator: TPM result for set locality : 0x%x",
+ loc.u.resp.tpm_result);
+ return -1;
+ }
+ tpm_pt->cur_locty_number = locty_number;
+ }
+ return 0;
+}
+
+static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd cmd)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+ TPMLocality *locty = NULL;
+ bool selftest_done = false;
+
+ DPRINTF("tpm_emulator: processing command type %d", cmd);
+
+ switch (cmd) {
+ case TPM_BACKEND_CMD_PROCESS_CMD:
+ locty = tb->tpm_state->locty_data;
+ if (tpm_emulator_set_locality(tpm_pt,
+ tb->tpm_state->locty_number) < 0) {
+ tpm_util_write_fatal_error_response(locty->r_buffer.buffer,
+ locty->r_buffer.size);
+ } else {
+ tpm_emulator_unix_tx_bufs(tpm_pt, locty->w_buffer.buffer,
+ locty->w_offset, locty->r_buffer.buffer,
+ locty->r_buffer.size, &selftest_done);
+ }
+ tb->recv_data_callback(tb->tpm_state, tb->tpm_state->locty_number,
+ selftest_done);
+ break;
+ case TPM_BACKEND_CMD_INIT:
+ case TPM_BACKEND_CMD_END:
+ case TPM_BACKEND_CMD_TPM_RESET:
+ /* nothing to do */
+ break;
+ }
+}
+
+/*
+ * Gracefully shut down the external unixio TPM
+ */
+static void tpm_emulator_shutdown(TPMEmulator *tpm_pt)
+{
+ ptm_res res;
+
+ if (!tpm_pt->child_running) {
+ return;
+ }
+
+ if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_SHUTDOWN, &res, 0,
+ sizeof(res)) < 0) {
+ error_report("tpm-emulator: Could not cleanly shutdown the TPM: %s",
+ strerror(errno));
+ } else if (res != 0) {
+ error_report("tpm-emulator: TPM result for sutdown: 0x%x",
+ be32_to_cpu(res));
+ }
+}
+
+static int tpm_emulator_probe_caps(TPMEmulator *tpm_pt)
+{
+ if (!tpm_pt->child_running) {
+ return -1;
+ }
+
+ DPRINTF("tpm_emulator: %s", __func__);
+ if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_GET_CAPABILITY,
+ &tpm_pt->caps, 0, sizeof(tpm_pt->caps)) < 0) {
+ error_report("tpm-emulator: probing failed : %s", strerror(errno));
+ return -1;
+ }
+
+ tpm_pt->caps = be64_to_cpu(tpm_pt->caps);
+
+ DPRINTF("tpm-emulator: capbilities : 0x%lx", tpm_pt->caps);
+
+ return 0;
+}
+
+static int tpm_emulator_check_caps(TPMEmulator *tpm_pt)
+{
+ ptm_cap caps = 0;
+ const char *tpm = NULL;
+
+ /* check for min. required capabilities */
+ switch (tpm_pt->tpm_version) {
+ case TPM_VERSION_1_2:
+ caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
+ PTM_CAP_SET_LOCALITY;
+ tpm = "1.2";
+ break;
+ case TPM_VERSION_2_0:
+ caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
+ PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED;
+ tpm = "2";
+ break;
+ case TPM_VERSION_UNSPEC:
+ error_report("tpm-emulator: TPM version has not been set");
+ return -1;
+ }
+
+ if (!TPM_EUMLATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, caps)) {
+ error_report("tpm-emulator: TPM does not implement minimum set of "
+ "required capabilities for TPM %s (0x%x)", tpm, (int)caps);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int tpm_emulator_init_tpm(TPMEmulator *tpm_pt, bool is_resume)
+{
+ ptm_init init;
+ ptm_res res;
+
+ if (!tpm_pt->child_running) {
+ return -1;
+ }
+
+ DPRINTF("tpm_emulator: %s", __func__);
+ if (is_resume) {
+ init.u.req.init_flags = cpu_to_be32(PTM_INIT_FLAG_DELETE_VOLATILE);
+ }
+
+ if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_INIT, &init, sizeof(init),
+ sizeof(init)) < 0) {
+ error_report("tpm-emulator: could not send INIT: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ res = be32_to_cpu(init.u.resp.tpm_result);
+ if (res) {
+ error_report("tpm-emulator: TPM result for PTM_INIT: 0x%x", res);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int tpm_emulator_startup_tpm(TPMBackend *tb)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+
+ DPRINTF("tpm_emulator: %s", __func__);
+
+ tpm_emulator_init_tpm(tpm_pt, false) ;
+
+ return 0;
+}
+
+static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+ ptm_est est;
+
+ DPRINTF("tpm_emulator: %s", __func__);
+ if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_GET_TPMESTABLISHED, &est, 0,
+ sizeof(est)) < 0) {
+ error_report("tpm-emulator: Could not get the TPM established flag: %s",
+ strerror(errno));
+ return false;
+ }
+ DPRINTF("tpm_emulator: established flag: %0x", est.u.resp.bit);
+
+ return (est.u.resp.bit != 0);
+}
+
+static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,
+ uint8_t locty)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+ ptm_reset_est reset_est;
+ ptm_res res;
+
+ /* only a TPM 2.0 will support this */
+ if (tpm_pt->tpm_version == TPM_VERSION_2_0) {
+ reset_est.u.req.loc = cpu_to_be32(tpm_pt->cur_locty_number);
+
+ if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_RESET_TPMESTABLISHED,
+ &reset_est, sizeof(reset_est),
+ sizeof(reset_est)) < 0) {
+ error_report("tpm-emulator: Could not reset the establishment bit: "
+ "%s", strerror(errno));
+ return -1;
+ }
+
+ res = be32_to_cpu(reset_est.u.resp.tpm_result);
+ if (res) {
+ error_report("tpm-emulator: TPM result for rest establixhed flag: "
+ "0x%x", res);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static bool tpm_emulator_get_startup_error(TPMBackend *tb)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+
+ return !tpm_pt->child_running;
+}
+
+static size_t tpm_emulator_realloc_buffer(TPMSizedBuffer *sb)
+{
+ size_t wanted_size = 4096; /* Linux tpm.c buffer size */
+
+ if (sb->size != wanted_size) {
+ sb->buffer = g_realloc(sb->buffer, wanted_size);
+ sb->size = wanted_size;
+ }
+ return sb->size;
+}
+
+static void tpm_emulator_cancel_cmd(TPMBackend *tb)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+ ptm_res res;
+
+ /*
+ * As of Linux 3.7 the tpm_tis driver does not properly cancel
+ * commands on all TPM manufacturers' TPMs.
+ * Only cancel if we're busy so we don't cancel someone else's
+ * command, e.g., a command executed on the host.
+ */
+ if (tpm_pt->op_executing) {
+ if (TPM_EUMLATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, PTM_CAP_CANCEL_TPM_CMD)) {
+ if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_CANCEL_TPM_CMD, &res,
+ 0, sizeof(res)) < 0) {
+ error_report("tpm-emulator: Could not cancel command: %s",
+ strerror(errno));
+ } else if (res != 0) {
+ error_report("tpm-emulator: Failed to cancel TPM: 0x%x",
+ be32_to_cpu(res));
+ } else {
+ tpm_pt->op_canceled = true;
+ }
+ }
+ }
+}
+
+static void tpm_emulator_reset(TPMBackend *tb)
+{
+ DPRINTF("tpm_emulator: %s", __func__);
+
+ tpm_emulator_cancel_cmd(tb);
+}
+
+static const char *tpm_emulator_desc(void)
+{
+ return "TPM emulator backend driver";
+}
+
+static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+
+ return tpm_pt->tpm_version;
+}
+
+static void tpm_emulator_fd_handler(void *opaque)
+{
+ TPMEmulator *tpm_pt = opaque;
+ char val = 0;
+ ssize_t size;
+
+ qemu_set_fd_handler(tpm_pt->tpm_fd, NULL, NULL, NULL);
+
+ size = qemu_recv(tpm_pt->tpm_fd, &val, 1, MSG_PEEK);
+ if (!size) {
+ error_report("TPM backend disappeared");
+ tpm_pt->child_running = false;
+ } else {
+ DPRINT("tpm-emulator: unexpected data on TPM\n");
+ }
+}
+
+static int tpm_emulator_spawn_emulator(TPMEmulator *tpm_pt)
+{
+ int fds[2];
+ int ctrl_fds[2];
+ pid_t cpid;
+
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) < 0) {
+ return -1;
+ }
+
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ctrl_fds) < 0) {
+ closesocket(fds[0]);
+ closesocket(fds[1]);
+ return -1;
+ }
+
+ cpid = fork();
+ if (cpid < 0) {
+ error_report("tpm-emulator: Fork failure: %s", strerror(errno));
+ closesocket(fds[0]); closesocket(fds[1]);
+ closesocket(ctrl_fds[0]); closesocket(ctrl_fds[1]);
+ return -1;
+ }
+
+ if (cpid == 0) { /* CHILD */
+ int i;
+ char fd_str[128] = "";
+ char ctrl_fd_str[128] = "";
+ char tpmstate_str[1024] = "";
+ char log_str[1024] = "";
+ const char *params[] = {
+ tpm_pt->ops.path, "socket",
+ "--fd", fd_str,
+ "--ctrl", ctrl_fd_str,
+ "--tpmstate", tpmstate_str,
+ "--log", log_str,
+ NULL /* End */
+ };
+
+ /* close all unused inherited sockets */
+ closesocket(fds[0]);
+ closesocket(ctrl_fds[0]);
+ for (i = STDERR_FILENO + 1; i < fds[1]; i++) {
+ closesocket(i);
+ }
+
+ sprintf(fd_str, "%d", fds[1]);
+ sprintf(ctrl_fd_str, "type=unixio,clientfd=%d", ctrl_fds[1]);
+ sprintf(tpmstate_str, "dir=%s", tpm_pt->ops.tpmstatedir);
+ if (tpm_pt->ops.has_logfile) {
+ sprintf(log_str, "file=%s,level=%d", tpm_pt->ops.logfile,
+ (int)tpm_pt->ops.loglevel);
+ } else {
+ /* truncate logs */
+ params[8] = NULL;
+ }
+ DPRINT("Running cmd: ")
+ for (i = 0; params[i]; i++) {
+ DPRINT(" %s", params[i])
+ }
+ DPRINT("\n")
+ if (execv(tpm_pt->ops.path, (char * const *)params) < 0) {
+ error_report("execv() failure : %s", strerror(errno));
+ }
+ closesocket(fds[1]);
+ closesocket(ctrl_fds[1]);
+ exit(0);
+ } else { /* self */
+ DPRINTF("tpm-emulator: child pid: %d", cpid);
+ /* FIXME: find better way of finding swtpm ready
+ maybe write 'ready'bit on socket ?
+ give some time to child to get ready */
+ sleep(1);
+
+ tpm_pt->tpm_fd = fds[0];
+ tpm_pt->tpm_ctrl_fd = ctrl_fds[0];
+ tpm_pt->child_running = true;
+
+ qemu_add_child_watch(cpid);
+
+ fcntl(tpm_pt->tpm_fd, F_SETFL, O_NONBLOCK);
+ qemu_set_fd_handler(tpm_pt->tpm_fd, tpm_emulator_fd_handler, NULL,
+ tpm_pt);
+
+ /* close unsed sockets */
+ closesocket(fds[1]);
+ closesocket(ctrl_fds[1]);
+ }
+
+ return 0;
+}
+
+static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_pt, QemuOpts *opts)
+{
+ const char *value;
+
+ value = qemu_opt_get(opts, "tpmstatedir");
+ if (!value) {
+ error_report("tpm-emulator: Missing tpm state directory");
+ return -1;
+ }
+ tpm_pt->ops.tpmstatedir = g_strdup(value);
+
+ value = qemu_opt_get(opts, "path");
+ if (!value) {
+ value = TPM_DEFAULT_EMULATOR;
+ tpm_pt->ops.has_path = false;
+ } else {
+ tpm_pt->ops.has_path = true;
+ if (value[0] == '/') {
+ struct stat st;
+ if (stat(value, &st) < 0 || !(S_ISREG(st.st_mode)
+ || S_ISLNK(st.st_mode))) {
+ error_report("tpm-emulator: Invalid emulator path: %s", value);
+ return -1;
+ }
+ }
+ }
+ tpm_pt->ops.path = g_strdup(value);
+
+ value = qemu_opt_get(opts, "logfile");
+ if (value) {
+ DPRINTF("tpm-emulator: LogFile: %s", value);
+ tpm_pt->ops.has_logfile = true;
+ tpm_pt->ops.logfile = g_strdup(value);
+ tpm_pt->ops.loglevel = qemu_opt_get_number(opts, "loglevel",
+ TPM_DEFAULT_LOGLEVEL);
+ tpm_pt->ops.has_loglevel = tpm_pt->ops.loglevel !=
+ TPM_DEFAULT_LOGLEVEL;
+ }
+
+ if (tpm_emulator_spawn_emulator(tpm_pt) < 0) {
+ goto err_close_dev;
+ }
+
+ tpm_pt->cur_locty_number = ~0;
+
+ if (tpm_emulator_probe_caps(tpm_pt) ||
+ tpm_emulator_init_tpm(tpm_pt, false)) {
+ goto err_close_dev;
+ }
+
+ if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) {
+ error_report("'%s' is not emulating TPM device.", tpm_pt->ops.path);
+ goto err_close_dev;
+ }
+
+ DPRINTF("tpm_emulator: TPM Version %s",
+ tpm_pt->tpm_version == TPM_VERSION_1_2 ? "1.2" :
+ (tpm_pt->tpm_version == TPM_VERSION_2_0 ? "2.0" : "Unspecified"));
+
+ if (tpm_emulator_check_caps(tpm_pt)) {
+ goto err_close_dev;
+ }
+
+ return 0;
+
+err_close_dev:
+ tpm_emulator_shutdown(tpm_pt);
+ return -1;
+}
+
+static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id)
+{
+ TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
+
+ tb->id = g_strdup(id);
+
+ if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {
+ goto err_exit;
+ }
+
+ return tb;
+
+err_exit:
+ object_unref(OBJECT(tb));
+
+ return NULL;
+}
+
+static void tpm_emulator_destroy(TPMBackend *tb)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+
+ DPRINTF("tpm_emulator: %s", __func__);
+
+ tpm_emulator_cancel_cmd(tb);
+ tpm_emulator_shutdown(tpm_pt);
+
+ closesocket(tpm_pt->tpm_fd);
+ closesocket(tpm_pt->tpm_ctrl_fd);
+ g_free(tpm_pt->ops.tpmstatedir);
+ g_free(tpm_pt->ops.path);
+ g_free(tpm_pt->ops.logfile);
+}
+
+static TPMOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
+ TPMEmulatorOptions *ops = g_new(TPMEmulatorOptions, 1);
+
+ if (!ops) {
+ return NULL;
+ }
+ DPRINTF("tpm_emulator: %s", __func__);
+
+ ops->tpmstatedir = g_strdup(tpm_pt->ops.tpmstatedir);
+ if (tpm_pt->ops.has_path) {
+ ops->has_path = true;
+ ops->path = g_strdup(tpm_pt->ops.path);
+ }
+ if (tpm_pt->ops.has_logfile) {
+ ops->has_logfile = true;
+ ops->logfile = g_strdup(tpm_pt->ops.logfile);
+ }
+ if (tpm_pt->ops.has_loglevel) {
+ ops->has_loglevel = true;
+ ops->loglevel = tpm_pt->ops.loglevel;
+ }
+
+ return (TPMOptions *)ops;
+}
+
+static const QemuOptDesc tpm_emulator_cmdline_opts[] = {
+ TPM_STANDARD_CMDLINE_OPTS,
+ {
+ .name = "tpmstatedir",
+ .type = QEMU_OPT_STRING,
+ .help = "TPM state directroy",
+ },
+ {
+ .name = "path",
+ .type = QEMU_OPT_STRING,
+ .help = "Path to TPM emulator binary",
+ },
+ {
+ .name = "logfile",
+ .type = QEMU_OPT_STRING,
+ .help = "Path to log file",
+ },
+ {
+ .name = "level",
+ .type = QEMU_OPT_STRING,
+ .help = "Log level number",
+ },
+ { /* end of list */ },
+};
+
+static const TPMDriverOps tpm_emulator_driver = {
+ .type = TPM_TYPE_EMULATOR,
+ .opts = tpm_emulator_cmdline_opts,
+ .desc = tpm_emulator_desc,
+ .create = tpm_emulator_create,
+ .destroy = tpm_emulator_destroy,
+ .startup_tpm = tpm_emulator_startup_tpm,
+ .realloc_buffer = tpm_emulator_realloc_buffer,
+ .reset = tpm_emulator_reset,
+ .had_startup_error = tpm_emulator_get_startup_error,
+ .cancel_cmd = tpm_emulator_cancel_cmd,
+ .get_tpm_established_flag = tpm_emulator_get_tpm_established_flag,
+ .reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag,
+ .get_tpm_version = tpm_emulator_get_tpm_version,
+ .get_tpm_options = tpm_emulator_get_tpm_options,
+};
+
+static void tpm_emulator_inst_init(Object *obj)
+{
+ TPMEmulator *tpm_pt = TPM_EMULATOR(obj);
+
+ DPRINTF("tpm_emulator: %s", __func__);
+ tpm_pt->tpm_fd = tpm_pt->tpm_ctrl_fd = -1;
+ tpm_pt->op_executing = tpm_pt->op_canceled = false;
+ tpm_pt->child_running = false;
+ tpm_pt->cur_locty_number = ~0;
+}
+
+static void tpm_emulator_class_init(ObjectClass *klass, void *data)
+{
+ TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
+ tbc->ops = &tpm_emulator_driver;
+ tbc->handle_request = tpm_emulator_handle_request;
+}
+
+static const TypeInfo tpm_emulator_info = {
+ .name = TYPE_TPM_EMULATOR,
+ .parent = TYPE_TPM_BACKEND,
+ .instance_size = sizeof(TPMEmulator),
+ .class_init = tpm_emulator_class_init,
+ .instance_init = tpm_emulator_inst_init,
+};
+
+static void tpm_emulator_register(void)
+{
+ type_register_static(&tpm_emulator_info);
+ tpm_register_driver(&tpm_emulator_driver);
+}
+
+type_init(tpm_emulator_register)
diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h
new file mode 100644
index 0000000..af49708
--- /dev/null
+++ b/hw/tpm/tpm_ioctl.h
@@ -0,0 +1,243 @@
+/*
+ * tpm_ioctl.h
+ *
+ * (c) Copyright IBM Corporation 2014, 2015.
+ *
+ * This file is licensed under the terms of the 3-clause BSD license
+ */
+#ifndef _TPM_IOCTL_H_
+#define _TPM_IOCTL_H_
+
+#include <stdint.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+/*
+ * Every response from a command involving a TPM command execution must hold
+ * the ptm_res as the first element.
+ * ptm_res corresponds to the error code of a command executed by the TPM.
+ */
+
+typedef uint32_t ptm_res;
+
+/* PTM_GET_TPMESTABLISHED: get the establishment bit */
+struct ptm_est {
+ union {
+ struct {
+ ptm_res tpm_result;
+ unsigned char bit; /* TPM established bit */
+ } resp; /* response */
+ } u;
+};
+
+/* PTM_RESET_TPMESTABLISHED: reset establishment bit */
+struct ptm_reset_est {
+ union {
+ struct {
+ uint8_t loc; /* locality to use */
+ } req; /* request */
+ struct {
+ ptm_res tpm_result;
+ } resp; /* response */
+ } u;
+};
+
+/* PTM_INIT */
+struct ptm_init {
+ union {
+ struct {
+ uint32_t init_flags; /* see definitions below */
+ } req; /* request */
+ struct {
+ ptm_res tpm_result;
+ } resp; /* response */
+ } u;
+};
+
+/* above init_flags */
+#define PTM_INIT_FLAG_DELETE_VOLATILE (1 << 0)
+ /* delete volatile state file after reading it */
+
+/* PTM_SET_LOCALITY */
+struct ptm_loc {
+ union {
+ struct {
+ uint8_t loc; /* locality to set */
+ } req; /* request */
+ struct {
+ ptm_res tpm_result;
+ } resp; /* response */
+ } u;
+};
+
+/* PTM_HASH_DATA: hash given data */
+struct ptm_hdata {
+ union {
+ struct {
+ uint32_t length;
+ uint8_t data[4096];
+ } req; /* request */
+ struct {
+ ptm_res tpm_result;
+ } resp; /* response */
+ } u;
+};
+
+/*
+ * size of the TPM state blob to transfer; x86_64 can handle 8k,
+ * ppc64le only ~7k; keep the response below a 4k page size
+ */
+#define PTM_STATE_BLOB_SIZE (3 * 1024)
+
+/*
+ * The following is the data structure to get state blobs from the TPM.
+ * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple reads
+ * with this ioctl and with adjusted offset are necessary. All bytes
+ * must be transferred and the transfer is done once the last byte has been
+ * returned.
+ * It is possible to use the read() interface for reading the data; however, the
+ * first bytes of the state blob will be part of the response to the ioctl(); a
+ * subsequent read() is only necessary if the total length (totlength) exceeds
+ * the number of received bytes. seek() is not supported.
+ */
+struct ptm_getstate {
+ union {
+ struct {
+ uint32_t state_flags; /* may be: PTM_STATE_FLAG_DECRYPTED */
+ uint32_t type; /* which blob to pull */
+ uint32_t offset; /* offset from where to read */
+ } req; /* request */
+ struct {
+ ptm_res tpm_result;
+ uint32_t state_flags; /* may be: PTM_STATE_FLAG_ENCRYPTED */
+ uint32_t totlength; /* total length that will be transferred */
+ uint32_t length; /* number of bytes in following buffer */
+ uint8_t data[PTM_STATE_BLOB_SIZE];
+ } resp; /* response */
+ } u;
+};
+
+/* TPM state blob types */
+#define PTM_BLOB_TYPE_PERMANENT 1
+#define PTM_BLOB_TYPE_VOLATILE 2
+#define PTM_BLOB_TYPE_SAVESTATE 3
+
+/* state_flags above : */
+#define PTM_STATE_FLAG_DECRYPTED 1 /* on input: get decrypted state */
+#define PTM_STATE_FLAG_ENCRYPTED 2 /* on output: state is encrypted */
+
+/*
+ * The following is the data structure to set state blobs in the TPM.
+ * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple
+ * 'writes' using this ioctl are necessary. The last packet is indicated
+ * by the length being smaller than the PTM_STATE_BLOB_SIZE.
+ * The very first packet may have a length indicator of '0' enabling
+ * a write() with all the bytes from a buffer. If the write() interface
+ * is used, a final ioctl with a non-full buffer must be made to indicate
+ * that all data were transferred (a write with 0 bytes would not work).
+ */
+struct ptm_setstate {
+ union {
+ struct {
+ uint32_t state_flags; /* may be PTM_STATE_FLAG_ENCRYPTED */
+ uint32_t type; /* which blob to set */
+ uint32_t length; /* length of the data;
+ use 0 on the first packet to
+ transfer using write() */
+ uint8_t data[PTM_STATE_BLOB_SIZE];
+ } req; /* request */
+ struct {
+ ptm_res tpm_result;
+ } resp; /* response */
+ } u;
+};
+
+/*
+ * PTM_GET_CONFIG: Data structure to get runtime configuration information
+ * such as which keys are applied.
+ */
+struct ptm_getconfig {
+ union {
+ struct {
+ ptm_res tpm_result;
+ uint32_t flags;
+ } resp; /* response */
+ } u;
+};
+
+#define PTM_CONFIG_FLAG_FILE_KEY 0x1
+#define PTM_CONFIG_FLAG_MIGRATION_KEY 0x2
+
+
+typedef uint64_t ptm_cap;
+typedef struct ptm_est ptm_est;
+typedef struct ptm_reset_est ptm_reset_est;
+typedef struct ptm_loc ptm_loc;
+typedef struct ptm_hdata ptm_hdata;
+typedef struct ptm_init ptm_init;
+typedef struct ptm_getstate ptm_getstate;
+typedef struct ptm_setstate ptm_setstate;
+typedef struct ptm_getconfig ptm_getconfig;
+
+/* capability flags returned by PTM_GET_CAPABILITY */
+#define PTM_CAP_INIT (1)
+#define PTM_CAP_SHUTDOWN (1 << 1)
+#define PTM_CAP_GET_TPMESTABLISHED (1 << 2)
+#define PTM_CAP_SET_LOCALITY (1 << 3)
+#define PTM_CAP_HASHING (1 << 4)
+#define PTM_CAP_CANCEL_TPM_CMD (1 << 5)
+#define PTM_CAP_STORE_VOLATILE (1 << 6)
+#define PTM_CAP_RESET_TPMESTABLISHED (1 << 7)
+#define PTM_CAP_GET_STATEBLOB (1 << 8)
+#define PTM_CAP_SET_STATEBLOB (1 << 9)
+#define PTM_CAP_STOP (1 << 10)
+#define PTM_CAP_GET_CONFIG (1 << 11)
+
+enum {
+ PTM_GET_CAPABILITY = _IOR('P', 0, ptm_cap),
+ PTM_INIT = _IOWR('P', 1, ptm_init),
+ PTM_SHUTDOWN = _IOR('P', 2, ptm_res),
+ PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptm_est),
+ PTM_SET_LOCALITY = _IOWR('P', 4, ptm_loc),
+ PTM_HASH_START = _IOR('P', 5, ptm_res),
+ PTM_HASH_DATA = _IOWR('P', 6, ptm_hdata),
+ PTM_HASH_END = _IOR('P', 7, ptm_res),
+ PTM_CANCEL_TPM_CMD = _IOR('P', 8, ptm_res),
+ PTM_STORE_VOLATILE = _IOR('P', 9, ptm_res),
+ PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptm_reset_est),
+ PTM_GET_STATEBLOB = _IOWR('P', 11, ptm_getstate),
+ PTM_SET_STATEBLOB = _IOWR('P', 12, ptm_setstate),
+ PTM_STOP = _IOR('P', 13, ptm_res),
+ PTM_GET_CONFIG = _IOR('P', 14, ptm_getconfig),
+};
+
+/*
+ * Commands used by the non-CUSE TPMs
+ *
+ * All messages container big-endian data.
+ *
+ * The return messages only contain the 'resp' part of the unions
+ * in the data structures above. Besides that the limits in the
+ * buffers above (ptm_hdata:u.req.data and ptm_get_state:u.resp.data
+ * and ptm_set_state:u.req.data) are 0xffffffff.
+ */
+enum {
+ CMD_GET_CAPABILITY = 1,
+ CMD_INIT,
+ CMD_SHUTDOWN,
+ CMD_GET_TPMESTABLISHED,
+ CMD_SET_LOCALITY,
+ CMD_HASH_START,
+ CMD_HASH_DATA,
+ CMD_HASH_END,
+ CMD_CANCEL_TPM_CMD,
+ CMD_STORE_VOLATILE,
+ CMD_RESET_TPMESTABLISHED,
+ CMD_GET_STATEBLOB,
+ CMD_SET_STATEBLOB,
+ CMD_STOP,
+ CMD_GET_CONFIG,
+};
+
+#endif /* _TPM_IOCTL_H */
diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c
index 5475acf..34b1d59 100644
--- a/hw/tpm/tpm_util.c
+++ b/hw/tpm/tpm_util.c
@@ -22,6 +22,7 @@
#include "qemu/osdep.h"
#include "tpm_util.h"
#include "tpm_int.h"
+#include "tpm_ioctl.h"
int tpm_util_unix_write(int fd, const uint8_t *buf, uint32_t len)
{
@@ -185,3 +186,36 @@ int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version)
return 1;
}
+
+static unsigned long ioctl_to_cmd(unsigned long ioctlnum)
+{
+ /* the ioctl number contains the command number - 1 */
+ return ((ioctlnum >> _IOC_NRSHIFT) & _IOC_NRMASK) + 1;
+}
+
+int tpm_util_ctrlcmd(int fd, unsigned long cmd, void *msg, size_t msg_len_in,
+ size_t msg_len_out)
+{
+ int n;
+
+ uint32_t cmd_no = cpu_to_be32(ioctl_to_cmd(cmd));
+ struct iovec iov[2] = {
+ { .iov_base = &cmd_no, .iov_len = sizeof(cmd_no), },
+ { .iov_base = msg, .iov_len = msg_len_in, },
+ };
+
+ n = writev(fd, iov, 2);
+ if (n > 0) {
+ if (msg_len_out > 0) {
+ n = read(fd, msg, msg_len_out);
+ /* simulate ioctl return value */
+ if (n > 0) {
+ n = 0;
+ }
+ } else {
+ n = 0;
+ }
+ }
+ return n;
+}
+
diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h
index c2feca7..b93d484 100644
--- a/hw/tpm/tpm_util.h
+++ b/hw/tpm/tpm_util.h
@@ -34,4 +34,7 @@ bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len);
int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version);
+int tpm_util_ctrlcmd(int fd, unsigned long cmd, void *msg,
+ size_t msg_len_in, size_t msg_len_out);
+
#endif /* TPM_TPM_UTIL_H */
diff --git a/qapi-schema.json b/qapi-schema.json
index 5faf1ac..e8ddbc6 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -5117,10 +5117,11 @@
# An enumeration of TPM types
#
# @passthrough: TPM passthrough type
+# @emulator: Software Emulator TPM type
#
# Since: 1.5
##
-{ 'enum': 'TpmType', 'data': [ 'passthrough' ] }
+{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ] }
##
# @query-tpm-types:
@@ -5163,6 +5164,22 @@
'data': { '*path' : 'str', '*cancel-path' : 'str'} }
##
+# @TPMEmulatorOptions:
+#
+# Information about the TPM emulator
+#
+# @tpmstatedir: TPM emilator state dir
+# @path: TPM emulator binary path to use
+# @logfile: file to use to place TPM emulator logs
+# @loglevel: log level number
+#
+# Since: 2.6
+##
+{ 'struct': 'TPMEmulatorOptions', 'base': 'TPMOptions',
+ 'data': { 'tpmstatedir' : 'str', '*path': 'str',
+ '*logfile' : 'str', '*loglevel' : 'int' } }
+
+##
# @TpmTypeOptions:
#
# A union referencing different TPM backend types' configuration options
@@ -5172,7 +5189,8 @@
# Since: 1.5
##
{ 'union': 'TpmTypeOptions',
- 'data': { 'passthrough' : 'TPMPassthroughOptions' } }
+ 'data': { 'passthrough' : 'TPMPassthroughOptions',
+ 'emulator' : 'TPMEmulatorOptions' } }
##
# @TPMInfo:
diff --git a/qemu-options.hx b/qemu-options.hx
index 99af8ed..5bbf187 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2846,7 +2846,12 @@ DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \
"-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n"
" use path to provide path to a character device; default is /dev/tpm0\n"
" use cancel-path to provide path to TPM's cancel sysfs entry; if\n"
- " not provided it will be searched for in /sys/class/misc/tpm?/device\n",
+ " not provided it will be searched for in /sys/class/misc/tpm?/device\n"
+ "-tpmdev emulator,id=id,tpmstatedir=dir[,path=emulator-path,logfile=path,loglevel=level]\n"
+ " use tpmstatedir to provide path to the tpm state dirctory\n"
+ " use path to provide the emulator binary to launch; default is 'swtpm'\n"
+ " use logfile to provide where to place the swtpm logs\n"
+ " use loglevel to controls the swtpm log level\n",
QEMU_ARCH_ALL)
STEXI
@@ -2855,8 +2860,8 @@ The general form of a TPM device option is:
@item -tpmdev @var{backend} ,id=@var{id} [,@var{options}]
@findex -tpmdev
-Backend type must be:
-@option{passthrough}.
+Backend type must be either one of the following:
+@option{passthrough}, @option{emulator}.
The specific backend type will determine the applicable options.
The @code{-tpmdev} option creates the TPM backend and requires a
@@ -2906,6 +2911,20 @@ To create a passthrough TPM use the following two options:
Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by
@code{tpmdev=tpm0} in the device option.
+@item -tpmdev emulator, id=@var{id}, tpmstatedir=@var{path}, path=@var{emulator-binary-path}, logfile=@var{path}, logevel=@var{level}
+
+(Linux-host only) Enable access to a TPM emulator.
+
+@option{tpmstatedir} specifies the tpm state directory
+@option{path} specifies the emulator binary path to use
+@option{logfile} optional log file to use to place log messages
+@option{loglevel} specifies the log level to use
+
+To create a TPM emulator backend device:
+@example
+-tpmdev emulator,id=tpm0,tpmstatedir=/tmp/my-tpm,path=/usr/local/bin/swtpm,logfile=/tmp/qemu-tpm.log,logevel=5 -device tpm-tis,tpmdev=tpm0
+@end example
+
@end table
ETEXI
diff --git a/tpm.c b/tpm.c
index c221000..ed110d2 100644
--- a/tpm.c
+++ b/tpm.c
@@ -25,7 +25,7 @@ static QLIST_HEAD(, TPMBackend) tpm_backends =
#define TPM_MAX_MODELS 1
-#define TPM_MAX_DRIVERS 1
+#define TPM_MAX_DRIVERS 2
static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = {
NULL,
@@ -263,6 +263,11 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
res->options->u.passthrough.data =
(TPMPassthroughOptions *)tpm_backend_get_tpm_options(drv);
break;
+ case TPM_TYPE_EMULATOR:
+ res->options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR;
+ res->options->u.emulator.data =
+ (TPMEmulatorOptions *) tpm_backend_get_tpm_options(drv);
+ break;
case TPM_TYPE__MAX:
break;
}
--
2.7.4
^ permalink raw reply related [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 7/7] tpm: New backend driver to support TPM emulator
2017-03-31 13:10 ` [Qemu-devel] [PATCH 7/7] tpm: New backend driver to support " Amarnath Valluri
@ 2017-04-04 16:23 ` Marc-André Lureau
2017-04-05 15:30 ` Daniel P. Berrange
1 sibling, 0 replies; 37+ messages in thread
From: Marc-André Lureau @ 2017-04-04 16:23 UTC (permalink / raw)
To: Amarnath Valluri, qemu-devel; +Cc: patrick.ohly, stefanb
Hi
(just a quick review, there will be more once the design discussion is over)
On Fri, Mar 31, 2017 at 5:03 PM Amarnath Valluri <amarnath.valluri@intel.com>
wrote:
> This change introduces a new TPM backend driver that can communicates with
>
communicate
> swtpm(software TPM emulator) using unix domain socket interface.
>
> Swtpm uses two unix sockets, one for plain TPM commands and responses, and
> one
> for out-of-band control messages.
>
>
Is the protocol documented? what's the reason to use 2 sockets?
> The swtpm and associated tools can be found here:
> https://github.com/stefanberger/swtpm
>
> Usage:
> # setup TPM state directory
> mkdir /tmp/mytpm
> chown -R tss:root /tmp/mytpm
> /usr/bin/swtpm_setup --tpm-state /tmp/mytpm --createek
>
> # Ask qeum to use TPM emulator with given tpm state directory
>
qemu
> qemu-system-x86_64 \
> [...] \
> -tpmdev
> emulator,id=tpm0,tpmstatedir=/tmp/mytpm,logfile=/tmp/swtpm.log \
> -device tpm-tis,tpmdev=tpm0 \
> [...]
>
> Signed-off-by: Amarnath Valluri <amarnath.valluri@intel.com>
> ---
> configure | 6 +
> hmp.c | 14 +
> hw/tpm/Makefile.objs | 1 +
> hw/tpm/tpm_emulator.c | 740
> ++++++++++++++++++++++++++++++++++++++++++++++++++
> hw/tpm/tpm_ioctl.h | 243 +++++++++++++++++
> hw/tpm/tpm_util.c | 34 +++
> hw/tpm/tpm_util.h | 3 +
> qapi-schema.json | 22 +-
> qemu-options.hx | 25 +-
> tpm.c | 7 +-
> 10 files changed, 1089 insertions(+), 6 deletions(-)
> create mode 100644 hw/tpm/tpm_emulator.c
> create mode 100644 hw/tpm/tpm_ioctl.h
>
> diff --git a/configure b/configure
> index 4901b9a..9089546 100755
> --- a/configure
> +++ b/configure
> @@ -3349,8 +3349,10 @@ fi
>
> if test "$targetos" = Linux && test "$cpu" = i386 -o "$cpu" = x86_64; then
> tpm_passthrough=$tpm
> + tpm_emulator=$tpm
>
What is the restriction to x86 & linux? I suppose it should work on various
unix.
> else
> tpm_passthrough=no
> + tpm_emulator=no
> fi
>
> ##########################################
> @@ -5125,6 +5127,7 @@ echo "gcov enabled $gcov"
> echo "TPM support $tpm"
> echo "libssh2 support $libssh2"
> echo "TPM passthrough $tpm_passthrough"
> +echo "TPM emulator $tpm_emulator"
> echo "QOM debugging $qom_cast_debug"
> echo "lzo support $lzo"
> echo "snappy support $snappy"
> @@ -5704,6 +5707,9 @@ if test "$tpm" = "yes"; then
> if test "$tpm_passthrough" = "yes"; then
> echo "CONFIG_TPM_PASSTHROUGH=y" >> $config_host_mak
> fi
> + if test "$tpm_emulator" = "yes"; then
> + echo "CONFIG_TPM_EMULATOR=y" >> $config_host_mak
> + fi
> fi
>
> echo "TRACE_BACKENDS=$trace_backends" >> $config_host_mak
> diff --git a/hmp.c b/hmp.c
> index edb8970..03a47e2 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -937,6 +937,7 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
> Error *err = NULL;
> unsigned int c = 0;
> TPMPassthroughOptions *tpo;
> + TPMEmulatorOptions *teo;
>
> info_list = qmp_query_tpm(&err);
> if (err) {
> @@ -966,6 +967,19 @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict)
> tpo->has_cancel_path ? ",cancel-path=" : "",
> tpo->has_cancel_path ? tpo->cancel_path : "");
> break;
> + case TPM_TYPE_OPTIONS_KIND_EMULATOR:
> + teo = ti->options->u.emulator.data;
> + monitor_printf(mon, ",tmpstatedir=%s", teo->tpmstatedir);
> + if (teo->has_path) {
> + monitor_printf(mon, ",path=%s", teo->path);
> + }
> + if (teo->has_logfile) {
> + monitor_printf(mon, ",logfile=%s", teo->logfile);
> + }
> + if (teo->has_loglevel) {
> + monitor_printf(mon, ",loglevel=%ld", teo->loglevel);
> + }
> + break;
> case TPM_TYPE_OPTIONS_KIND__MAX:
> break;
> }
> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
> index 64cecc3..41f0b7a 100644
> --- a/hw/tpm/Makefile.objs
> +++ b/hw/tpm/Makefile.objs
> @@ -1,2 +1,3 @@
> common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
> common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o tpm_util.o
> +common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o tpm_util.o
> diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c
> new file mode 100644
> index 0000000..5b1dcfa
> --- /dev/null
> +++ b/hw/tpm/tpm_emulator.c
> @@ -0,0 +1,740 @@
> +/*
> + * emulator TPM driver
> + *
> + * Copyright (c) 2017 Intel Corporation
> + * Author: Amarnath Valluri <amarnath.valluri@intel.com>
> + *
> + * Copyright (c) 2010 - 2013 IBM Corporation
> + * Authors:
> + * Stefan Berger <stefanb@us.ibm.com>
> + *
> + * Copyright (C) 2011 IAIK, Graz University of Technology
> + * Author: Andreas Niederl
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <
> http://www.gnu.org/licenses/>
> + *
> + * The origin of the code is from CUSE driver posed by Stefan Berger:
> + * https://github.com/stefanberger/qemu-tpm
I wonder if it makes sense to leave that only in commit message instead,
URL often break..
>
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/error-report.h"
> +#include "sysemu/tpm_backend.h"
> +#include "tpm_int.h"
> +#include "hw/hw.h"
> +#include "hw/i386/pc.h"
> +#include "sysemu/tpm_backend_int.h"
> +#include "tpm_util.h"
> +#include "tpm_ioctl.h"
> +#include "qapi/error.h"
> +
> +#include <fcntl.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <stdio.h>
> +
> +#define DEBUG_TPM 0
> +
> +#define DPRINT(fmt, ...) do { \
> + if (DEBUG_TPM) { \
> + fprintf(stderr, fmt, ## __VA_ARGS__); \
> + } \
> +} while (0);
> +
> +#define DPRINTF(fmt, ...) DPRINT(fmt"\n", __VA_ARGS__)
> +
> +#define TYPE_TPM_EMULATOR "emulator"
>
please keep the tpm- prefix (object typename is global)
+#define TPM_EMULATOR(obj) \
> + OBJECT_CHECK(TPMEmulator, (obj), TYPE_TPM_EMULATOR)
> +
> +static const TPMDriverOps tpm_emulator_driver;
> +
> +/* data structures */
> +typedef struct TPMEmulator {
> + TPMBackend parent;
> +
> + TPMEmulatorOptions ops;
> + int tpm_fd;
> + int tpm_ctrl_fd;
> + bool op_executing;
> + bool op_canceled;
> + bool child_running;
> + TPMVersion tpm_version;
> + ptm_cap caps; /* capabilities of the TPM */
> + uint8_t cur_locty_number; /* last set locality */
> +} TPMEmulator;
> +
> +#define TPM_DEFAULT_EMULATOR "swtpm"
> +#define TPM_DEFAULT_LOGLEVEL 5
> +#define TPM_EUMLATOR_IMPLEMENTS_ALL_CAPS(S, cap) (((S)->caps & (cap)) ==
> (cap))
>
EUMLATOR: typo
> +
> +static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_pt,
> + const uint8_t *in, uint32_t in_len,
> + uint8_t *out, uint32_t out_len,
> + bool *selftest_done)
> +{
> + int ret;
> + bool is_selftest;
> + const struct tpm_resp_hdr *hdr;
> +
> + if (!tpm_pt->child_running) {
> + return -1;
> + }
> +
> + tpm_pt->op_canceled = false;
> + tpm_pt->op_executing = true;
> + *selftest_done = false;
> +
> + is_selftest = tpm_util_is_selftest(in, in_len);
> +
> + ret = tpm_util_unix_write(tpm_pt->tpm_fd, in, in_len);
> + if (ret != in_len) {
> + if (!tpm_pt->op_canceled || errno != ECANCELED) {
> + error_report("tpm_emulator: error while transmitting data "
> + "to TPM: %s (%i)", strerror(errno), errno);
> + }
> + goto err_exit;
> + }
> +
> + tpm_pt->op_executing = false;
> +
> + ret = tpm_util_unix_read(tpm_pt->tpm_fd, out, out_len);
> + if (ret < 0) {
> + if (!tpm_pt->op_canceled || errno != ECANCELED) {
> + error_report("tpm_emulator: error while reading data from "
> + "TPM: %s (%i)", strerror(errno), errno);
> + }
> + } else if (ret < sizeof(struct tpm_resp_hdr) ||
> + be32_to_cpu(((struct tpm_resp_hdr *)out)->len) != ret) {
> + ret = -1;
> + error_report("tpm_emulator: received invalid response "
> + "packet from TPM");
> + }
> +
> + if (is_selftest && (ret >= sizeof(struct tpm_resp_hdr))) {
> + hdr = (struct tpm_resp_hdr *)out;
> + *selftest_done = (be32_to_cpu(hdr->errcode) == 0);
> + }
> +
> +err_exit:
> + if (ret < 0) {
> + tpm_util_write_fatal_error_response(out, out_len);
> + }
> +
> + tpm_pt->op_executing = false;
> +
> + return ret;
> +}
> +
> +static int tpm_emulator_set_locality(TPMEmulator *tpm_pt,
> + uint8_t locty_number)
> +{
> + ptm_loc loc;
> +
> + if (!tpm_pt->child_running) {
> + return -1;
> + }
> +
> + DPRINTF("tpm_emulator: %s : locality: 0x%x", __func__, locty_number);
> +
> + if (tpm_pt->cur_locty_number != locty_number) {
> + DPRINTF("tpm-emulator: setting locality : 0x%x", locty_number);
> + loc.u.req.loc = cpu_to_be32(locty_number);
> + if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_SET_LOCALITY, &loc,
> + sizeof(loc), sizeof(loc)) < 0) {
> + error_report("tpm-emulator: could not set locality : %s",
> + strerror(errno));
> + return -1;
> + }
> + loc.u.resp.tpm_result = be32_to_cpu(loc.u.resp.tpm_result);
> + if (loc.u.resp.tpm_result != 0) {
> + error_report("tpm-emulator: TPM result for set locality :
> 0x%x",
> + loc.u.resp.tpm_result);
>
you used "tpm_emulator:" above, you may want to have consistency
> + return -1;
> + }
> + tpm_pt->cur_locty_number = locty_number;
> + }
> + return 0;
> +}
> +
> +static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd cmd)
> +{
> + TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
> + TPMLocality *locty = NULL;
> + bool selftest_done = false;
> +
> + DPRINTF("tpm_emulator: processing command type %d", cmd);
> +
> + switch (cmd) {
> + case TPM_BACKEND_CMD_PROCESS_CMD:
> + locty = tb->tpm_state->locty_data;
>
tbh, I wonder why there is no lock to protect against concurrent usage of
tpm state. It seems it would be possible to have the worker thread doing a
read/write concurrently with the main thread (though another callback). It
may not happen, but it doesn't look safe. Should we add locks? this may be
true for passthrough as well, but it is more obvious with this code.
> + if (tpm_emulator_set_locality(tpm_pt,
> + tb->tpm_state->locty_number) < 0) {
> + tpm_util_write_fatal_error_response(locty->r_buffer.buffer,
> + locty->r_buffer.size);
> + } else {
> + tpm_emulator_unix_tx_bufs(tpm_pt, locty->w_buffer.buffer,
> + locty->w_offset, locty->r_buffer.buffer,
> + locty->r_buffer.size, &selftest_done);
> + }
> + tb->recv_data_callback(tb->tpm_state, tb->tpm_state->locty_number,
> + selftest_done);
> + break;
> + case TPM_BACKEND_CMD_INIT:
> + case TPM_BACKEND_CMD_END:
> + case TPM_BACKEND_CMD_TPM_RESET:
> + /* nothing to do */
> + break;
> + }
> +}
> +
> +/*
> + * Gracefully shut down the external unixio TPM
> + */
> +static void tpm_emulator_shutdown(TPMEmulator *tpm_pt)
> +{
> + ptm_res res;
> +
> + if (!tpm_pt->child_running) {
> + return;
> + }
> +
> + if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_SHUTDOWN, &res, 0,
> + sizeof(res)) < 0) {
> + error_report("tpm-emulator: Could not cleanly shutdown the TPM:
> %s",
> + strerror(errno));
> + } else if (res != 0) {
> + error_report("tpm-emulator: TPM result for sutdown: 0x%x",
> + be32_to_cpu(res));
> + }
> +}
> +
> +static int tpm_emulator_probe_caps(TPMEmulator *tpm_pt)
> +{
> + if (!tpm_pt->child_running) {
> + return -1;
> + }
> +
> + DPRINTF("tpm_emulator: %s", __func__);
> + if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_GET_CAPABILITY,
> + &tpm_pt->caps, 0, sizeof(tpm_pt->caps)) < 0) {
> + error_report("tpm-emulator: probing failed : %s",
> strerror(errno));
> + return -1;
> + }
> +
> + tpm_pt->caps = be64_to_cpu(tpm_pt->caps);
> +
> + DPRINTF("tpm-emulator: capbilities : 0x%lx", tpm_pt->caps);
> +
> + return 0;
> +}
> +
> +static int tpm_emulator_check_caps(TPMEmulator *tpm_pt)
> +{
> + ptm_cap caps = 0;
> + const char *tpm = NULL;
> +
> + /* check for min. required capabilities */
> + switch (tpm_pt->tpm_version) {
> + case TPM_VERSION_1_2:
> + caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN |
> PTM_CAP_GET_TPMESTABLISHED |
> + PTM_CAP_SET_LOCALITY;
> + tpm = "1.2";
> + break;
> + case TPM_VERSION_2_0:
> + caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN |
> PTM_CAP_GET_TPMESTABLISHED |
> + PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED;
> + tpm = "2";
> + break;
> + case TPM_VERSION_UNSPEC:
> + error_report("tpm-emulator: TPM version has not been set");
> + return -1;
> + }
> +
> + if (!TPM_EUMLATOR_IMPLEMENTS_ALL_CAPS(tpm_pt, caps)) {
> + error_report("tpm-emulator: TPM does not implement minimum set of
> "
> + "required capabilities for TPM %s (0x%x)", tpm,
> (int)caps);
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int tpm_emulator_init_tpm(TPMEmulator *tpm_pt, bool is_resume)
> +{
> + ptm_init init;
> + ptm_res res;
> +
> + if (!tpm_pt->child_running) {
> + return -1;
> + }
> +
> + DPRINTF("tpm_emulator: %s", __func__);
> + if (is_resume) {
> + init.u.req.init_flags =
> cpu_to_be32(PTM_INIT_FLAG_DELETE_VOLATILE);
> + }
>
is_resume is always false, remove it?
> +
> + if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_INIT, &init,
> sizeof(init),
> + sizeof(init)) < 0) {
> + error_report("tpm-emulator: could not send INIT: %s",
> + strerror(errno));
> + return -1;
> + }
> +
> + res = be32_to_cpu(init.u.resp.tpm_result);
> + if (res) {
> + error_report("tpm-emulator: TPM result for PTM_INIT: 0x%x", res);
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int tpm_emulator_startup_tpm(TPMBackend *tb)
> +{
> + TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
> +
> + DPRINTF("tpm_emulator: %s", __func__);
> +
> + tpm_emulator_init_tpm(tpm_pt, false) ;
> +
> + return 0;
> +}
> +
> +static bool tpm_emulator_get_tpm_established_flag(TPMBackend *tb)
> +{
> + TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
> + ptm_est est;
> +
> + DPRINTF("tpm_emulator: %s", __func__);
> + if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_GET_TPMESTABLISHED,
> &est, 0,
> + sizeof(est)) < 0) {
> + error_report("tpm-emulator: Could not get the TPM established
> flag: %s",
> + strerror(errno));
> + return false;
> + }
> + DPRINTF("tpm_emulator: established flag: %0x", est.u.resp.bit);
> +
> + return (est.u.resp.bit != 0);
> +}
> +
> +static int tpm_emulator_reset_tpm_established_flag(TPMBackend *tb,
> + uint8_t locty)
> +{
> + TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
> + ptm_reset_est reset_est;
> + ptm_res res;
> +
> + /* only a TPM 2.0 will support this */
> + if (tpm_pt->tpm_version == TPM_VERSION_2_0) {
> + reset_est.u.req.loc = cpu_to_be32(tpm_pt->cur_locty_number);
> +
> + if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd,
> PTM_RESET_TPMESTABLISHED,
> + &reset_est, sizeof(reset_est),
> + sizeof(reset_est)) < 0) {
> + error_report("tpm-emulator: Could not reset the establishment
> bit: "
> + "%s", strerror(errno));
> + return -1;
> + }
> +
> + res = be32_to_cpu(reset_est.u.resp.tpm_result);
> + if (res) {
> + error_report("tpm-emulator: TPM result for rest establixhed
> flag: "
> + "0x%x", res);
> + return -1;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static bool tpm_emulator_get_startup_error(TPMBackend *tb)
>
I prefer to name the function after the callback if possible to avoid
confusions (had_startup_error)
> +{
> + TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
> +
> + return !tpm_pt->child_running;
> +}
> +
> +static size_t tpm_emulator_realloc_buffer(TPMSizedBuffer *sb)
> +{
> + size_t wanted_size = 4096; /* Linux tpm.c buffer size */
> +
> + if (sb->size != wanted_size) {
> + sb->buffer = g_realloc(sb->buffer, wanted_size);
> + sb->size = wanted_size;
> + }
> + return sb->size;
> +}
>
Same as tpm_passthrough.. Move it to base class?
> +
> +static void tpm_emulator_cancel_cmd(TPMBackend *tb)
> +{
> + TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
> + ptm_res res;
> +
> + /*
> + * As of Linux 3.7 the tpm_tis driver does not properly cancel
> + * commands on all TPM manufacturers' TPMs.
> + * Only cancel if we're busy so we don't cancel someone else's
> + * command, e.g., a command executed on the host.
> + */
> + if (tpm_pt->op_executing) {
> + if (TPM_EUMLATOR_IMPLEMENTS_ALL_CAPS(tpm_pt,
> PTM_CAP_CANCEL_TPM_CMD)) {
> + if (tpm_util_ctrlcmd(tpm_pt->tpm_ctrl_fd, PTM_CANCEL_TPM_CMD,
> &res,
> + 0, sizeof(res)) < 0) {
> + error_report("tpm-emulator: Could not cancel command: %s",
> + strerror(errno));
> + } else if (res != 0) {
> + error_report("tpm-emulator: Failed to cancel TPM: 0x%x",
> + be32_to_cpu(res));
> + } else {
> + tpm_pt->op_canceled = true;
> + }
> + }
> + }
> +}
> +
> +static void tpm_emulator_reset(TPMBackend *tb)
> +{
> + DPRINTF("tpm_emulator: %s", __func__);
> +
> + tpm_emulator_cancel_cmd(tb);
> +}
> +
> +static const char *tpm_emulator_desc(void)
> +{
> + return "TPM emulator backend driver";
> +}
> +
> +static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)
> +{
> + TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
> +
> + return tpm_pt->tpm_version;
> +}
> +
> +static void tpm_emulator_fd_handler(void *opaque)
> +{
> + TPMEmulator *tpm_pt = opaque;
> + char val = 0;
> + ssize_t size;
> +
> + qemu_set_fd_handler(tpm_pt->tpm_fd, NULL, NULL, NULL);
> +
> + size = qemu_recv(tpm_pt->tpm_fd, &val, 1, MSG_PEEK);
> + if (!size) {
> + error_report("TPM backend disappeared");
> + tpm_pt->child_running = false;
> + } else {
> + DPRINT("tpm-emulator: unexpected data on TPM\n");
> + }
> +}
> +
> +static int tpm_emulator_spawn_emulator(TPMEmulator *tpm_pt)
> +{
> + int fds[2];
> + int ctrl_fds[2];
> + pid_t cpid;
> +
> + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) < 0) {
> + return -1;
> + }
> +
> + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ctrl_fds) < 0) {
> + closesocket(fds[0]);
> + closesocket(fds[1]);
> + return -1;
> + }
> +
> + cpid = fork();
> + if (cpid < 0) {
> + error_report("tpm-emulator: Fork failure: %s", strerror(errno));
> + closesocket(fds[0]); closesocket(fds[1]);
> + closesocket(ctrl_fds[0]); closesocket(ctrl_fds[1]);
> + return -1;
> + }
> +
> + if (cpid == 0) { /* CHILD */
> + int i;
> + char fd_str[128] = "";
> + char ctrl_fd_str[128] = "";
> + char tpmstate_str[1024] = "";
> + char log_str[1024] = "";
> + const char *params[] = {
> + tpm_pt->ops.path, "socket",
> + "--fd", fd_str,
> + "--ctrl", ctrl_fd_str,
> + "--tpmstate", tpmstate_str,
> + "--log", log_str,
> + NULL /* End */
> + };
> +
> + /* close all unused inherited sockets */
> + closesocket(fds[0]);
> + closesocket(ctrl_fds[0]);
> + for (i = STDERR_FILENO + 1; i < fds[1]; i++) {
> + closesocket(i);
>
what is this closing? I guess you should close all until
sysconf(_SC_OPEN_MAX) . I would dup2() the needed sockets to fixed values
after stderr.
+ }
> +
> + sprintf(fd_str, "%d", fds[1]);
> + sprintf(ctrl_fd_str, "type=unixio,clientfd=%d", ctrl_fds[1]);
> + sprintf(tpmstate_str, "dir=%s", tpm_pt->ops.tpmstatedir);
>
Or snprintf, better safe than sorry (for very long statedir path for ex)
> + if (tpm_pt->ops.has_logfile) {
> + sprintf(log_str, "file=%s,level=%d", tpm_pt->ops.logfile,
> + (int)tpm_pt->ops.loglevel);
> + } else {
> + /* truncate logs */
> + params[8] = NULL;
> + }
> + DPRINT("Running cmd: ")
> + for (i = 0; params[i]; i++) {
> + DPRINT(" %s", params[i])
> + }
> + DPRINT("\n")
> + if (execv(tpm_pt->ops.path, (char * const *)params) < 0) {
> + error_report("execv() failure : %s", strerror(errno));
> + }
> + closesocket(fds[1]);
> + closesocket(ctrl_fds[1]);
> + exit(0);
> + } else { /* self */
> + DPRINTF("tpm-emulator: child pid: %d", cpid);
> + /* FIXME: find better way of finding swtpm ready
> + maybe write 'ready'bit on socket ?
> + give some time to child to get ready */
> + sleep(1);
>
what happens without the sleep?
> +
> + tpm_pt->tpm_fd = fds[0];
> + tpm_pt->tpm_ctrl_fd = ctrl_fds[0];
> + tpm_pt->child_running = true;
> +
> + qemu_add_child_watch(cpid);
> +
> + fcntl(tpm_pt->tpm_fd, F_SETFL, O_NONBLOCK);
> + qemu_set_fd_handler(tpm_pt->tpm_fd, tpm_emulator_fd_handler, NULL,
> + tpm_pt);
> +
> + /* close unsed sockets */
> + closesocket(fds[1]);
> + closesocket(ctrl_fds[1]);
> + }
> +
> + return 0;
> +}
> +
> +static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_pt, QemuOpts
> *opts)
> +{
> + const char *value;
> +
> + value = qemu_opt_get(opts, "tpmstatedir");
> + if (!value) {
> + error_report("tpm-emulator: Missing tpm state directory");
> + return -1;
> + }
> + tpm_pt->ops.tpmstatedir = g_strdup(value);
> +
> + value = qemu_opt_get(opts, "path");
> + if (!value) {
> + value = TPM_DEFAULT_EMULATOR;
> + tpm_pt->ops.has_path = false;
> + } else {
> + tpm_pt->ops.has_path = true;
> + if (value[0] == '/') {
> + struct stat st;
> + if (stat(value, &st) < 0 || !(S_ISREG(st.st_mode)
> + || S_ISLNK(st.st_mode))) {
> + error_report("tpm-emulator: Invalid emulator path: %s",
> value);
>
probably not worth the racy check in qemu
+ return -1;
> + }
> + }
> + }
> + tpm_pt->ops.path = g_strdup(value);
> +
> + value = qemu_opt_get(opts, "logfile");
> + if (value) {
> + DPRINTF("tpm-emulator: LogFile: %s", value);
> + tpm_pt->ops.has_logfile = true;
> + tpm_pt->ops.logfile = g_strdup(value);
> + tpm_pt->ops.loglevel = qemu_opt_get_number(opts, "loglevel",
> + TPM_DEFAULT_LOGLEVEL);
> + tpm_pt->ops.has_loglevel = tpm_pt->ops.loglevel !=
> + TPM_DEFAULT_LOGLEVEL;
> + }
> +
> + if (tpm_emulator_spawn_emulator(tpm_pt) < 0) {
> + goto err_close_dev;
> + }
> +
> + tpm_pt->cur_locty_number = ~0;
> +
> + if (tpm_emulator_probe_caps(tpm_pt) ||
> + tpm_emulator_init_tpm(tpm_pt, false)) {
> + goto err_close_dev;
> + }
> +
> + if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) {
> + error_report("'%s' is not emulating TPM device.",
> tpm_pt->ops.path);
> + goto err_close_dev;
> + }
> +
> + DPRINTF("tpm_emulator: TPM Version %s",
> + tpm_pt->tpm_version == TPM_VERSION_1_2 ? "1.2" :
> + (tpm_pt->tpm_version == TPM_VERSION_2_0 ? "2.0" :
> "Unspecified"));
> +
> + if (tpm_emulator_check_caps(tpm_pt)) {
> + goto err_close_dev;
> + }
> +
> + return 0;
> +
> +err_close_dev:
> + tpm_emulator_shutdown(tpm_pt);
> + return -1;
> +}
> +
> +static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id)
> +{
> + TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));
> +
> + tb->id = g_strdup(id);
> +
> + if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {
> + goto err_exit;
> + }
> +
> + return tb;
> +
> +err_exit:
> + object_unref(OBJECT(tb));
> +
> + return NULL;
> +}
> +
> +static void tpm_emulator_destroy(TPMBackend *tb)
> +{
> + TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
> +
> + DPRINTF("tpm_emulator: %s", __func__);
> +
> + tpm_emulator_cancel_cmd(tb);
> + tpm_emulator_shutdown(tpm_pt);
> +
> + closesocket(tpm_pt->tpm_fd);
> + closesocket(tpm_pt->tpm_ctrl_fd);
> + g_free(tpm_pt->ops.tpmstatedir);
> + g_free(tpm_pt->ops.path);
> + g_free(tpm_pt->ops.logfile);
> +}
> +
> +static TPMOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
> +{
> + TPMEmulator *tpm_pt = TPM_EMULATOR(tb);
> + TPMEmulatorOptions *ops = g_new(TPMEmulatorOptions, 1);
> +
> + if (!ops) {
> + return NULL;
> + }
> + DPRINTF("tpm_emulator: %s", __func__);
> +
> + ops->tpmstatedir = g_strdup(tpm_pt->ops.tpmstatedir);
> + if (tpm_pt->ops.has_path) {
> + ops->has_path = true;
> + ops->path = g_strdup(tpm_pt->ops.path);
> + }
> + if (tpm_pt->ops.has_logfile) {
> + ops->has_logfile = true;
> + ops->logfile = g_strdup(tpm_pt->ops.logfile);
> + }
> + if (tpm_pt->ops.has_loglevel) {
> + ops->has_loglevel = true;
> + ops->loglevel = tpm_pt->ops.loglevel;
> + }
> +
> + return (TPMOptions *)ops;
> +}
> +
> +static const QemuOptDesc tpm_emulator_cmdline_opts[] = {
> + TPM_STANDARD_CMDLINE_OPTS,
> + {
> + .name = "tpmstatedir",
> + .type = QEMU_OPT_STRING,
> + .help = "TPM state directroy",
> + },
> + {
> + .name = "path",
> + .type = QEMU_OPT_STRING,
> + .help = "Path to TPM emulator binary",
>
I wonder if it's wise to let qemu exec any path. Maybe this should be
restricted to a known location?
> + },
> + {
> + .name = "logfile",
> + .type = QEMU_OPT_STRING,
> + .help = "Path to log file",
> + },
> + {
> + .name = "level",
> + .type = QEMU_OPT_STRING,
> + .help = "Log level number",
> + },
> + { /* end of list */ },
> +};
> +
> +static const TPMDriverOps tpm_emulator_driver = {
> + .type = TPM_TYPE_EMULATOR,
> + .opts = tpm_emulator_cmdline_opts,
> + .desc = tpm_emulator_desc,
> + .create = tpm_emulator_create,
> + .destroy = tpm_emulator_destroy,
> + .startup_tpm = tpm_emulator_startup_tpm,
> + .realloc_buffer = tpm_emulator_realloc_buffer,
> + .reset = tpm_emulator_reset,
> + .had_startup_error = tpm_emulator_get_startup_error,
> + .cancel_cmd = tpm_emulator_cancel_cmd,
> + .get_tpm_established_flag = tpm_emulator_get_tpm_established_flag,
> + .reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag,
> + .get_tpm_version = tpm_emulator_get_tpm_version,
> + .get_tpm_options = tpm_emulator_get_tpm_options,
> +};
> +
> +static void tpm_emulator_inst_init(Object *obj)
> +{
> + TPMEmulator *tpm_pt = TPM_EMULATOR(obj);
> +
> + DPRINTF("tpm_emulator: %s", __func__);
> + tpm_pt->tpm_fd = tpm_pt->tpm_ctrl_fd = -1;
> + tpm_pt->op_executing = tpm_pt->op_canceled = false;
> + tpm_pt->child_running = false;
> + tpm_pt->cur_locty_number = ~0;
> +}
> +
> +static void tpm_emulator_class_init(ObjectClass *klass, void *data)
> +{
> + TPMBackendClass *tbc = TPM_BACKEND_CLASS(klass);
> + tbc->ops = &tpm_emulator_driver;
> + tbc->handle_request = tpm_emulator_handle_request;
> +}
> +
> +static const TypeInfo tpm_emulator_info = {
> + .name = TYPE_TPM_EMULATOR,
> + .parent = TYPE_TPM_BACKEND,
> + .instance_size = sizeof(TPMEmulator),
> + .class_init = tpm_emulator_class_init,
> + .instance_init = tpm_emulator_inst_init,
> +};
> +
> +static void tpm_emulator_register(void)
> +{
> + type_register_static(&tpm_emulator_info);
> + tpm_register_driver(&tpm_emulator_driver);
> +}
> +
> +type_init(tpm_emulator_register)
> diff --git a/hw/tpm/tpm_ioctl.h b/hw/tpm/tpm_ioctl.h
> new file mode 100644
> index 0000000..af49708
> --- /dev/null
> +++ b/hw/tpm/tpm_ioctl.h
> @@ -0,0 +1,243 @@
> +/*
> + * tpm_ioctl.h
> + *
> + * (c) Copyright IBM Corporation 2014, 2015.
> + *
> + * This file is licensed under the terms of the 3-clause BSD license
> + */
> +#ifndef _TPM_IOCTL_H_
> +#define _TPM_IOCTL_H_
> +
> +#include <stdint.h>
> +#include <sys/uio.h>
> +#include <sys/types.h>
> +#include <sys/ioctl.h>
> +
> +/*
> + * Every response from a command involving a TPM command execution must
> hold
> + * the ptm_res as the first element.
> + * ptm_res corresponds to the error code of a command executed by the TPM.
> + */
> +
> +typedef uint32_t ptm_res;
> +
> +/* PTM_GET_TPMESTABLISHED: get the establishment bit */
>
any reason why all the commands have PTM prefix instead of TPM ?
(presumably to avoid some conflict?)
> +struct ptm_est {
> + union {
> + struct {
> + ptm_res tpm_result;
> + unsigned char bit; /* TPM established bit */
> + } resp; /* response */
> + } u;
> +};
> +
> +/* PTM_RESET_TPMESTABLISHED: reset establishment bit */
> +struct ptm_reset_est {
> + union {
> + struct {
> + uint8_t loc; /* locality to use */
> + } req; /* request */
> + struct {
> + ptm_res tpm_result;
> + } resp; /* response */
> + } u;
> +};
> +
> +/* PTM_INIT */
> +struct ptm_init {
> + union {
> + struct {
> + uint32_t init_flags; /* see definitions below */
> + } req; /* request */
> + struct {
> + ptm_res tpm_result;
> + } resp; /* response */
> + } u;
> +};
> +
> +/* above init_flags */
> +#define PTM_INIT_FLAG_DELETE_VOLATILE (1 << 0)
> + /* delete volatile state file after reading it */
> +
> +/* PTM_SET_LOCALITY */
> +struct ptm_loc {
> + union {
> + struct {
> + uint8_t loc; /* locality to set */
> + } req; /* request */
> + struct {
> + ptm_res tpm_result;
> + } resp; /* response */
> + } u;
> +};
> +
> +/* PTM_HASH_DATA: hash given data */
> +struct ptm_hdata {
> + union {
> + struct {
> + uint32_t length;
> + uint8_t data[4096];
> + } req; /* request */
> + struct {
> + ptm_res tpm_result;
> + } resp; /* response */
> + } u;
> +};
> +
> +/*
> + * size of the TPM state blob to transfer; x86_64 can handle 8k,
> + * ppc64le only ~7k; keep the response below a 4k page size
> + */
> +#define PTM_STATE_BLOB_SIZE (3 * 1024)
> +
> +/*
> + * The following is the data structure to get state blobs from the TPM.
> + * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE,
> multiple reads
> + * with this ioctl and with adjusted offset are necessary. All bytes
> + * must be transferred and the transfer is done once the last byte has
> been
> + * returned.
> + * It is possible to use the read() interface for reading the data;
> however, the
> + * first bytes of the state blob will be part of the response to the
> ioctl(); a
> + * subsequent read() is only necessary if the total length (totlength)
> exceeds
> + * the number of received bytes. seek() is not supported.
> + */
> +struct ptm_getstate {
> + union {
> + struct {
> + uint32_t state_flags; /* may be: PTM_STATE_FLAG_DECRYPTED */
> + uint32_t type; /* which blob to pull */
> + uint32_t offset; /* offset from where to read */
> + } req; /* request */
> + struct {
> + ptm_res tpm_result;
> + uint32_t state_flags; /* may be: PTM_STATE_FLAG_ENCRYPTED */
> + uint32_t totlength; /* total length that will be
> transferred */
> + uint32_t length; /* number of bytes in following buffer
> */
> + uint8_t data[PTM_STATE_BLOB_SIZE];
> + } resp; /* response */
> + } u;
> +};
> +
> +/* TPM state blob types */
> +#define PTM_BLOB_TYPE_PERMANENT 1
> +#define PTM_BLOB_TYPE_VOLATILE 2
> +#define PTM_BLOB_TYPE_SAVESTATE 3
> +
> +/* state_flags above : */
> +#define PTM_STATE_FLAG_DECRYPTED 1 /* on input: get decrypted state
> */
> +#define PTM_STATE_FLAG_ENCRYPTED 2 /* on output: state is encrypted */
> +
> +/*
> + * The following is the data structure to set state blobs in the TPM.
> + * If the size of the state blob exceeds the PTM_STATE_BLOB_SIZE, multiple
> + * 'writes' using this ioctl are necessary. The last packet is indicated
> + * by the length being smaller than the PTM_STATE_BLOB_SIZE.
> + * The very first packet may have a length indicator of '0' enabling
> + * a write() with all the bytes from a buffer. If the write() interface
> + * is used, a final ioctl with a non-full buffer must be made to indicate
> + * that all data were transferred (a write with 0 bytes would not work).
> + */
> +struct ptm_setstate {
> + union {
> + struct {
> + uint32_t state_flags; /* may be PTM_STATE_FLAG_ENCRYPTED */
> + uint32_t type; /* which blob to set */
> + uint32_t length; /* length of the data;
> + use 0 on the first packet to
> + transfer using write() */
> + uint8_t data[PTM_STATE_BLOB_SIZE];
> + } req; /* request */
> + struct {
> + ptm_res tpm_result;
> + } resp; /* response */
> + } u;
> +};
> +
> +/*
> + * PTM_GET_CONFIG: Data structure to get runtime configuration information
> + * such as which keys are applied.
> + */
> +struct ptm_getconfig {
> + union {
> + struct {
> + ptm_res tpm_result;
> + uint32_t flags;
> + } resp; /* response */
> + } u;
> +};
> +
> +#define PTM_CONFIG_FLAG_FILE_KEY 0x1
> +#define PTM_CONFIG_FLAG_MIGRATION_KEY 0x2
> +
> +
> +typedef uint64_t ptm_cap;
> +typedef struct ptm_est ptm_est;
> +typedef struct ptm_reset_est ptm_reset_est;
> +typedef struct ptm_loc ptm_loc;
> +typedef struct ptm_hdata ptm_hdata;
> +typedef struct ptm_init ptm_init;
> +typedef struct ptm_getstate ptm_getstate;
> +typedef struct ptm_setstate ptm_setstate;
> +typedef struct ptm_getconfig ptm_getconfig;
> +
> +/* capability flags returned by PTM_GET_CAPABILITY */
> +#define PTM_CAP_INIT (1)
> +#define PTM_CAP_SHUTDOWN (1 << 1)
> +#define PTM_CAP_GET_TPMESTABLISHED (1 << 2)
> +#define PTM_CAP_SET_LOCALITY (1 << 3)
> +#define PTM_CAP_HASHING (1 << 4)
> +#define PTM_CAP_CANCEL_TPM_CMD (1 << 5)
> +#define PTM_CAP_STORE_VOLATILE (1 << 6)
> +#define PTM_CAP_RESET_TPMESTABLISHED (1 << 7)
> +#define PTM_CAP_GET_STATEBLOB (1 << 8)
> +#define PTM_CAP_SET_STATEBLOB (1 << 9)
> +#define PTM_CAP_STOP (1 << 10)
> +#define PTM_CAP_GET_CONFIG (1 << 11)
> +
> +enum {
> + PTM_GET_CAPABILITY = _IOR('P', 0, ptm_cap),
> + PTM_INIT = _IOWR('P', 1, ptm_init),
> + PTM_SHUTDOWN = _IOR('P', 2, ptm_res),
> + PTM_GET_TPMESTABLISHED = _IOR('P', 3, ptm_est),
> + PTM_SET_LOCALITY = _IOWR('P', 4, ptm_loc),
> + PTM_HASH_START = _IOR('P', 5, ptm_res),
> + PTM_HASH_DATA = _IOWR('P', 6, ptm_hdata),
> + PTM_HASH_END = _IOR('P', 7, ptm_res),
> + PTM_CANCEL_TPM_CMD = _IOR('P', 8, ptm_res),
> + PTM_STORE_VOLATILE = _IOR('P', 9, ptm_res),
> + PTM_RESET_TPMESTABLISHED = _IOWR('P', 10, ptm_reset_est),
> + PTM_GET_STATEBLOB = _IOWR('P', 11, ptm_getstate),
> + PTM_SET_STATEBLOB = _IOWR('P', 12, ptm_setstate),
> + PTM_STOP = _IOR('P', 13, ptm_res),
> + PTM_GET_CONFIG = _IOR('P', 14, ptm_getconfig),
> +};
> +
> +/*
> + * Commands used by the non-CUSE TPMs
> + *
> + * All messages container big-endian data.
> + *
> + * The return messages only contain the 'resp' part of the unions
> + * in the data structures above. Besides that the limits in the
> + * buffers above (ptm_hdata:u.req.data and ptm_get_state:u.resp.data
> + * and ptm_set_state:u.req.data) are 0xffffffff.
> + */
> +enum {
> + CMD_GET_CAPABILITY = 1,
> + CMD_INIT,
> + CMD_SHUTDOWN,
> + CMD_GET_TPMESTABLISHED,
> + CMD_SET_LOCALITY,
> + CMD_HASH_START,
> + CMD_HASH_DATA,
> + CMD_HASH_END,
> + CMD_CANCEL_TPM_CMD,
> + CMD_STORE_VOLATILE,
> + CMD_RESET_TPMESTABLISHED,
> + CMD_GET_STATEBLOB,
> + CMD_SET_STATEBLOB,
> + CMD_STOP,
> + CMD_GET_CONFIG,
> +};
> +
> +#endif /* _TPM_IOCTL_H */
> diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c
> index 5475acf..34b1d59 100644
> --- a/hw/tpm/tpm_util.c
> +++ b/hw/tpm/tpm_util.c
> @@ -22,6 +22,7 @@
> #include "qemu/osdep.h"
> #include "tpm_util.h"
> #include "tpm_int.h"
> +#include "tpm_ioctl.h"
>
> int tpm_util_unix_write(int fd, const uint8_t *buf, uint32_t len)
> {
> @@ -185,3 +186,36 @@ int tpm_util_test_tpmdev(int tpm_fd, TPMVersion
> *tpm_version)
>
> return 1;
> }
> +
> +static unsigned long ioctl_to_cmd(unsigned long ioctlnum)
> +{
> + /* the ioctl number contains the command number - 1 */
> + return ((ioctlnum >> _IOC_NRSHIFT) & _IOC_NRMASK) + 1;
> +}
> +
> +int tpm_util_ctrlcmd(int fd, unsigned long cmd, void *msg, size_t
> msg_len_in,
> + size_t msg_len_out)
> +{
> + int n;
> +
> + uint32_t cmd_no = cpu_to_be32(ioctl_to_cmd(cmd));
> + struct iovec iov[2] = {
> + { .iov_base = &cmd_no, .iov_len = sizeof(cmd_no), },
> + { .iov_base = msg, .iov_len = msg_len_in, },
> + };
> +
> + n = writev(fd, iov, 2);
> + if (n > 0) {
> + if (msg_len_out > 0) {
> + n = read(fd, msg, msg_len_out);
> + /* simulate ioctl return value */
> + if (n > 0) {
> + n = 0;
> + }
> + } else {
> + n = 0;
> + }
> + }
> + return n;
> +}
> +
>
This helper could be kept in tpm_emulator.c
> diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h
> index c2feca7..b93d484 100644
> --- a/hw/tpm/tpm_util.h
> +++ b/hw/tpm/tpm_util.h
> @@ -34,4 +34,7 @@ bool tpm_util_is_selftest(const uint8_t *in, uint32_t
> in_len);
>
> int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version);
>
> +int tpm_util_ctrlcmd(int fd, unsigned long cmd, void *msg,
> + size_t msg_len_in, size_t msg_len_out);
> +
> #endif /* TPM_TPM_UTIL_H */
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 5faf1ac..e8ddbc6 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -5117,10 +5117,11 @@
> # An enumeration of TPM types
> #
> # @passthrough: TPM passthrough type
> +# @emulator: Software Emulator TPM type
> #
> # Since: 1.5
> ##
> -{ 'enum': 'TpmType', 'data': [ 'passthrough' ] }
> +{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ] }
>
> ##
> # @query-tpm-types:
> @@ -5163,6 +5164,22 @@
> 'data': { '*path' : 'str', '*cancel-path' : 'str'} }
>
> ##
> +# @TPMEmulatorOptions:
> +#
> +# Information about the TPM emulator
> +#
> +# @tpmstatedir: TPM emilator state dir
> +# @path: TPM emulator binary path to use
> +# @logfile: file to use to place TPM emulator logs
> +# @loglevel: log level number
> +#
> +# Since: 2.6
> +##
> +{ 'struct': 'TPMEmulatorOptions', 'base': 'TPMOptions',
> + 'data': { 'tpmstatedir' : 'str', '*path': 'str',
> + '*logfile' : 'str', '*loglevel' : 'int' } }
> +
> +##
> # @TpmTypeOptions:
> #
> # A union referencing different TPM backend types' configuration options
> @@ -5172,7 +5189,8 @@
> # Since: 1.5
> ##
> { 'union': 'TpmTypeOptions',
> - 'data': { 'passthrough' : 'TPMPassthroughOptions' } }
> + 'data': { 'passthrough' : 'TPMPassthroughOptions',
> + 'emulator' : 'TPMEmulatorOptions' } }
>
> ##
> # @TPMInfo:
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 99af8ed..5bbf187 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -2846,7 +2846,12 @@ DEF("tpmdev", HAS_ARG, QEMU_OPTION_tpmdev, \
> "-tpmdev passthrough,id=id[,path=path][,cancel-path=path]\n"
> " use path to provide path to a character device;
> default is /dev/tpm0\n"
> " use cancel-path to provide path to TPM's cancel
> sysfs entry; if\n"
> - " not provided it will be searched for in
> /sys/class/misc/tpm?/device\n",
> + " not provided it will be searched for in
> /sys/class/misc/tpm?/device\n"
> + "-tpmdev
> emulator,id=id,tpmstatedir=dir[,path=emulator-path,logfile=path,loglevel=level]\n"
> + " use tpmstatedir to provide path to the tpm state
> dirctory\n"
> + " use path to provide the emulator binary to launch;
> default is 'swtpm'\n"
> + " use logfile to provide where to place the swtpm
> logs\n"
> + " use loglevel to controls the swtpm log level\n",
> QEMU_ARCH_ALL)
> STEXI
>
> @@ -2855,8 +2860,8 @@ The general form of a TPM device option is:
>
> @item -tpmdev @var{backend} ,id=@var{id} [,@var{options}]
> @findex -tpmdev
> -Backend type must be:
> -@option{passthrough}.
> +Backend type must be either one of the following:
> +@option{passthrough}, @option{emulator}.
>
> The specific backend type will determine the applicable options.
> The @code{-tpmdev} option creates the TPM backend and requires a
> @@ -2906,6 +2911,20 @@ To create a passthrough TPM use the following two
> options:
> Note that the @code{-tpmdev} id is @code{tpm0} and is referenced by
> @code{tpmdev=tpm0} in the device option.
>
> +@item -tpmdev emulator, id=@var{id}, tpmstatedir=@var{path},
> path=@var{emulator-binary-path}, logfile=@var{path}, logevel=@var{level}
> +
> +(Linux-host only) Enable access to a TPM emulator.
> +
> +@option{tpmstatedir} specifies the tpm state directory
> +@option{path} specifies the emulator binary path to use
> +@option{logfile} optional log file to use to place log messages
> +@option{loglevel} specifies the log level to use
> +
> +To create a TPM emulator backend device:
> +@example
> +-tpmdev
> emulator,id=tpm0,tpmstatedir=/tmp/my-tpm,path=/usr/local/bin/swtpm,logfile=/tmp/qemu-tpm.log,logevel=5
> -device tpm-tis,tpmdev=tpm0
> +@end example
> +
> @end table
>
> ETEXI
> diff --git a/tpm.c b/tpm.c
> index c221000..ed110d2 100644
> --- a/tpm.c
> +++ b/tpm.c
> @@ -25,7 +25,7 @@ static QLIST_HEAD(, TPMBackend) tpm_backends =
>
>
> #define TPM_MAX_MODELS 1
> -#define TPM_MAX_DRIVERS 1
> +#define TPM_MAX_DRIVERS 2
>
> static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = {
> NULL,
> @@ -263,6 +263,11 @@ static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
> res->options->u.passthrough.data =
> (TPMPassthroughOptions *)tpm_backend_get_tpm_options(drv);
> break;
> + case TPM_TYPE_EMULATOR:
> + res->options->type = TPM_TYPE_OPTIONS_KIND_EMULATOR;
> + res->options->u.emulator.data =
> + (TPMEmulatorOptions *) tpm_backend_get_tpm_options(drv);
> + break;
> case TPM_TYPE__MAX:
> break;
> }
> --
> 2.7.4
>
>
> --
Marc-André Lureau
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 7/7] tpm: New backend driver to support TPM emulator
2017-03-31 13:10 ` [Qemu-devel] [PATCH 7/7] tpm: New backend driver to support " Amarnath Valluri
2017-04-04 16:23 ` Marc-André Lureau
@ 2017-04-05 15:30 ` Daniel P. Berrange
1 sibling, 0 replies; 37+ messages in thread
From: Daniel P. Berrange @ 2017-04-05 15:30 UTC (permalink / raw)
To: Amarnath Valluri; +Cc: qemu-devel, patrick.ohly, stefanb
On Fri, Mar 31, 2017 at 04:10:17PM +0300, Amarnath Valluri wrote:
> +static int tpm_emulator_spawn_emulator(TPMEmulator *tpm_pt)
> +{
> + int fds[2];
> + int ctrl_fds[2];
> + pid_t cpid;
> +
> + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds) < 0) {
> + return -1;
> + }
> +
> + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ctrl_fds) < 0) {
> + closesocket(fds[0]);
> + closesocket(fds[1]);
> + return -1;
> + }
> +
> + cpid = fork();
You must use qemu_fork() to ensure signals are put into a sane state
and also to avoid signal handler races which can hit between fork & exec.
> + if (cpid < 0) {
> + error_report("tpm-emulator: Fork failure: %s", strerror(errno));
> + closesocket(fds[0]); closesocket(fds[1]);
> + closesocket(ctrl_fds[0]); closesocket(ctrl_fds[1]);
> + return -1;
> + }
> +
> + if (cpid == 0) { /* CHILD */
> + int i;
> + char fd_str[128] = "";
> + char ctrl_fd_str[128] = "";
> + char tpmstate_str[1024] = "";
> + char log_str[1024] = "";
> + const char *params[] = {
> + tpm_pt->ops.path, "socket",
> + "--fd", fd_str,
> + "--ctrl", ctrl_fd_str,
> + "--tpmstate", tpmstate_str,
> + "--log", log_str,
> + NULL /* End */
> + };
> +
> + /* close all unused inherited sockets */
> + closesocket(fds[0]);
> + closesocket(ctrl_fds[0]);
> + for (i = STDERR_FILENO + 1; i < fds[1]; i++) {
> + closesocket(i);
> + }
So you're assuming that fds[1] is the most highest open file descriptor
in QEMU, since you opened it a few lines earlier. Unfortunately this is not
valid, as QEMU is multi-threaded and so other threads may have opened FDs
in this time window. In addition there may be previously opened FDs with
high numbers. If you want to close all open FDs, you need to use sysconf
to query _SC_OPEN_MAX and iterate upto that value.
> +
> + sprintf(fd_str, "%d", fds[1]);
> + sprintf(ctrl_fd_str, "type=unixio,clientfd=%d", ctrl_fds[1]);
> + sprintf(tpmstate_str, "dir=%s", tpm_pt->ops.tpmstatedir);
All these unchecked sprintfs into fixed buffers are bad and the directory
based ones are in fact buffer overflows if the user gives a tpmstatedir
path longer than 1020 characters. Use g_strdup_printf() to malloc strings
on the stack and free them when done.
> + if (tpm_pt->ops.has_logfile) {
> + sprintf(log_str, "file=%s,level=%d", tpm_pt->ops.logfile,
> + (int)tpm_pt->ops.loglevel);
> + } else {
> + /* truncate logs */
> + params[8] = NULL;
> + }
> + DPRINT("Running cmd: ")
> + for (i = 0; params[i]; i++) {
> + DPRINT(" %s", params[i])
> + }
> + DPRINT("\n")
> + if (execv(tpm_pt->ops.path, (char * const *)params) < 0) {
> + error_report("execv() failure : %s", strerror(errno));
> + }
> + closesocket(fds[1]);
> + closesocket(ctrl_fds[1]);
> + exit(0);
> + } else { /* self */
> + DPRINTF("tpm-emulator: child pid: %d", cpid);
> + /* FIXME: find better way of finding swtpm ready
> + maybe write 'ready'bit on socket ?
> + give some time to child to get ready */
> + sleep(1);
> +
> + tpm_pt->tpm_fd = fds[0];
> + tpm_pt->tpm_ctrl_fd = ctrl_fds[0];
Unless you switch over to using QEMU Chardevs backends as the I/O mechanism,
you should uses QIOChannelSocket for I/O and event handlers, rather than using
raw sockets directly.
ie, create one with qio_channel_socket_new_fd(fds[0]);
....
> + tpm_pt->child_running = true;
> +
> + qemu_add_child_watch(cpid);
> +
> + fcntl(tpm_pt->tpm_fd, F_SETFL, O_NONBLOCK);
..then
qio_channel_set_blocking
> + qemu_set_fd_handler(tpm_pt->tpm_fd, tpm_emulator_fd_handler, NULL,
> + tpm_pt);
and use qio_channel_add_watch,
etc, likewise in the places where you do actual I/O
> +
> + /* close unsed sockets */
> + closesocket(fds[1]);
> + closesocket(ctrl_fds[1]);
> + }
> +
> + return 0;
> +}
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://entangle-photo.org -o- http://search.cpan.org/~danberr/ :|
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-03-31 13:10 [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator Amarnath Valluri
` (7 preceding siblings ...)
2017-03-31 13:10 ` [Qemu-devel] [PATCH 7/7] tpm: New backend driver to support " Amarnath Valluri
@ 2017-04-02 8:33 ` no-reply
2017-04-03 17:07 ` Daniel P. Berrange
9 siblings, 0 replies; 37+ messages in thread
From: no-reply @ 2017-04-02 8:33 UTC (permalink / raw)
To: amarnath.valluri; +Cc: famz, qemu-devel, patrick.ohly, stefanb
Hi,
This series failed automatic build test. Please find the testing commands and
their output below. If you have docker installed, you can probably reproduce it
locally.
Subject: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
Type: series
Message-id: 1490965817-16913-1-git-send-email-amarnath.valluri@intel.com
=== TEST SCRIPT BEGIN ===
#!/bin/bash
set -e
git submodule update --init dtc
# Let docker tests dump environment info
export SHOW_ENV=1
export J=8
make docker-test-quick@centos6
make docker-test-mingw@fedora
make docker-test-build@min-glib
=== TEST SCRIPT END ===
Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
Switched to a new branch 'test'
2bc0e80 Added support for TPM emulator
3585a4d tpm-passthrough: move reusable code to utils
792f9e4 tmp backend: Add new api to read backend tpm options
d3eb0fb tpm-backend: Call interface methods only if backend implements them
dc4c821 tpm-backend: Initialize and free data members in it's own methods
4067c5c tpm-backend: Move thread handling inside TPMBackend
4f07a18 tpm-backend: Remove unneeded member variable from backend class
=== OUTPUT BEGIN ===
Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc'
Cloning into '/var/tmp/patchew-tester-tmp-ylr_f574/src/dtc'...
Submodule path 'dtc': checked out '558cd81bdd432769b59bff01240c44f82cfb1a9d'
BUILD centos6
make[1]: Entering directory '/var/tmp/patchew-tester-tmp-ylr_f574/src'
ARCHIVE qemu.tgz
ARCHIVE dtc.tgz
COPY RUNNER
RUN test-quick in qemu:centos6
Packages installed:
SDL-devel-1.2.14-7.el6_7.1.x86_64
ccache-3.1.6-2.el6.x86_64
epel-release-6-8.noarch
gcc-4.4.7-17.el6.x86_64
git-1.7.1-4.el6_7.1.x86_64
glib2-devel-2.28.8-5.el6.x86_64
libfdt-devel-1.4.0-1.el6.x86_64
make-3.81-23.el6.x86_64
package g++ is not installed
pixman-devel-0.32.8-1.el6.x86_64
tar-1.23-15.el6_8.x86_64
zlib-devel-1.2.3-29.el6.x86_64
Environment variables:
PACKAGES=libfdt-devel ccache tar git make gcc g++ zlib-devel glib2-devel SDL-devel pixman-devel epel-release
HOSTNAME=1687611770ac
TERM=xterm
MAKEFLAGS= -j8
HISTSIZE=1000
J=8
USER=root
CCACHE_DIR=/var/tmp/ccache
EXTRA_CONFIGURE_OPTS=
V=
SHOW_ENV=1
MAIL=/var/spool/mail/root
PATH=/usr/lib/ccache:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
LANG=en_US.UTF-8
TARGET_LIST=
HISTCONTROL=ignoredups
SHLVL=1
HOME=/root
TEST_DIR=/tmp/qemu-test
LOGNAME=root
LESSOPEN=||/usr/bin/lesspipe.sh %s
FEATURES= dtc
DEBUG=
G_BROKEN_FILENAMES=1
CCACHE_HASHDIR=
_=/usr/bin/env
Configure options:
--enable-werror --target-list=x86_64-softmmu,aarch64-softmmu --prefix=/var/tmp/qemu-build/install
No C++ compiler available; disabling C++ specific optional code
Install prefix /var/tmp/qemu-build/install
BIOS directory /var/tmp/qemu-build/install/share/qemu
binary directory /var/tmp/qemu-build/install/bin
library directory /var/tmp/qemu-build/install/lib
module directory /var/tmp/qemu-build/install/lib/qemu
libexec directory /var/tmp/qemu-build/install/libexec
include directory /var/tmp/qemu-build/install/include
config directory /var/tmp/qemu-build/install/etc
local state directory /var/tmp/qemu-build/install/var
Manual directory /var/tmp/qemu-build/install/share/man
ELF interp prefix /usr/gnemul/qemu-%M
Source path /tmp/qemu-test/src
C compiler cc
Host C compiler cc
C++ compiler
Objective-C compiler cc
ARFLAGS rv
CFLAGS -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -g
QEMU_CFLAGS -I/usr/include/pixman-1 -I$(SRC_PATH)/dtc/libfdt -pthread -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -fPIE -DPIE -m64 -mcx16 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wstrict-prototypes -Wredundant-decls -Wall -Wundef -Wwrite-strings -Wmissing-prototypes -fno-strict-aliasing -fno-common -fwrapv -Wendif-labels -Wno-missing-include-dirs -Wempty-body -Wnested-externs -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration -Wold-style-definition -Wtype-limits -fstack-protector-all
LDFLAGS -Wl,--warn-common -Wl,-z,relro -Wl,-z,now -pie -m64 -g
make make
install install
python python -B
smbd /usr/sbin/smbd
module support no
host CPU x86_64
host big endian no
target list x86_64-softmmu aarch64-softmmu
tcg debug enabled no
gprof enabled no
sparse enabled no
strip binaries yes
profiler no
static build no
pixman system
SDL support yes (1.2.14)
GTK support no
GTK GL support no
VTE support no
TLS priority NORMAL
GNUTLS support no
GNUTLS rnd no
libgcrypt no
libgcrypt kdf no
nettle no
nettle kdf no
libtasn1 no
curses support no
virgl support no
curl support no
mingw32 support no
Audio drivers oss
Block whitelist (rw)
Block whitelist (ro)
VirtFS support no
VNC support yes
VNC SASL support no
VNC JPEG support no
VNC PNG support no
xen support no
brlapi support no
bluez support no
Documentation no
PIE yes
vde support no
netmap support no
Linux AIO support no
ATTR/XATTR support yes
Install blobs yes
KVM support yes
HAX support no
RDMA support no
TCG interpreter no
fdt support yes
preadv support yes
fdatasync yes
madvise yes
posix_madvise yes
libcap-ng support no
vhost-net support yes
vhost-scsi support yes
vhost-vsock support yes
Trace backends log
spice support no
rbd support no
xfsctl support no
smartcard support no
libusb no
usb net redir no
OpenGL support no
OpenGL dmabufs no
libiscsi support no
libnfs support no
build guest agent yes
QGA VSS support no
QGA w32 disk info no
QGA MSI support no
seccomp support no
coroutine backend ucontext
coroutine pool yes
debug stack usage no
GlusterFS support no
gcov gcov
gcov enabled no
TPM support yes
libssh2 support no
TPM passthrough yes
TPM emulator yes
QOM debugging yes
lzo support no
snappy support no
bzip2 support no
NUMA host support no
tcmalloc support no
jemalloc support no
avx2 optimization no
replication support yes
mkdir -p dtc/libfdt
GEN x86_64-softmmu/config-devices.mak.tmp
mkdir -p dtc/tests
GEN aarch64-softmmu/config-devices.mak.tmp
GEN config-host.h
GEN qemu-options.def
GEN qmp-commands.h
GEN qapi-types.h
GEN qapi-visit.h
GEN qapi-event.h
GEN aarch64-softmmu/config-devices.mak
GEN x86_64-softmmu/config-devices.mak
GEN qmp-marshal.c
GEN qapi-types.c
GEN qapi-visit.c
GEN qapi-event.c
GEN qmp-introspect.h
GEN qmp-introspect.c
GEN trace/generated-tcg-tracers.h
GEN trace/generated-helpers-wrappers.h
GEN trace/generated-helpers.h
GEN trace/generated-helpers.c
GEN module_block.h
GEN tests/test-qapi-types.h
GEN tests/test-qapi-visit.h
GEN tests/test-qmp-commands.h
GEN tests/test-qapi-event.h
GEN tests/test-qmp-introspect.h
GEN trace-root.h
GEN util/trace.h
GEN crypto/trace.h
GEN io/trace.h
GEN migration/trace.h
GEN block/trace.h
GEN backends/trace.h
GEN hw/block/trace.h
GEN hw/block/dataplane/trace.h
GEN hw/char/trace.h
GEN hw/intc/trace.h
GEN hw/net/trace.h
GEN hw/virtio/trace.h
GEN hw/audio/trace.h
GEN hw/misc/trace.h
GEN hw/usb/trace.h
GEN hw/scsi/trace.h
GEN hw/nvram/trace.h
GEN hw/display/trace.h
GEN hw/input/trace.h
GEN hw/timer/trace.h
GEN hw/dma/trace.h
GEN hw/sparc/trace.h
GEN hw/sd/trace.h
GEN hw/isa/trace.h
GEN hw/mem/trace.h
GEN hw/i386/trace.h
GEN hw/i386/xen/trace.h
GEN hw/9pfs/trace.h
GEN hw/ppc/trace.h
GEN hw/pci/trace.h
GEN hw/s390x/trace.h
GEN hw/vfio/trace.h
GEN hw/acpi/trace.h
GEN hw/arm/trace.h
GEN hw/alpha/trace.h
GEN hw/xen/trace.h
GEN ui/trace.h
GEN audio/trace.h
GEN net/trace.h
GEN target/arm/trace.h
GEN target/i386/trace.h
GEN target/mips/trace.h
GEN target/sparc/trace.h
GEN target/s390x/trace.h
GEN target/ppc/trace.h
GEN qom/trace.h
GEN linux-user/trace.h
GEN qapi/trace.h
GEN trace-root.c
GEN util/trace.c
GEN crypto/trace.c
GEN io/trace.c
GEN migration/trace.c
GEN block/trace.c
GEN backends/trace.c
GEN hw/block/trace.c
GEN hw/block/dataplane/trace.c
GEN hw/char/trace.c
GEN hw/intc/trace.c
GEN hw/net/trace.c
GEN hw/virtio/trace.c
GEN hw/audio/trace.c
GEN hw/misc/trace.c
GEN hw/usb/trace.c
GEN hw/scsi/trace.c
GEN hw/nvram/trace.c
GEN hw/display/trace.c
GEN hw/input/trace.c
GEN hw/timer/trace.c
GEN hw/dma/trace.c
GEN hw/sparc/trace.c
GEN hw/sd/trace.c
GEN hw/isa/trace.c
GEN hw/mem/trace.c
GEN hw/i386/trace.c
GEN hw/i386/xen/trace.c
GEN hw/9pfs/trace.c
GEN hw/ppc/trace.c
GEN hw/pci/trace.c
GEN hw/s390x/trace.c
GEN hw/vfio/trace.c
GEN hw/acpi/trace.c
GEN hw/arm/trace.c
GEN hw/alpha/trace.c
GEN hw/xen/trace.c
GEN ui/trace.c
GEN audio/trace.c
GEN net/trace.c
GEN target/arm/trace.c
GEN target/i386/trace.c
GEN target/mips/trace.c
GEN target/sparc/trace.c
GEN target/s390x/trace.c
GEN target/ppc/trace.c
GEN qom/trace.c
GEN linux-user/trace.c
GEN qapi/trace.c
GEN config-all-devices.mak
DEP /tmp/qemu-test/src/dtc/tests/dumptrees.c
DEP /tmp/qemu-test/src/dtc/tests/trees.S
DEP /tmp/qemu-test/src/dtc/tests/testutils.c
DEP /tmp/qemu-test/src/dtc/tests/value-labels.c
DEP /tmp/qemu-test/src/dtc/tests/asm_tree_dump.c
DEP /tmp/qemu-test/src/dtc/tests/truncated_property.c
DEP /tmp/qemu-test/src/dtc/tests/check_path.c
DEP /tmp/qemu-test/src/dtc/tests/overlay_bad_fixup.c
DEP /tmp/qemu-test/src/dtc/tests/overlay.c
DEP /tmp/qemu-test/src/dtc/tests/subnode_iterate.c
DEP /tmp/qemu-test/src/dtc/tests/property_iterate.c
DEP /tmp/qemu-test/src/dtc/tests/integer-expressions.c
DEP /tmp/qemu-test/src/dtc/tests/utilfdt_test.c
DEP /tmp/qemu-test/src/dtc/tests/add_subnode_with_nops.c
DEP /tmp/qemu-test/src/dtc/tests/path_offset_aliases.c
DEP /tmp/qemu-test/src/dtc/tests/dtbs_equal_unordered.c
DEP /tmp/qemu-test/src/dtc/tests/dtb_reverse.c
DEP /tmp/qemu-test/src/dtc/tests/dtbs_equal_ordered.c
DEP /tmp/qemu-test/src/dtc/tests/extra-terminating-null.c
DEP /tmp/qemu-test/src/dtc/tests/incbin.c
DEP /tmp/qemu-test/src/dtc/tests/boot-cpuid.c
DEP /tmp/qemu-test/src/dtc/tests/phandle_format.c
DEP /tmp/qemu-test/src/dtc/tests/path-references.c
DEP /tmp/qemu-test/src/dtc/tests/references.c
DEP /tmp/qemu-test/src/dtc/tests/string_escapes.c
DEP /tmp/qemu-test/src/dtc/tests/propname_escapes.c
DEP /tmp/qemu-test/src/dtc/tests/appendprop2.c
DEP /tmp/qemu-test/src/dtc/tests/appendprop1.c
DEP /tmp/qemu-test/src/dtc/tests/del_node.c
DEP /tmp/qemu-test/src/dtc/tests/del_property.c
DEP /tmp/qemu-test/src/dtc/tests/set_name.c
DEP /tmp/qemu-test/src/dtc/tests/setprop.c
DEP /tmp/qemu-test/src/dtc/tests/rw_tree1.c
DEP /tmp/qemu-test/src/dtc/tests/open_pack.c
DEP /tmp/qemu-test/src/dtc/tests/nopulate.c
DEP /tmp/qemu-test/src/dtc/tests/mangle-layout.c
DEP /tmp/qemu-test/src/dtc/tests/move_and_save.c
DEP /tmp/qemu-test/src/dtc/tests/sw_tree1.c
DEP /tmp/qemu-test/src/dtc/tests/nop_node.c
DEP /tmp/qemu-test/src/dtc/tests/nop_property.c
DEP /tmp/qemu-test/src/dtc/tests/setprop_inplace.c
DEP /tmp/qemu-test/src/dtc/tests/stringlist.c
DEP /tmp/qemu-test/src/dtc/tests/addr_size_cells.c
DEP /tmp/qemu-test/src/dtc/tests/notfound.c
DEP /tmp/qemu-test/src/dtc/tests/sized_cells.c
DEP /tmp/qemu-test/src/dtc/tests/char_literal.c
DEP /tmp/qemu-test/src/dtc/tests/get_alias.c
DEP /tmp/qemu-test/src/dtc/tests/node_offset_by_compatible.c
DEP /tmp/qemu-test/src/dtc/tests/node_check_compatible.c
DEP /tmp/qemu-test/src/dtc/tests/node_offset_by_phandle.c
DEP /tmp/qemu-test/src/dtc/tests/node_offset_by_prop_value.c
DEP /tmp/qemu-test/src/dtc/tests/parent_offset.c
DEP /tmp/qemu-test/src/dtc/tests/supernode_atdepth_offset.c
DEP /tmp/qemu-test/src/dtc/tests/get_path.c
DEP /tmp/qemu-test/src/dtc/tests/get_phandle.c
DEP /tmp/qemu-test/src/dtc/tests/getprop.c
DEP /tmp/qemu-test/src/dtc/tests/get_name.c
DEP /tmp/qemu-test/src/dtc/tests/path_offset.c
DEP /tmp/qemu-test/src/dtc/tests/subnode_offset.c
DEP /tmp/qemu-test/src/dtc/tests/find_property.c
DEP /tmp/qemu-test/src/dtc/tests/root_node.c
DEP /tmp/qemu-test/src/dtc/tests/get_mem_rsv.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_overlay.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_addresses.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_empty_tree.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_strerror.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_rw.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_sw.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_wip.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_ro.c
DEP /tmp/qemu-test/src/dtc/util.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt.c
DEP /tmp/qemu-test/src/dtc/fdtput.c
DEP /tmp/qemu-test/src/dtc/fdtget.c
DEP /tmp/qemu-test/src/dtc/fdtdump.c
LEX convert-dtsv0-lexer.lex.c
make[1]: flex: Command not found
DEP /tmp/qemu-test/src/dtc/srcpos.c
BISON dtc-parser.tab.c
make[1]: bison: Command not found
LEX dtc-lexer.lex.c
make[1]: flex: Command not found
DEP /tmp/qemu-test/src/dtc/treesource.c
DEP /tmp/qemu-test/src/dtc/livetree.c
DEP /tmp/qemu-test/src/dtc/fstree.c
DEP /tmp/qemu-test/src/dtc/flattree.c
DEP /tmp/qemu-test/src/dtc/dtc.c
DEP /tmp/qemu-test/src/dtc/data.c
DEP /tmp/qemu-test/src/dtc/checks.c
CHK version_gen.h
LEX convert-dtsv0-lexer.lex.c
make[1]: flex: Command not found
LEX dtc-lexer.lex.c
make[1]: flex: Command not found
BISON dtc-parser.tab.c
UPD version_gen.h
make[1]: bison: Command not found
DEP /tmp/qemu-test/src/dtc/util.c
LEX convert-dtsv0-lexer.lex.c
make[1]: flex: Command not found
LEX dtc-lexer.lex.c
BISON dtc-parser.tab.c
make[1]: flex: Command not found
make[1]: bison: Command not found
CC libfdt/fdt.o
CC libfdt/fdt_ro.o
CC libfdt/fdt_wip.o
CC libfdt/fdt_sw.o
CC libfdt/fdt_strerror.o
CC libfdt/fdt_rw.o
CC libfdt/fdt_empty_tree.o
CC libfdt/fdt_addresses.o
CC libfdt/fdt_overlay.o
AR libfdt/libfdt.a
ar: creating libfdt/libfdt.a
a - libfdt/fdt.o
a - libfdt/fdt_ro.o
a - libfdt/fdt_wip.o
a - libfdt/fdt_sw.o
a - libfdt/fdt_rw.o
a - libfdt/fdt_strerror.o
a - libfdt/fdt_empty_tree.o
a - libfdt/fdt_addresses.o
a - libfdt/fdt_overlay.o
LEX convert-dtsv0-lexer.lex.c
make[1]: flex: Command not found
BISON dtc-parser.tab.c
LEX dtc-lexer.lex.c
make[1]: bison: Command not found
make[1]: flex: Command not found
CC tests/qemu-iotests/socket_scm_helper.o
GEN qga/qapi-generated/qga-qapi-types.c
GEN qga/qapi-generated/qga-qapi-types.h
GEN qga/qapi-generated/qga-qapi-visit.h
GEN qga/qapi-generated/qga-qapi-visit.c
GEN qga/qapi-generated/qga-qmp-commands.h
GEN qga/qapi-generated/qga-qmp-marshal.c
CC trace-root.o
CC util/trace.o
CC crypto/trace.o
CC io/trace.o
CC migration/trace.o
CC block/trace.o
CC backends/trace.o
CC hw/block/trace.o
CC hw/block/dataplane/trace.o
CC hw/char/trace.o
CC hw/intc/trace.o
CC hw/net/trace.o
CC hw/virtio/trace.o
CC hw/audio/trace.o
CC hw/misc/trace.o
CC hw/usb/trace.o
CC hw/scsi/trace.o
CC hw/nvram/trace.o
CC hw/display/trace.o
CC hw/input/trace.o
CC hw/timer/trace.o
CC hw/dma/trace.o
CC hw/sparc/trace.o
CC hw/sd/trace.o
CC hw/isa/trace.o
CC hw/mem/trace.o
CC hw/i386/trace.o
CC hw/i386/xen/trace.o
CC hw/9pfs/trace.o
CC hw/ppc/trace.o
CC hw/pci/trace.o
CC hw/s390x/trace.o
CC hw/vfio/trace.o
CC hw/acpi/trace.o
CC hw/arm/trace.o
CC hw/alpha/trace.o
CC hw/xen/trace.o
CC ui/trace.o
CC audio/trace.o
CC net/trace.o
CC target/arm/trace.o
CC target/i386/trace.o
CC target/mips/trace.o
CC target/sparc/trace.o
CC target/s390x/trace.o
CC target/ppc/trace.o
CC qom/trace.o
CC linux-user/trace.o
CC qapi/trace.o
CC qmp-introspect.o
CC qapi-types.o
CC qapi-visit.o
CC qapi-event.o
CC qapi/qapi-visit-core.o
CC qapi/qapi-dealloc-visitor.o
CC qapi/qobject-input-visitor.o
CC qapi/qobject-output-visitor.o
CC qapi/qmp-registry.o
CC qapi/qmp-dispatch.o
CC qapi/string-input-visitor.o
CC qapi/string-output-visitor.o
CC qapi/opts-visitor.o
CC qapi/qapi-clone-visitor.o
CC qapi/qmp-event.o
CC qapi/qapi-util.o
CC qobject/qnull.o
CC qobject/qint.o
CC qobject/qstring.o
CC qobject/qdict.o
CC qobject/qlist.o
CC qobject/qfloat.o
CC qobject/qbool.o
CC qobject/qjson.o
CC qobject/qobject.o
CC qobject/json-lexer.o
CC qobject/json-streamer.o
CC qobject/json-parser.o
CC trace/control.o
CC trace/qmp.o
CC util/osdep.o
CC util/cutils.o
CC util/unicode.o
CC util/qemu-timer-common.o
CC util/bufferiszero.o
CC util/lockcnt.o
CC util/aiocb.o
CC util/async.o
CC util/thread-pool.o
CC util/qemu-timer.o
CC util/main-loop.o
CC util/iohandler.o
CC util/aio-posix.o
CC util/compatfd.o
CC util/event_notifier-posix.o
CC util/mmap-alloc.o
CC util/oslib-posix.o
CC util/qemu-openpty.o
CC util/qemu-thread-posix.o
CC util/memfd.o
CC util/envlist.o
CC util/path.o
CC util/module.o
CC util/host-utils.o
CC util/bitmap.o
CC util/bitops.o
CC util/hbitmap.o
CC util/fifo8.o
CC util/acl.o
CC util/error.o
CC util/qemu-error.o
CC util/id.o
CC util/iov.o
CC util/qemu-config.o
CC util/qemu-sockets.o
CC util/uri.o
CC util/notify.o
CC util/qemu-option.o
CC util/qemu-progress.o
CC util/keyval.o
CC util/hexdump.o
CC util/crc32c.o
CC util/uuid.o
CC util/throttle.o
CC util/getauxval.o
CC util/readline.o
CC util/rcu.o
CC util/qemu-coroutine.o
CC util/qemu-coroutine-lock.o
CC util/qemu-coroutine-io.o
CC util/qemu-coroutine-sleep.o
CC util/coroutine-ucontext.o
CC util/buffer.o
CC util/timed-average.o
CC util/base64.o
CC util/log.o
CC util/qdist.o
CC util/qht.o
CC util/range.o
CC util/systemd.o
CC crypto/pbkdf-stub.o
CC stubs/arch-query-cpu-def.o
CC stubs/arch-query-cpu-model-expansion.o
CC stubs/arch-query-cpu-model-comparison.o
CC stubs/arch-query-cpu-model-baseline.o
CC stubs/bdrv-next-monitor-owned.o
CC stubs/blk-commit-all.o
CC stubs/blockdev-close-all-bdrv-states.o
CC stubs/clock-warp.o
CC stubs/cpu-get-clock.o
CC stubs/cpu-get-icount.o
CC stubs/dump.o
CC stubs/error-printf.o
CC stubs/fdset.o
CC stubs/gdbstub.o
CC stubs/get-vm-name.o
CC stubs/iothread.o
CC stubs/iothread-lock.o
CC stubs/is-daemonized.o
CC stubs/machine-init-done.o
CC stubs/migr-blocker.o
CC stubs/monitor.o
CC stubs/notify-event.o
CC stubs/qtest.o
CC stubs/replay.o
CC stubs/runstate-check.o
CC stubs/set-fd-handler.o
CC stubs/slirp.o
CC stubs/sysbus.o
CC stubs/trace-control.o
CC stubs/uuid.o
CC stubs/vm-stop.o
CC stubs/vmstate.o
CC stubs/qmp_pc_dimm_device_list.o
CC stubs/target-monitor-defs.o
CC stubs/target-get-monitor-def.o
CC stubs/pc_madt_cpu_entry.o
CC stubs/vmgenid.o
CC contrib/ivshmem-client/ivshmem-client.o
CC contrib/ivshmem-client/main.o
CC contrib/ivshmem-server/ivshmem-server.o
CC contrib/ivshmem-server/main.o
CC qemu-nbd.o
CC block.o
CC blockjob.o
CC qemu-io-cmds.o
CC replication.o
CC block/raw-format.o
CC block/qcow.o
CC block/vdi.o
CC block/vmdk.o
CC block/cloop.o
CC block/bochs.o
CC block/vpc.o
CC block/vvfat.o
CC block/dmg.o
CC block/qcow2.o
CC block/qcow2-refcount.o
CC block/qcow2-cluster.o
CC block/qcow2-snapshot.o
CC block/qcow2-cache.o
CC block/qed.o
CC block/qed-gencb.o
CC block/qed-l2-cache.o
CC block/qed-table.o
CC block/qed-cluster.o
CC block/qed-check.o
CC block/vhdx.o
CC block/vhdx-endian.o
CC block/vhdx-log.o
CC block/quorum.o
CC block/parallels.o
CC block/blkdebug.o
CC block/blkverify.o
CC block/blkreplay.o
CC block/block-backend.o
CC block/snapshot.o
CC block/qapi.o
CC block/file-posix.o
CC block/null.o
CC block/mirror.o
CC block/commit.o
CC block/io.o
CC block/throttle-groups.o
CC block/nbd.o
CC block/nbd-client.o
CC block/sheepdog.o
CC block/accounting.o
CC block/dirty-bitmap.o
CC block/write-threshold.o
CC block/backup.o
CC block/replication.o
CC block/crypto.o
CC nbd/server.o
CC nbd/client.o
CC nbd/common.o
CC crypto/hash.o
CC crypto/init.o
CC crypto/hash-glib.o
CC crypto/hmac.o
CC crypto/hmac-glib.o
CC crypto/aes.o
CC crypto/desrfb.o
CC crypto/cipher.o
CC crypto/tlscreds.o
CC crypto/tlscredsanon.o
CC crypto/tlscredsx509.o
CC crypto/tlssession.o
CC crypto/secret.o
CC crypto/random-platform.o
CC crypto/pbkdf.o
CC crypto/ivgen.o
CC crypto/ivgen-essiv.o
CC crypto/ivgen-plain.o
CC crypto/ivgen-plain64.o
CC crypto/afsplit.o
CC crypto/xts.o
CC crypto/block.o
CC crypto/block-qcow.o
CC crypto/block-luks.o
CC io/channel.o
CC io/channel-buffer.o
CC io/channel-command.o
CC io/channel-file.o
CC io/channel-socket.o
CC io/channel-tls.o
CC io/channel-watch.o
CC io/channel-websock.o
CC io/channel-util.o
CC io/dns-resolver.o
CC io/task.o
CC qom/object.o
CC qom/container.o
CC qom/qom-qobject.o
CC qom/object_interfaces.o
GEN qemu-img-cmds.h
CC qemu-io.o
CC qemu-bridge-helper.o
CC blockdev.o
CC blockdev-nbd.o
CC iothread.o
CC qdev-monitor.o
CC device-hotplug.o
CC os-posix.o
CC page_cache.o
CC accel.o
CC bt-host.o
CC bt-vhci.o
CC dma-helpers.o
CC vl.o
CC tpm.o
CC qmp-marshal.o
CC device_tree.o
CC qmp.o
CC hmp.o
CC cpus-common.o
CC audio/audio.o
CC audio/noaudio.o
CC audio/wavaudio.o
CC audio/mixeng.o
CC audio/sdlaudio.o
CC audio/ossaudio.o
CC audio/wavcapture.o
CC backends/rng.o
CC backends/rng-egd.o
CC backends/rng-random.o
CC backends/msmouse.o
CC backends/wctablet.o
CC backends/testdev.o
CC backends/tpm.o
CC backends/hostmem.o
CC backends/hostmem-ram.o
CC backends/hostmem-file.o
CC backends/cryptodev.o
CC backends/cryptodev-builtin.o
CC block/stream.o
CC disas/arm.o
CC disas/i386.o
CC fsdev/qemu-fsdev-dummy.o
CC fsdev/qemu-fsdev-opts.o
CC fsdev/qemu-fsdev-throttle.o
CC hw/acpi/core.o
CC hw/acpi/piix4.o
CC hw/acpi/pcihp.o
CC hw/acpi/ich9.o
CC hw/acpi/tco.o
CC hw/acpi/cpu_hotplug.o
CC hw/acpi/memory_hotplug.o
CC hw/acpi/cpu.o
CC hw/acpi/nvdimm.o
CC hw/acpi/vmgenid.o
CC hw/acpi/acpi_interface.o
CC hw/acpi/bios-linker-loader.o
CC hw/acpi/aml-build.o
CC hw/acpi/ipmi.o
CC hw/acpi/acpi-stub.o
CC hw/acpi/ipmi-stub.o
CC hw/audio/sb16.o
CC hw/audio/es1370.o
CC hw/audio/ac97.o
CC hw/audio/fmopl.o
CC hw/audio/adlib.o
CC hw/audio/gus.o
CC hw/audio/gusemu_hal.o
CC hw/audio/gusemu_mixer.o
CC hw/audio/cs4231a.o
CC hw/audio/intel-hda.o
CC hw/audio/hda-codec.o
CC hw/audio/pcspk.o
CC hw/audio/wm8750.o
CC hw/audio/pl041.o
CC hw/audio/lm4549.o
CC hw/audio/marvell_88w8618.o
CC hw/block/block.o
CC hw/block/cdrom.o
CC hw/block/hd-geometry.o
CC hw/block/fdc.o
CC hw/block/m25p80.o
CC hw/block/nand.o
CC hw/block/pflash_cfi01.o
CC hw/block/pflash_cfi02.o
CC hw/block/ecc.o
CC hw/block/onenand.o
CC hw/block/nvme.o
CC hw/bt/core.o
CC hw/bt/l2cap.o
CC hw/bt/sdp.o
CC hw/bt/hci.o
CC hw/bt/hid.o
CC hw/bt/hci-csr.o
CC hw/char/ipoctal232.o
CC hw/char/parallel.o
CC hw/char/pl011.o
CC hw/char/serial.o
CC hw/char/serial-isa.o
CC hw/char/serial-pci.o
CC hw/char/virtio-console.o
CC hw/char/cadence_uart.o
CC hw/char/debugcon.o
CC hw/char/imx_serial.o
CC hw/core/qdev.o
CC hw/core/qdev-properties.o
CC hw/core/bus.o
CC hw/core/reset.o
CC hw/core/fw-path-provider.o
CC hw/core/irq.o
CC hw/core/hotplug.o
CC hw/core/ptimer.o
CC hw/core/sysbus.o
CC hw/core/machine.o
CC hw/core/loader.o
CC hw/core/qdev-properties-system.o
CC hw/core/register.o
CC hw/core/or-irq.o
CC hw/core/platform-bus.o
CC hw/display/ads7846.o
CC hw/display/cirrus_vga.o
CC hw/display/pl110.o
CC hw/display/ssd0303.o
CC hw/display/ssd0323.o
CC hw/display/vga-pci.o
CC hw/display/vga-isa.o
CC hw/display/vmware_vga.o
CC hw/display/blizzard.o
CC hw/display/exynos4210_fimd.o
CC hw/display/framebuffer.o
CC hw/display/tc6393xb.o
CC hw/dma/pl080.o
CC hw/dma/pl330.o
CC hw/dma/i8257.o
CC hw/dma/xlnx-zynq-devcfg.o
CC hw/gpio/max7310.o
CC hw/gpio/pl061.o
CC hw/gpio/zaurus.o
CC hw/gpio/gpio_key.o
CC hw/i2c/core.o
CC hw/i2c/smbus.o
CC hw/i2c/smbus_eeprom.o
CC hw/i2c/i2c-ddc.o
CC hw/i2c/versatile_i2c.o
CC hw/i2c/smbus_ich9.o
CC hw/i2c/pm_smbus.o
CC hw/i2c/bitbang_i2c.o
CC hw/i2c/exynos4210_i2c.o
CC hw/i2c/imx_i2c.o
CC hw/i2c/aspeed_i2c.o
CC hw/ide/core.o
CC hw/ide/atapi.o
CC hw/ide/qdev.o
CC hw/ide/pci.o
CC hw/ide/isa.o
CC hw/ide/piix.o
CC hw/ide/microdrive.o
CC hw/ide/ahci.o
CC hw/ide/ich.o
CC hw/input/hid.o
CC hw/input/lm832x.o
CC hw/input/pckbd.o
CC hw/input/pl050.o
CC hw/input/ps2.o
CC hw/input/stellaris_input.o
CC hw/input/tsc2005.o
CC hw/input/vmmouse.o
CC hw/input/virtio-input.o
CC hw/input/virtio-input-hid.o
CC hw/input/virtio-input-host.o
CC hw/intc/i8259_common.o
CC hw/intc/i8259.o
CC hw/intc/pl190.o
CC hw/intc/imx_avic.o
CC hw/intc/realview_gic.o
CC hw/intc/ioapic_common.o
CC hw/intc/arm_gic_common.o
CC hw/intc/arm_gic.o
CC hw/intc/arm_gicv2m.o
CC hw/intc/arm_gicv3_common.o
CC hw/intc/arm_gicv3.o
CC hw/intc/arm_gicv3_dist.o
CC hw/intc/arm_gicv3_redist.o
CC hw/intc/arm_gicv3_its_common.o
CC hw/intc/intc.o
CC hw/ipack/ipack.o
CC hw/ipack/tpci200.o
CC hw/ipmi/ipmi.o
CC hw/ipmi/ipmi_bmc_sim.o
CC hw/ipmi/ipmi_bmc_extern.o
CC hw/ipmi/isa_ipmi_kcs.o
CC hw/ipmi/isa_ipmi_bt.o
CC hw/isa/isa-bus.o
CC hw/isa/apm.o
CC hw/mem/pc-dimm.o
CC hw/mem/nvdimm.o
CC hw/misc/applesmc.o
CC hw/misc/max111x.o
CC hw/misc/tmp105.o
CC hw/misc/debugexit.o
CC hw/misc/sga.o
CC hw/misc/pc-testdev.o
CC hw/misc/pci-testdev.o
CC hw/misc/unimp.o
CC hw/misc/arm_l2x0.o
CC hw/misc/arm_integrator_debug.o
CC hw/misc/arm11scu.o
CC hw/misc/a9scu.o
CC hw/net/ne2000.o
CC hw/net/eepro100.o
CC hw/net/pcnet-pci.o
CC hw/net/pcnet.o
CC hw/net/e1000.o
CC hw/net/net_tx_pkt.o
CC hw/net/e1000x_common.o
CC hw/net/net_rx_pkt.o
CC hw/net/e1000e.o
CC hw/net/e1000e_core.o
CC hw/net/rtl8139.o
CC hw/net/vmxnet3.o
CC hw/net/smc91c111.o
CC hw/net/lan9118.o
CC hw/net/ne2000-isa.o
CC hw/net/xgmac.o
CC hw/net/allwinner_emac.o
CC hw/net/imx_fec.o
CC hw/net/cadence_gem.o
CC hw/net/stellaris_enet.o
CC hw/net/rocker/rocker.o
CC hw/net/rocker/rocker_fp.o
CC hw/net/rocker/rocker_desc.o
CC hw/net/rocker/rocker_world.o
CC hw/net/rocker/rocker_of_dpa.o
CC hw/nvram/eeprom93xx.o
CC hw/nvram/fw_cfg.o
CC hw/nvram/chrp_nvram.o
CC hw/pci-bridge/pci_bridge_dev.o
CC hw/pci-bridge/pcie_root_port.o
CC hw/pci-bridge/gen_pcie_root_port.o
CC hw/pci-bridge/pci_expander_bridge.o
CC hw/pci-bridge/xio3130_upstream.o
CC hw/pci-bridge/xio3130_downstream.o
CC hw/pci-bridge/ioh3420.o
CC hw/pci-bridge/i82801b11.o
CC hw/pci-host/pam.o
CC hw/pci-host/versatile.o
CC hw/pci-host/piix.o
CC hw/pci-host/q35.o
CC hw/pci-host/gpex.o
CC hw/pci/pci.o
CC hw/pci/pci_bridge.o
CC hw/pci/msix.o
CC hw/pci/msi.o
CC hw/pci/shpc.o
CC hw/pci/slotid_cap.o
CC hw/pci/pci_host.o
CC hw/pci/pcie_host.o
CC hw/pci/pcie.o
CC hw/pci/pcie_aer.o
CC hw/pci/pcie_port.o
CC hw/pci/pci-stub.o
CC hw/pcmcia/pcmcia.o
CC hw/scsi/scsi-disk.o
CC hw/scsi/scsi-generic.o
CC hw/scsi/scsi-bus.o
CC hw/scsi/lsi53c895a.o
CC hw/scsi/mptsas.o
CC hw/scsi/mptconfig.o
CC hw/scsi/mptendian.o
CC hw/scsi/megasas.o
CC hw/scsi/vmw_pvscsi.o
CC hw/scsi/esp.o
CC hw/scsi/esp-pci.o
CC hw/sd/pl181.o
CC hw/sd/ssi-sd.o
CC hw/sd/sd.o
CC hw/sd/core.o
CC hw/sd/sdhci.o
CC hw/smbios/smbios.o
CC hw/smbios/smbios_type_38.o
CC hw/smbios/smbios-stub.o
CC hw/smbios/smbios_type_38-stub.o
CC hw/ssi/pl022.o
CC hw/ssi/ssi.o
CC hw/ssi/xilinx_spips.o
CC hw/ssi/aspeed_smc.o
CC hw/ssi/stm32f2xx_spi.o
CC hw/timer/arm_timer.o
CC hw/timer/arm_mptimer.o
CC hw/timer/armv7m_systick.o
CC hw/timer/a9gtimer.o
CC hw/timer/cadence_ttc.o
CC hw/timer/ds1338.o
CC hw/timer/hpet.o
CC hw/timer/i8254_common.o
CC hw/timer/i8254.o
CC hw/timer/pl031.o
CC hw/timer/twl92230.o
CC hw/timer/imx_epit.o
CC hw/timer/imx_gpt.o
CC hw/timer/stm32f2xx_timer.o
CC hw/timer/aspeed_timer.o
CC hw/tpm/tpm_tis.o
CC hw/tpm/tpm_passthrough.o
CC hw/tpm/tpm_util.o
CC hw/tpm/tpm_emulator.o
CC hw/usb/core.o
CC hw/usb/combined-packet.o
CC hw/usb/bus.o
CC hw/usb/libhw.o
CC hw/usb/desc.o
CC hw/usb/desc-msos.o
CC hw/usb/hcd-uhci.o
CC hw/usb/hcd-ohci.o
CC hw/usb/hcd-ehci.o
CC hw/usb/hcd-ehci-pci.o
CC hw/usb/hcd-ehci-sysbus.o
CC hw/usb/hcd-xhci.o
CC hw/usb/hcd-musb.o
CC hw/usb/dev-hub.o
CC hw/usb/dev-hid.o
CC hw/usb/dev-wacom.o
CC hw/usb/dev-storage.o
CC hw/usb/dev-uas.o
CC hw/usb/dev-audio.o
CC hw/usb/dev-serial.o
CC hw/usb/dev-network.o
CC hw/usb/dev-bluetooth.o
CC hw/usb/dev-smartcard-reader.o
CC hw/usb/dev-mtp.o
CC hw/usb/host-stub.o
CC hw/virtio/virtio-rng.o
CC hw/virtio/virtio-pci.o
CC hw/virtio/virtio-bus.o
CC hw/virtio/virtio-mmio.o
CC hw/virtio/vhost-stub.o
CC hw/watchdog/watchdog.o
CC hw/watchdog/wdt_i6300esb.o
CC hw/watchdog/wdt_ib700.o
CC hw/watchdog/wdt_aspeed.o
CC migration/migration.o
CC migration/socket.o
CC migration/fd.o
CC migration/exec.o
CC migration/tls.o
CC migration/colo-comm.o
CC migration/colo.o
CC migration/colo-failover.o
CC migration/vmstate.o
CC migration/qemu-file.o
CC migration/qemu-file-channel.o
CC migration/xbzrle.o
CC migration/postcopy-ram.o
CC migration/qjson.o
CC migration/block.o
CC net/net.o
CC net/queue.o
CC net/checksum.o
CC net/util.o
CC net/hub.o
CC net/socket.o
CC net/dump.o
CC net/eth.o
CC net/l2tpv3.o
CC net/tap.o
CC net/vhost-user.o
CC net/tap-linux.o
CC net/slirp.o
CC net/filter.o
CC net/filter-buffer.o
CC net/filter-mirror.o
CC net/colo-compare.o
CC net/colo.o
CC net/filter-rewriter.o
CC net/filter-replay.o
CC qom/cpu.o
CC replay/replay.o
CC replay/replay-internal.o
CC replay/replay-events.o
CC replay/replay-time.o
CC replay/replay-input.o
CC replay/replay-char.o
CC replay/replay-snapshot.o
/tmp/qemu-test/src/replay/replay-internal.c: In function ‘replay_put_array’:
/tmp/qemu-test/src/replay/replay-internal.c:65: warning: ignoring return value of ‘fwrite’, declared with attribute warn_unused_result
CC replay/replay-net.o
CC replay/replay-audio.o
CC slirp/cksum.o
CC slirp/if.o
CC slirp/ip_icmp.o
CC slirp/ip6_icmp.o
CC slirp/ip6_input.o
CC slirp/ip6_output.o
CC slirp/ip_input.o
CC slirp/ip_output.o
CC slirp/dnssearch.o
CC slirp/dhcpv6.o
CC slirp/slirp.o
CC slirp/mbuf.o
CC slirp/misc.o
CC slirp/sbuf.o
CC slirp/socket.o
CC slirp/tcp_input.o
CC slirp/tcp_output.o
CC slirp/tcp_subr.o
CC slirp/tcp_timer.o
CC slirp/udp.o
CC slirp/udp6.o
CC slirp/bootp.o
CC slirp/tftp.o
CC slirp/arp_table.o
/tmp/qemu-test/src/slirp/tcp_input.c: In function ‘tcp_input’:
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: ‘save_ip.ip_p’ may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: ‘save_ip.ip_len’ may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: ‘save_ip.ip_tos’ may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: ‘save_ip.ip_id’ may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: ‘save_ip.ip_off’ may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: ‘save_ip.ip_ttl’ may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: ‘save_ip.ip_sum’ may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: ‘save_ip.ip_src.s_addr’ may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:219: warning: ‘save_ip.ip_dst.s_addr’ may be used uninitialized in this function
/tmp/qemu-test/src/slirp/tcp_input.c:220: warning: ‘save_ip6.ip_nh’ may be used uninitialized in this function
CC slirp/ndp_table.o
CC ui/keymaps.o
CC ui/console.o
CC ui/cursor.o
CC ui/qemu-pixman.o
CC ui/input.o
CC ui/input-keymap.o
CC ui/input-legacy.o
CC ui/input-linux.o
CC ui/sdl.o
CC ui/sdl_zoom.o
CC ui/x_keymap.o
CC ui/vnc.o
CC ui/vnc-enc-zlib.o
CC ui/vnc-enc-hextile.o
CC ui/vnc-enc-tight.o
CC ui/vnc-palette.o
CC ui/vnc-enc-zrle.o
CC ui/vnc-auth-vencrypt.o
CC ui/vnc-ws.o
CC ui/vnc-jobs.o
CC chardev/char.o
CC chardev/char-fd.o
CC chardev/char-file.o
CC chardev/char-io.o
CC chardev/char-mux.o
CC chardev/char-null.o
CC chardev/char-parallel.o
CC chardev/char-pipe.o
CC chardev/char-pty.o
CC chardev/char-ringbuf.o
CC chardev/char-serial.o
CC chardev/char-socket.o
CC chardev/char-stdio.o
CC chardev/char-udp.o
LINK tests/qemu-iotests/socket_scm_helper
CC qga/commands.o
AS optionrom/multiboot.o
AS optionrom/linuxboot.o
CC qga/guest-agent-command-state.o
CC optionrom/linuxboot_dma.o
cc: unrecognized option '-no-integrated-as'
cc: unrecognized option '-no-integrated-as'
AS optionrom/kvmvapic.o
BUILD optionrom/multiboot.img
BUILD optionrom/linuxboot.img
BUILD optionrom/linuxboot_dma.img
BUILD optionrom/kvmvapic.img
BUILD optionrom/multiboot.raw
CC qga/main.o
BUILD optionrom/linuxboot.raw
BUILD optionrom/linuxboot_dma.raw
CC qga/commands-posix.o
CC qga/channel-posix.o
CC qga/qapi-generated/qga-qapi-types.o
CC qga/qapi-generated/qga-qapi-visit.o
CC qga/qapi-generated/qga-qmp-marshal.o
BUILD optionrom/kvmvapic.raw
SIGN optionrom/multiboot.bin
AR libqemuutil.a
AR libqemustub.a
SIGN optionrom/linuxboot.bin
SIGN optionrom/linuxboot_dma.bin
CC qemu-img.o
SIGN optionrom/kvmvapic.bin
LINK qemu-io
LINK qemu-bridge-helper
LINK qemu-ga
LINK ivshmem-client
LINK ivshmem-server
LINK qemu-nbd
LINK qemu-img
GEN aarch64-softmmu/hmp-commands.h
GEN aarch64-softmmu/hmp-commands-info.h
GEN aarch64-softmmu/config-target.h
CC aarch64-softmmu/exec.o
CC aarch64-softmmu/translate-all.o
CC aarch64-softmmu/cpu-exec-common.o
CC aarch64-softmmu/translate-common.o
CC aarch64-softmmu/cpu-exec.o
GEN x86_64-softmmu/hmp-commands.h
GEN x86_64-softmmu/hmp-commands-info.h
GEN x86_64-softmmu/config-target.h
CC aarch64-softmmu/tcg/tcg.o
CC x86_64-softmmu/exec.o
CC x86_64-softmmu/translate-all.o
CC aarch64-softmmu/tcg/tcg-op.o
CC x86_64-softmmu/cpu-exec.o
CC aarch64-softmmu/tcg/optimize.o
CC x86_64-softmmu/translate-common.o
CC aarch64-softmmu/tcg/tcg-common.o
CC aarch64-softmmu/fpu/softfloat.o
CC aarch64-softmmu/disas.o
CC aarch64-softmmu/tcg-runtime.o
GEN aarch64-softmmu/gdbstub-xml.c
CC aarch64-softmmu/hax-stub.o
CC aarch64-softmmu/kvm-stub.o
CC aarch64-softmmu/arch_init.o
CC aarch64-softmmu/cpus.o
CC aarch64-softmmu/monitor.o
CC aarch64-softmmu/gdbstub.o
CC aarch64-softmmu/balloon.o
CC aarch64-softmmu/ioport.o
CC x86_64-softmmu/cpu-exec-common.o
CC aarch64-softmmu/numa.o
CC aarch64-softmmu/qtest.o
CC aarch64-softmmu/bootdevice.o
CC x86_64-softmmu/tcg/tcg.o
CC aarch64-softmmu/memory.o
CC aarch64-softmmu/cputlb.o
CC aarch64-softmmu/memory_mapping.o
CC aarch64-softmmu/dump.o
CC aarch64-softmmu/migration/ram.o
CC aarch64-softmmu/migration/savevm.o
CC aarch64-softmmu/xen-common-stub.o
CC aarch64-softmmu/xen-hvm-stub.o
CC aarch64-softmmu/hw/adc/stm32f2xx_adc.o
CC aarch64-softmmu/hw/block/virtio-blk.o
CC aarch64-softmmu/hw/block/dataplane/virtio-blk.o
CC aarch64-softmmu/hw/char/exynos4210_uart.o
CC aarch64-softmmu/hw/char/omap_uart.o
CC x86_64-softmmu/tcg/tcg-op.o
CC aarch64-softmmu/hw/char/digic-uart.o
CC aarch64-softmmu/hw/char/stm32f2xx_usart.o
CC x86_64-softmmu/tcg/optimize.o
CC x86_64-softmmu/tcg/tcg-common.o
CC x86_64-softmmu/fpu/softfloat.o
CC x86_64-softmmu/disas.o
CC x86_64-softmmu/tcg-runtime.o
CC x86_64-softmmu/hax-stub.o
CC aarch64-softmmu/hw/char/bcm2835_aux.o
CC aarch64-softmmu/hw/char/virtio-serial-bus.o
CC aarch64-softmmu/hw/core/nmi.o
CC aarch64-softmmu/hw/core/generic-loader.o
CC x86_64-softmmu/arch_init.o
CC aarch64-softmmu/hw/core/null-machine.o
CC x86_64-softmmu/cpus.o
CC aarch64-softmmu/hw/cpu/arm11mpcore.o
CC x86_64-softmmu/monitor.o
CC x86_64-softmmu/gdbstub.o
CC x86_64-softmmu/balloon.o
CC x86_64-softmmu/ioport.o
CC x86_64-softmmu/numa.o
CC aarch64-softmmu/hw/cpu/realview_mpcore.o
CC aarch64-softmmu/hw/cpu/a9mpcore.o
CC x86_64-softmmu/qtest.o
CC x86_64-softmmu/bootdevice.o
CC aarch64-softmmu/hw/cpu/a15mpcore.o
CC x86_64-softmmu/kvm-all.o
CC aarch64-softmmu/hw/cpu/core.o
CC x86_64-softmmu/memory.o
CC x86_64-softmmu/cputlb.o
CC x86_64-softmmu/memory_mapping.o
CC aarch64-softmmu/hw/display/omap_dss.o
CC x86_64-softmmu/dump.o
CC x86_64-softmmu/migration/ram.o
CC aarch64-softmmu/hw/display/omap_lcdc.o
CC x86_64-softmmu/migration/savevm.o
CC x86_64-softmmu/xen-common-stub.o
CC aarch64-softmmu/hw/display/pxa2xx_lcd.o
CC x86_64-softmmu/xen-hvm-stub.o
CC x86_64-softmmu/hw/block/virtio-blk.o
CC x86_64-softmmu/hw/block/dataplane/virtio-blk.o
CC x86_64-softmmu/hw/char/virtio-serial-bus.o
CC x86_64-softmmu/hw/core/nmi.o
CC x86_64-softmmu/hw/core/generic-loader.o
CC x86_64-softmmu/hw/core/null-machine.o
CC x86_64-softmmu/hw/cpu/core.o
CC aarch64-softmmu/hw/display/bcm2835_fb.o
CC aarch64-softmmu/hw/display/vga.o
CC aarch64-softmmu/hw/display/virtio-gpu.o
CC aarch64-softmmu/hw/display/virtio-gpu-3d.o
CC aarch64-softmmu/hw/display/virtio-gpu-pci.o
CC aarch64-softmmu/hw/display/dpcd.o
CC x86_64-softmmu/hw/display/vga.o
CC aarch64-softmmu/hw/display/xlnx_dp.o
CC aarch64-softmmu/hw/dma/xlnx_dpdma.o
CC aarch64-softmmu/hw/dma/omap_dma.o
CC x86_64-softmmu/hw/display/virtio-gpu.o
CC x86_64-softmmu/hw/display/virtio-gpu-3d.o
CC aarch64-softmmu/hw/dma/soc_dma.o
CC x86_64-softmmu/hw/display/virtio-gpu-pci.o
CC aarch64-softmmu/hw/dma/pxa2xx_dma.o
CC aarch64-softmmu/hw/dma/bcm2835_dma.o
CC x86_64-softmmu/hw/display/virtio-vga.o
CC aarch64-softmmu/hw/gpio/omap_gpio.o
CC x86_64-softmmu/hw/intc/apic.o
CC aarch64-softmmu/hw/gpio/imx_gpio.o
CC aarch64-softmmu/hw/gpio/bcm2835_gpio.o
CC aarch64-softmmu/hw/i2c/omap_i2c.o
CC aarch64-softmmu/hw/input/pxa2xx_keypad.o
CC aarch64-softmmu/hw/input/tsc210x.o
CC x86_64-softmmu/hw/intc/apic_common.o
CC x86_64-softmmu/hw/intc/ioapic.o
CC x86_64-softmmu/hw/isa/lpc_ich9.o
CC aarch64-softmmu/hw/intc/armv7m_nvic.o
CC x86_64-softmmu/hw/misc/vmport.o
CC x86_64-softmmu/hw/misc/ivshmem.o
CC x86_64-softmmu/hw/misc/pvpanic.o
CC aarch64-softmmu/hw/intc/exynos4210_gic.o
CC aarch64-softmmu/hw/intc/exynos4210_combiner.o
CC x86_64-softmmu/hw/misc/edu.o
CC aarch64-softmmu/hw/intc/omap_intc.o
CC aarch64-softmmu/hw/intc/bcm2835_ic.o
CC x86_64-softmmu/hw/misc/hyperv_testdev.o
CC x86_64-softmmu/hw/net/virtio-net.o
CC aarch64-softmmu/hw/intc/bcm2836_control.o
CC aarch64-softmmu/hw/intc/allwinner-a10-pic.o
CC x86_64-softmmu/hw/net/vhost_net.o
CC x86_64-softmmu/hw/scsi/virtio-scsi.o
CC x86_64-softmmu/hw/scsi/virtio-scsi-dataplane.o
CC aarch64-softmmu/hw/intc/aspeed_vic.o
CC x86_64-softmmu/hw/scsi/vhost-scsi.o
CC aarch64-softmmu/hw/intc/arm_gicv3_cpuif.o
CC x86_64-softmmu/hw/timer/mc146818rtc.o
CC x86_64-softmmu/hw/vfio/common.o
CC x86_64-softmmu/hw/vfio/pci.o
CC x86_64-softmmu/hw/vfio/pci-quirks.o
CC x86_64-softmmu/hw/vfio/platform.o
CC x86_64-softmmu/hw/vfio/spapr.o
CC x86_64-softmmu/hw/virtio/virtio.o
CC aarch64-softmmu/hw/misc/ivshmem.o
CC x86_64-softmmu/hw/virtio/virtio-balloon.o
CC x86_64-softmmu/hw/virtio/vhost.o
CC x86_64-softmmu/hw/virtio/vhost-backend.o
CC aarch64-softmmu/hw/misc/arm_sysctl.o
CC x86_64-softmmu/hw/virtio/vhost-user.o
CC x86_64-softmmu/hw/virtio/vhost-vsock.o
CC x86_64-softmmu/hw/virtio/virtio-crypto.o
CC aarch64-softmmu/hw/misc/cbus.o
CC x86_64-softmmu/hw/virtio/virtio-crypto-pci.o
CC aarch64-softmmu/hw/misc/exynos4210_pmu.o
CC x86_64-softmmu/hw/i386/multiboot.o
CC aarch64-softmmu/hw/misc/exynos4210_clk.o
CC x86_64-softmmu/hw/i386/pc.o
CC x86_64-softmmu/hw/i386/pc_piix.o
CC x86_64-softmmu/hw/i386/pc_q35.o
CC x86_64-softmmu/hw/i386/pc_sysfw.o
CC aarch64-softmmu/hw/misc/imx_ccm.o
CC aarch64-softmmu/hw/misc/imx31_ccm.o
CC aarch64-softmmu/hw/misc/imx25_ccm.o
CC x86_64-softmmu/hw/i386/x86-iommu.o
CC aarch64-softmmu/hw/misc/imx6_ccm.o
CC aarch64-softmmu/hw/misc/imx6_src.o
CC aarch64-softmmu/hw/misc/mst_fpga.o
CC x86_64-softmmu/hw/i386/intel_iommu.o
/tmp/qemu-test/src/hw/i386/pc_piix.c: In function ‘igd_passthrough_isa_bridge_create’:
/tmp/qemu-test/src/hw/i386/pc_piix.c:1055: warning: ‘pch_rev_id’ may be used uninitialized in this function
CC aarch64-softmmu/hw/misc/omap_clk.o
CC aarch64-softmmu/hw/misc/omap_gpmc.o
CC x86_64-softmmu/hw/i386/amd_iommu.o
CC aarch64-softmmu/hw/misc/omap_l4.o
CC aarch64-softmmu/hw/misc/omap_sdrc.o
CC x86_64-softmmu/hw/i386/kvmvapic.o
CC aarch64-softmmu/hw/misc/omap_tap.o
CC aarch64-softmmu/hw/misc/bcm2835_mbox.o
CC aarch64-softmmu/hw/misc/bcm2835_property.o
CC aarch64-softmmu/hw/misc/bcm2835_rng.o
CC aarch64-softmmu/hw/misc/zynq_slcr.o
CC aarch64-softmmu/hw/misc/zynq-xadc.o
CC aarch64-softmmu/hw/misc/stm32f2xx_syscfg.o
CC x86_64-softmmu/hw/i386/acpi-build.o
CC x86_64-softmmu/hw/i386/pci-assign-load-rom.o
CC aarch64-softmmu/hw/misc/edu.o
CC aarch64-softmmu/hw/misc/auxbus.o
CC aarch64-softmmu/hw/misc/aspeed_scu.o
CC aarch64-softmmu/hw/misc/aspeed_sdmc.o
CC aarch64-softmmu/hw/net/virtio-net.o
CC x86_64-softmmu/hw/i386/kvm/clock.o
CC x86_64-softmmu/hw/i386/kvm/apic.o
CC aarch64-softmmu/hw/net/vhost_net.o
CC aarch64-softmmu/hw/pcmcia/pxa2xx.o
CC aarch64-softmmu/hw/scsi/virtio-scsi.o
CC x86_64-softmmu/hw/i386/kvm/i8259.o
CC aarch64-softmmu/hw/scsi/virtio-scsi-dataplane.o
CC aarch64-softmmu/hw/scsi/vhost-scsi.o
CC aarch64-softmmu/hw/sd/omap_mmc.o
CC x86_64-softmmu/hw/i386/kvm/ioapic.o
CC x86_64-softmmu/hw/i386/kvm/i8254.o
CC aarch64-softmmu/hw/sd/pxa2xx_mmci.o
CC aarch64-softmmu/hw/sd/bcm2835_sdhost.o
CC x86_64-softmmu/hw/i386/kvm/pci-assign.o
/tmp/qemu-test/src/hw/i386/acpi-build.c: In function ‘build_append_pci_bus_devices’:
/tmp/qemu-test/src/hw/i386/acpi-build.c:496: warning: ‘notify_method’ may be used uninitialized in this function
CC aarch64-softmmu/hw/ssi/omap_spi.o
CC x86_64-softmmu/target/i386/translate.o
CC aarch64-softmmu/hw/ssi/imx_spi.o
CC aarch64-softmmu/hw/timer/exynos4210_mct.o
CC x86_64-softmmu/target/i386/helper.o
CC aarch64-softmmu/hw/timer/exynos4210_pwm.o
CC aarch64-softmmu/hw/timer/exynos4210_rtc.o
CC aarch64-softmmu/hw/timer/omap_gptimer.o
CC aarch64-softmmu/hw/timer/omap_synctimer.o
CC aarch64-softmmu/hw/timer/pxa2xx_timer.o
CC aarch64-softmmu/hw/timer/digic-timer.o
CC aarch64-softmmu/hw/timer/allwinner-a10-pit.o
CC aarch64-softmmu/hw/usb/tusb6010.o
CC aarch64-softmmu/hw/vfio/common.o
CC x86_64-softmmu/target/i386/cpu.o
CC x86_64-softmmu/target/i386/bpt_helper.o
CC aarch64-softmmu/hw/vfio/pci.o
CC aarch64-softmmu/hw/vfio/pci-quirks.o
CC aarch64-softmmu/hw/vfio/platform.o
CC aarch64-softmmu/hw/vfio/calxeda-xgmac.o
CC x86_64-softmmu/target/i386/excp_helper.o
CC aarch64-softmmu/hw/vfio/amd-xgbe.o
CC aarch64-softmmu/hw/vfio/spapr.o
CC x86_64-softmmu/target/i386/fpu_helper.o
CC aarch64-softmmu/hw/virtio/virtio.o
CC aarch64-softmmu/hw/virtio/virtio-balloon.o
CC x86_64-softmmu/target/i386/cc_helper.o
CC aarch64-softmmu/hw/virtio/vhost.o
CC aarch64-softmmu/hw/virtio/vhost-backend.o
CC aarch64-softmmu/hw/virtio/vhost-user.o
CC aarch64-softmmu/hw/virtio/vhost-vsock.o
CC aarch64-softmmu/hw/virtio/virtio-crypto.o
CC x86_64-softmmu/target/i386/int_helper.o
CC aarch64-softmmu/hw/virtio/virtio-crypto-pci.o
CC aarch64-softmmu/hw/arm/boot.o
CC aarch64-softmmu/hw/arm/collie.o
CC aarch64-softmmu/hw/arm/exynos4_boards.o
CC aarch64-softmmu/hw/arm/gumstix.o
CC aarch64-softmmu/hw/arm/highbank.o
CC aarch64-softmmu/hw/arm/digic_boards.o
CC x86_64-softmmu/target/i386/svm_helper.o
CC aarch64-softmmu/hw/arm/integratorcp.o
CC aarch64-softmmu/hw/arm/mainstone.o
CC aarch64-softmmu/hw/arm/musicpal.o
CC aarch64-softmmu/hw/arm/nseries.o
CC aarch64-softmmu/hw/arm/omap_sx1.o
CC x86_64-softmmu/target/i386/smm_helper.o
CC aarch64-softmmu/hw/arm/palm.o
CC aarch64-softmmu/hw/arm/realview.o
CC aarch64-softmmu/hw/arm/spitz.o
CC aarch64-softmmu/hw/arm/stellaris.o
CC aarch64-softmmu/hw/arm/tosa.o
CC x86_64-softmmu/target/i386/misc_helper.o
CC x86_64-softmmu/target/i386/mem_helper.o
CC aarch64-softmmu/hw/arm/versatilepb.o
CC aarch64-softmmu/hw/arm/vexpress.o
CC aarch64-softmmu/hw/arm/virt.o
CC aarch64-softmmu/hw/arm/xilinx_zynq.o
CC x86_64-softmmu/target/i386/seg_helper.o
CC x86_64-softmmu/target/i386/mpx_helper.o
CC aarch64-softmmu/hw/arm/z2.o
CC aarch64-softmmu/hw/arm/virt-acpi-build.o
CC aarch64-softmmu/hw/arm/netduino2.o
CC aarch64-softmmu/hw/arm/sysbus-fdt.o
CC aarch64-softmmu/hw/arm/armv7m.o
CC aarch64-softmmu/hw/arm/exynos4210.o
CC aarch64-softmmu/hw/arm/pxa2xx.o
CC aarch64-softmmu/hw/arm/pxa2xx_gpio.o
CC x86_64-softmmu/target/i386/gdbstub.o
CC aarch64-softmmu/hw/arm/pxa2xx_pic.o
CC x86_64-softmmu/target/i386/machine.o
CC aarch64-softmmu/hw/arm/digic.o
CC aarch64-softmmu/hw/arm/omap1.o
CC x86_64-softmmu/target/i386/arch_memory_mapping.o
CC aarch64-softmmu/hw/arm/omap2.o
CC aarch64-softmmu/hw/arm/strongarm.o
CC aarch64-softmmu/hw/arm/allwinner-a10.o
CC x86_64-softmmu/target/i386/arch_dump.o
CC x86_64-softmmu/target/i386/monitor.o
CC aarch64-softmmu/hw/arm/cubieboard.o
CC x86_64-softmmu/target/i386/kvm.o
CC aarch64-softmmu/hw/arm/bcm2835_peripherals.o
CC x86_64-softmmu/target/i386/hyperv.o
CC aarch64-softmmu/hw/arm/bcm2836.o
GEN trace/generated-helpers.c
CC aarch64-softmmu/hw/arm/raspi.o
CC x86_64-softmmu/trace/control-target.o
CC aarch64-softmmu/hw/arm/stm32f205_soc.o
CC aarch64-softmmu/hw/arm/xlnx-zynqmp.o
CC aarch64-softmmu/hw/arm/xlnx-ep108.o
CC aarch64-softmmu/hw/arm/fsl-imx25.o
CC aarch64-softmmu/hw/arm/imx25_pdk.o
CC aarch64-softmmu/hw/arm/fsl-imx31.o
CC aarch64-softmmu/hw/arm/kzm.o
CC aarch64-softmmu/hw/arm/fsl-imx6.o
CC aarch64-softmmu/hw/arm/sabrelite.o
CC x86_64-softmmu/trace/generated-helpers.o
CC aarch64-softmmu/hw/arm/aspeed_soc.o
CC aarch64-softmmu/hw/arm/aspeed.o
CC aarch64-softmmu/target/arm/arm-semi.o
CC aarch64-softmmu/target/arm/machine.o
CC aarch64-softmmu/target/arm/psci.o
CC aarch64-softmmu/target/arm/arch_dump.o
CC aarch64-softmmu/target/arm/monitor.o
CC aarch64-softmmu/target/arm/kvm-stub.o
CC aarch64-softmmu/target/arm/translate.o
CC aarch64-softmmu/target/arm/op_helper.o
CC aarch64-softmmu/target/arm/helper.o
CC aarch64-softmmu/target/arm/cpu.o
CC aarch64-softmmu/target/arm/neon_helper.o
CC aarch64-softmmu/target/arm/iwmmxt_helper.o
CC aarch64-softmmu/target/arm/gdbstub.o
CC aarch64-softmmu/target/arm/cpu64.o
LINK x86_64-softmmu/qemu-system-x86_64
CC aarch64-softmmu/target/arm/translate-a64.o
CC aarch64-softmmu/target/arm/helper-a64.o
CC aarch64-softmmu/target/arm/gdbstub64.o
CC aarch64-softmmu/target/arm/crypto_helper.o
CC aarch64-softmmu/target/arm/arm-powerctl.o
GEN trace/generated-helpers.c
CC aarch64-softmmu/trace/control-target.o
CC aarch64-softmmu/gdbstub-xml.o
CC aarch64-softmmu/trace/generated-helpers.o
/tmp/qemu-test/src/target/arm/translate-a64.c: In function ‘handle_shri_with_rndacc’:
/tmp/qemu-test/src/target/arm/translate-a64.c:6359: warning: ‘tcg_src_hi’ may be used uninitialized in this function
/tmp/qemu-test/src/target/arm/translate-a64.c: In function ‘disas_simd_scalar_two_reg_misc’:
/tmp/qemu-test/src/target/arm/translate-a64.c:8086: warning: ‘rmode’ may be used uninitialized in this function
LINK aarch64-softmmu/qemu-system-aarch64
LEX convert-dtsv0-lexer.lex.c
BISON dtc-parser.tab.c
make[1]: flex: Command not found
make[1]: bison: Command not found
LEX dtc-lexer.lex.c
make[1]: flex: Command not found
TEST tests/qapi-schema/alternate-any.out
TEST tests/qapi-schema/alternate-clash.out
TEST tests/qapi-schema/alternate-base.out
TEST tests/qapi-schema/alternate-conflict-dict.out
TEST tests/qapi-schema/alternate-array.out
TEST tests/qapi-schema/alternate-conflict-string.out
TEST tests/qapi-schema/alternate-nested.out
TEST tests/qapi-schema/alternate-empty.out
TEST tests/qapi-schema/alternate-unknown.out
TEST tests/qapi-schema/args-alternate.out
TEST tests/qapi-schema/args-any.out
TEST tests/qapi-schema/args-array-empty.out
TEST tests/qapi-schema/args-array-unknown.out
TEST tests/qapi-schema/args-bad-boxed.out
TEST tests/qapi-schema/args-boxed-anon.out
TEST tests/qapi-schema/args-boxed-empty.out
TEST tests/qapi-schema/args-boxed-string.out
TEST tests/qapi-schema/args-int.out
TEST tests/qapi-schema/args-invalid.out
TEST tests/qapi-schema/args-member-array-bad.out
TEST tests/qapi-schema/args-member-case.out
TEST tests/qapi-schema/args-member-unknown.out
TEST tests/qapi-schema/args-name-clash.out
TEST tests/qapi-schema/args-union.out
TEST tests/qapi-schema/args-unknown.out
TEST tests/qapi-schema/bad-base.out
TEST tests/qapi-schema/bad-data.out
TEST tests/qapi-schema/bad-ident.out
TEST tests/qapi-schema/bad-type-bool.out
TEST tests/qapi-schema/bad-type-dict.out
TEST tests/qapi-schema/bad-type-int.out
TEST tests/qapi-schema/base-cycle-direct.out
TEST tests/qapi-schema/base-cycle-indirect.out
TEST tests/qapi-schema/command-int.out
TEST tests/qapi-schema/comments.out
TEST tests/qapi-schema/doc-bad-alternate-member.out
TEST tests/qapi-schema/doc-bad-command-arg.out
TEST tests/qapi-schema/doc-bad-symbol.out
TEST tests/qapi-schema/doc-bad-union-member.out
TEST tests/qapi-schema/doc-before-include.out
TEST tests/qapi-schema/doc-before-pragma.out
TEST tests/qapi-schema/doc-duplicated-arg.out
TEST tests/qapi-schema/doc-duplicated-return.out
TEST tests/qapi-schema/doc-duplicated-since.out
TEST tests/qapi-schema/doc-empty-arg.out
TEST tests/qapi-schema/doc-empty-section.out
TEST tests/qapi-schema/doc-empty-symbol.out
TEST tests/qapi-schema/doc-good.out
TEST tests/qapi-schema/doc-interleaved-section.out
TEST tests/qapi-schema/doc-invalid-end.out
TEST tests/qapi-schema/doc-invalid-end2.out
TEST tests/qapi-schema/doc-invalid-return.out
TEST tests/qapi-schema/doc-invalid-section.out
TEST tests/qapi-schema/doc-invalid-start.out
TEST tests/qapi-schema/doc-missing.out
TEST tests/qapi-schema/doc-missing-colon.out
TEST tests/qapi-schema/doc-missing-space.out
TEST tests/qapi-schema/doc-missing-expr.out
TEST tests/qapi-schema/doc-no-symbol.out
TEST tests/qapi-schema/double-data.out
TEST tests/qapi-schema/double-type.out
TEST tests/qapi-schema/duplicate-key.out
TEST tests/qapi-schema/empty.out
TEST tests/qapi-schema/enum-bad-name.out
TEST tests/qapi-schema/enum-bad-prefix.out
TEST tests/qapi-schema/enum-clash-member.out
TEST tests/qapi-schema/enum-dict-member.out
TEST tests/qapi-schema/enum-member-case.out
TEST tests/qapi-schema/enum-int-member.out
TEST tests/qapi-schema/enum-missing-data.out
TEST tests/qapi-schema/enum-wrong-data.out
TEST tests/qapi-schema/escape-outside-string.out
TEST tests/qapi-schema/escape-too-big.out
TEST tests/qapi-schema/escape-too-short.out
TEST tests/qapi-schema/event-boxed-empty.out
TEST tests/qapi-schema/event-case.out
TEST tests/qapi-schema/event-nest-struct.out
TEST tests/qapi-schema/flat-union-array-branch.out
TEST tests/qapi-schema/flat-union-bad-base.out
TEST tests/qapi-schema/flat-union-bad-discriminator.out
TEST tests/qapi-schema/flat-union-base-any.out
TEST tests/qapi-schema/flat-union-base-union.out
TEST tests/qapi-schema/flat-union-empty.out
TEST tests/qapi-schema/flat-union-clash-member.out
TEST tests/qapi-schema/flat-union-incomplete-branch.out
TEST tests/qapi-schema/flat-union-inline.out
TEST tests/qapi-schema/flat-union-int-branch.out
TEST tests/qapi-schema/flat-union-invalid-branch-key.out
TEST tests/qapi-schema/flat-union-invalid-discriminator.out
TEST tests/qapi-schema/flat-union-no-base.out
TEST tests/qapi-schema/flat-union-optional-discriminator.out
TEST tests/qapi-schema/flat-union-string-discriminator.out
TEST tests/qapi-schema/funny-char.out
TEST tests/qapi-schema/ident-with-escape.out
TEST tests/qapi-schema/include-before-err.out
TEST tests/qapi-schema/include-cycle.out
TEST tests/qapi-schema/include-extra-junk.out
TEST tests/qapi-schema/include-format-err.out
TEST tests/qapi-schema/include-nested-err.out
TEST tests/qapi-schema/include-no-file.out
TEST tests/qapi-schema/include-non-file.out
TEST tests/qapi-schema/include-relpath.out
TEST tests/qapi-schema/include-repetition.out
TEST tests/qapi-schema/include-self-cycle.out
TEST tests/qapi-schema/include-simple.out
TEST tests/qapi-schema/indented-expr.out
TEST tests/qapi-schema/leading-comma-list.out
TEST tests/qapi-schema/leading-comma-object.out
TEST tests/qapi-schema/missing-colon.out
TEST tests/qapi-schema/missing-comma-list.out
TEST tests/qapi-schema/missing-comma-object.out
TEST tests/qapi-schema/nested-struct-data.out
TEST tests/qapi-schema/missing-type.out
TEST tests/qapi-schema/non-objects.out
TEST tests/qapi-schema/pragma-doc-required-crap.out
TEST tests/qapi-schema/pragma-extra-junk.out
TEST tests/qapi-schema/pragma-name-case-whitelist-crap.out
TEST tests/qapi-schema/pragma-non-dict.out
TEST tests/qapi-schema/pragma-returns-whitelist-crap.out
TEST tests/qapi-schema/qapi-schema-test.out
TEST tests/qapi-schema/quoted-structural-chars.out
TEST tests/qapi-schema/redefined-builtin.out
TEST tests/qapi-schema/redefined-command.out
TEST tests/qapi-schema/redefined-event.out
TEST tests/qapi-schema/redefined-type.out
TEST tests/qapi-schema/reserved-command-q.out
TEST tests/qapi-schema/reserved-enum-q.out
TEST tests/qapi-schema/reserved-member-has.out
TEST tests/qapi-schema/reserved-member-q.out
TEST tests/qapi-schema/reserved-member-u.out
TEST tests/qapi-schema/reserved-member-underscore.out
TEST tests/qapi-schema/reserved-type-kind.out
TEST tests/qapi-schema/reserved-type-list.out
TEST tests/qapi-schema/returns-alternate.out
TEST tests/qapi-schema/returns-dict.out
TEST tests/qapi-schema/returns-array-bad.out
TEST tests/qapi-schema/returns-unknown.out
TEST tests/qapi-schema/returns-whitelist.out
TEST tests/qapi-schema/struct-base-clash-deep.out
TEST tests/qapi-schema/struct-base-clash.out
TEST tests/qapi-schema/struct-data-invalid.out
TEST tests/qapi-schema/struct-member-invalid.out
TEST tests/qapi-schema/trailing-comma-list.out
TEST tests/qapi-schema/trailing-comma-object.out
TEST tests/qapi-schema/type-bypass-bad-gen.out
TEST tests/qapi-schema/unclosed-list.out
TEST tests/qapi-schema/unclosed-object.out
TEST tests/qapi-schema/unclosed-string.out
TEST tests/qapi-schema/unicode-str.out
TEST tests/qapi-schema/union-base-empty.out
TEST tests/qapi-schema/union-base-no-discriminator.out
TEST tests/qapi-schema/union-branch-case.out
TEST tests/qapi-schema/union-clash-branches.out
TEST tests/qapi-schema/union-empty.out
TEST tests/qapi-schema/union-invalid-base.out
TEST tests/qapi-schema/union-optional-branch.out
TEST tests/qapi-schema/union-unknown.out
TEST tests/qapi-schema/unknown-escape.out
TEST tests/qapi-schema/unknown-expr-key.out
GEN tests/qapi-schema/doc-good.test.texi
CC tests/check-qdict.o
CC tests/test-char.o
CC tests/check-qint.o
CC tests/check-qfloat.o
CC tests/check-qstring.o
CC tests/check-qlist.o
CC tests/check-qnull.o
CC tests/check-qjson.o
CC tests/test-qobject-output-visitor.o
GEN tests/test-qapi-visit.c
GEN tests/test-qapi-types.c
GEN tests/test-qapi-event.c
GEN tests/test-qmp-introspect.c
CC tests/test-clone-visitor.o
CC tests/test-qobject-input-visitor.o
CC tests/test-qmp-commands.o
GEN tests/test-qmp-marshal.c
CC tests/test-string-input-visitor.o
CC tests/test-string-output-visitor.o
CC tests/test-qmp-event.o
CC tests/test-opts-visitor.o
CC tests/test-coroutine.o
CC tests/iothread.o
CC tests/test-visitor-serialization.o
CC tests/test-iov.o
CC tests/test-aio.o
CC tests/test-aio-multithread.o
CC tests/test-throttle.o
CC tests/test-thread-pool.o
CC tests/test-hbitmap.o
CC tests/test-blockjob.o
CC tests/test-blockjob-txn.o
CC tests/test-x86-cpuid.o
CC tests/test-xbzrle.o
CC tests/test-vmstate.o
CC tests/test-cutils.o
CC tests/test-shift128.o
CC tests/test-mul64.o
CC tests/test-int128.o
CC tests/rcutorture.o
CC tests/test-rcu-list.o
CC tests/test-qdist.o
/tmp/qemu-test/src/tests/test-int128.c:180: warning: ‘__noclone__’ attribute directive ignored
CC tests/test-qht.o
CC tests/test-qht-par.o
CC tests/qht-bench.o
CC tests/test-bitops.o
CC tests/test-bitcnt.o
CC tests/check-qom-proplist.o
CC tests/check-qom-interface.o
CC tests/test-qemu-opts.o
CC tests/test-keyval.o
CC tests/test-write-threshold.o
CC tests/test-crypto-hash.o
CC tests/test-crypto-hmac.o
CC tests/test-crypto-cipher.o
CC tests/test-crypto-secret.o
CC tests/test-qga.o
CC tests/libqtest.o
CC tests/test-timed-average.o
CC tests/test-io-task.o
CC tests/test-io-channel-socket.o
CC tests/io-channel-helpers.o
CC tests/test-io-channel-file.o
CC tests/test-io-channel-command.o
CC tests/test-io-channel-buffer.o
CC tests/test-base64.o
CC tests/test-crypto-ivgen.o
CC tests/test-crypto-afsplit.o
CC tests/test-crypto-xts.o
CC tests/test-crypto-block.o
CC tests/test-logging.o
CC tests/test-replication.o
CC tests/test-bufferiszero.o
CC tests/test-uuid.o
CC tests/ptimer-test.o
CC tests/ptimer-test-stubs.o
CC tests/test-qapi-util.o
CC tests/vhost-user-test.o
CC tests/libqos/pci.o
CC tests/libqos/fw_cfg.o
CC tests/libqos/malloc.o
CC tests/libqos/i2c.o
CC tests/libqos/libqos.o
CC tests/libqos/malloc-spapr.o
CC tests/libqos/libqos-spapr.o
CC tests/libqos/rtas.o
CC tests/libqos/pci-spapr.o
CC tests/libqos/pci-pc.o
CC tests/libqos/malloc-pc.o
CC tests/libqos/libqos-pc.o
CC tests/libqos/ahci.o
CC tests/libqos/virtio.o
CC tests/libqos/virtio-pci.o
CC tests/libqos/virtio-mmio.o
CC tests/libqos/malloc-generic.o
CC tests/endianness-test.o
CC tests/fdc-test.o
CC tests/ide-test.o
CC tests/ahci-test.o
CC tests/hd-geo-test.o
CC tests/boot-order-test.o
CC tests/bios-tables-test.o
CC tests/acpi-utils.o
CC tests/boot-sector.o
CC tests/boot-serial-test.o
CC tests/pxe-test.o
CC tests/rtc-test.o
/tmp/qemu-test/src/tests/ide-test.c: In function ‘cdrom_pio_impl’:
/tmp/qemu-test/src/tests/ide-test.c:803: warning: ignoring return value of ‘fwrite’, declared with attribute warn_unused_result
/tmp/qemu-test/src/tests/ide-test.c: In function ‘test_cdrom_dma’:
/tmp/qemu-test/src/tests/ide-test.c:899: warning: ignoring return value of ‘fwrite’, declared with attribute warn_unused_result
CC tests/ipmi-kcs-test.o
CC tests/ipmi-bt-test.o
CC tests/i440fx-test.o
CC tests/fw_cfg-test.o
CC tests/drive_del-test.o
CC tests/wdt_ib700-test.o
CC tests/tco-test.o
CC tests/e1000-test.o
CC tests/e1000e-test.o
CC tests/rtl8139-test.o
CC tests/pcnet-test.o
CC tests/eepro100-test.o
CC tests/ne2000-test.o
CC tests/nvme-test.o
CC tests/ac97-test.o
CC tests/es1370-test.o
CC tests/virtio-net-test.o
CC tests/virtio-balloon-test.o
CC tests/virtio-blk-test.o
CC tests/virtio-rng-test.o
CC tests/virtio-scsi-test.o
CC tests/virtio-serial-test.o
CC tests/virtio-console-test.o
CC tests/tpci200-test.o
CC tests/ipoctal232-test.o
CC tests/display-vga-test.o
CC tests/intel-hda-test.o
CC tests/ivshmem-test.o
CC tests/vmxnet3-test.o
CC tests/pvpanic-test.o
CC tests/i82801b11-test.o
CC tests/usb-hcd-ohci-test.o
CC tests/ioh3420-test.o
CC tests/libqos/usb.o
CC tests/usb-hcd-uhci-test.o
CC tests/usb-hcd-ehci-test.o
CC tests/usb-hcd-xhci-test.o
CC tests/pc-cpu-test.o
CC tests/q35-test.o
CC tests/test-netfilter.o
CC tests/test-filter-mirror.o
CC tests/test-filter-redirector.o
CC tests/postcopy-test.o
CC tests/test-x86-cpuid-compat.o
CC tests/qmp-test.o
CC tests/device-introspect-test.o
CC tests/qom-test.o
LINK tests/check-qdict
LINK tests/test-char
LINK tests/check-qfloat
LINK tests/check-qint
LINK tests/check-qstring
LINK tests/check-qlist
LINK tests/check-qnull
LINK tests/check-qjson
CC tests/test-qapi-visit.o
CC tests/test-qapi-types.o
CC tests/test-qapi-event.o
CC tests/test-qmp-introspect.o
CC tests/test-qmp-marshal.o
LINK tests/test-coroutine
LINK tests/test-iov
LINK tests/test-aio
LINK tests/test-aio-multithread
LINK tests/test-throttle
LINK tests/test-thread-pool
LINK tests/test-hbitmap
LINK tests/test-blockjob
LINK tests/test-blockjob-txn
LINK tests/test-x86-cpuid
LINK tests/test-xbzrle
LINK tests/test-vmstate
LINK tests/test-cutils
LINK tests/test-shift128
LINK tests/test-mul64
LINK tests/test-int128
LINK tests/rcutorture
LINK tests/test-rcu-list
LINK tests/test-qdist
LINK tests/test-qht
LINK tests/qht-bench
LINK tests/test-bitops
LINK tests/test-bitcnt
LINK tests/check-qom-interface
LINK tests/check-qom-proplist
LINK tests/test-qemu-opts
LINK tests/test-keyval
LINK tests/test-write-threshold
LINK tests/test-crypto-hash
LINK tests/test-crypto-hmac
LINK tests/test-crypto-cipher
LINK tests/test-crypto-secret
LINK tests/test-qga
LINK tests/test-timed-average
LINK tests/test-io-task
LINK tests/test-io-channel-socket
LINK tests/test-io-channel-file
LINK tests/test-io-channel-command
LINK tests/test-io-channel-buffer
LINK tests/test-base64
LINK tests/test-crypto-ivgen
LINK tests/test-crypto-afsplit
LINK tests/test-crypto-xts
LINK tests/test-crypto-block
LINK tests/test-logging
LINK tests/test-replication
LINK tests/test-bufferiszero
LINK tests/test-uuid
LINK tests/ptimer-test
LINK tests/test-qapi-util
LINK tests/vhost-user-test
LINK tests/endianness-test
LINK tests/fdc-test
LINK tests/ide-test
LINK tests/ahci-test
LINK tests/hd-geo-test
LINK tests/boot-order-test
LINK tests/bios-tables-test
LINK tests/boot-serial-test
LINK tests/pxe-test
LINK tests/rtc-test
LINK tests/ipmi-kcs-test
LINK tests/ipmi-bt-test
LINK tests/i440fx-test
LINK tests/fw_cfg-test
LINK tests/drive_del-test
LINK tests/wdt_ib700-test
LINK tests/tco-test
LINK tests/e1000-test
LINK tests/e1000e-test
LINK tests/rtl8139-test
LINK tests/pcnet-test
LINK tests/eepro100-test
LINK tests/ne2000-test
LINK tests/nvme-test
LINK tests/ac97-test
LINK tests/es1370-test
LINK tests/virtio-net-test
LINK tests/virtio-balloon-test
LINK tests/virtio-blk-test
LINK tests/virtio-rng-test
LINK tests/virtio-scsi-test
LINK tests/virtio-serial-test
LINK tests/virtio-console-test
LINK tests/tpci200-test
LINK tests/ipoctal232-test
LINK tests/display-vga-test
LINK tests/intel-hda-test
LINK tests/ivshmem-test
LINK tests/vmxnet3-test
LINK tests/pvpanic-test
LINK tests/i82801b11-test
LINK tests/ioh3420-test
LINK tests/usb-hcd-ohci-test
LINK tests/usb-hcd-uhci-test
LINK tests/usb-hcd-ehci-test
LINK tests/usb-hcd-xhci-test
LINK tests/pc-cpu-test
LINK tests/q35-test
LINK tests/test-netfilter
LINK tests/test-filter-mirror
LINK tests/test-filter-redirector
LINK tests/postcopy-test
LINK tests/test-x86-cpuid-compat
LINK tests/qmp-test
LINK tests/device-introspect-test
LINK tests/qom-test
GTESTER tests/check-qdict
GTESTER tests/test-char
GTESTER tests/check-qfloat
GTESTER tests/check-qint
GTESTER tests/check-qstring
GTESTER tests/check-qlist
GTESTER tests/check-qnull
GTESTER tests/check-qjson
LINK tests/test-qobject-output-visitor
LINK tests/test-clone-visitor
LINK tests/test-qobject-input-visitor
LINK tests/test-qmp-commands
LINK tests/test-string-input-visitor
LINK tests/test-string-output-visitor
LINK tests/test-qmp-event
LINK tests/test-opts-visitor
GTESTER tests/test-coroutine
LINK tests/test-visitor-serialization
GTESTER tests/test-iov
GTESTER tests/test-aio
GTESTER tests/test-throttle
GTESTER tests/test-aio-multithread
GTESTER tests/test-thread-pool
GTESTER tests/test-hbitmap
GTESTER tests/test-blockjob
GTESTER tests/test-blockjob-txn
GTESTER tests/test-x86-cpuid
GTESTER tests/test-xbzrle
GTESTER tests/test-vmstate
Failed to load simple/primitive:b_1
Failed to load simple/primitive:i64_2
Failed to load simple/primitive:i32_1
Failed to load simple/primitive:i32_1
Failed to load test/with_tmp:a
Failed to load test/tmp_child_parent:f
Failed to load test/tmp_child:parent
Failed to load test/with_tmp:tmp
Failed to load test/tmp_child:diff
Failed to load test/with_tmp:tmp
Failed to load test/tmp_child:diff
Failed to load test/with_tmp:tmp
GTESTER tests/test-cutils
GTESTER tests/test-shift128
GTESTER tests/test-mul64
GTESTER tests/test-int128
GTESTER tests/rcutorture
GTESTER tests/test-rcu-list
GTESTER tests/test-qdist
GTESTER tests/test-qht
LINK tests/test-qht-par
GTESTER tests/test-bitops
GTESTER tests/test-bitcnt
GTESTER tests/check-qom-interface
GTESTER tests/check-qom-proplist
GTESTER tests/test-qemu-opts
GTESTER tests/test-write-threshold
GTESTER tests/test-keyval
GTESTER tests/test-crypto-hash
GTESTER tests/test-crypto-hmac
GTESTER tests/test-crypto-cipher
GTESTER tests/test-crypto-secret
GTESTER tests/test-timed-average
GTESTER tests/test-qga
GTESTER tests/test-io-task
GTESTER tests/test-io-channel-socket
GTESTER tests/test-io-channel-file
GTESTER tests/test-io-channel-command
GTESTER tests/test-io-channel-buffer
GTESTER tests/test-base64
GTESTER tests/test-crypto-ivgen
GTESTER tests/test-crypto-afsplit
GTESTER tests/test-crypto-xts
GTESTER tests/test-crypto-block
GTESTER tests/test-logging
GTESTER tests/test-replication
GTESTER tests/test-bufferiszero
GTESTER tests/test-uuid
GTESTER tests/ptimer-test
GTESTER tests/test-qapi-util
GTESTER check-qtest-x86_64
GTESTER check-qtest-aarch64
GTESTER tests/test-qobject-output-visitor
GTESTER tests/test-clone-visitor
GTESTER tests/test-qobject-input-visitor
GTESTER tests/test-qmp-commands
GTESTER tests/test-string-input-visitor
GTESTER tests/test-string-output-visitor
GTESTER tests/test-qmp-event
GTESTER tests/test-opts-visitor
GTESTER tests/test-visitor-serialization
GTESTER tests/test-qht-par
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
Could not access KVM kernel module: No such file or directory
failed to initialize KVM: No such file or directory
Back to tcg accelerator.
make[1]: Leaving directory '/var/tmp/patchew-tester-tmp-ylr_f574/src'
BUILD fedora
make[1]: Entering directory '/var/tmp/patchew-tester-tmp-ylr_f574/src'
ARCHIVE qemu.tgz
ARCHIVE dtc.tgz
COPY RUNNER
RUN test-mingw in qemu:fedora
Packages installed:
PyYAML-3.11-13.fc25.x86_64
SDL-devel-1.2.15-21.fc24.x86_64
bc-1.06.95-16.fc24.x86_64
bison-3.0.4-4.fc24.x86_64
ccache-3.3.4-1.fc25.x86_64
clang-3.9.1-2.fc25.x86_64
findutils-4.6.0-8.fc25.x86_64
flex-2.6.0-3.fc25.x86_64
gcc-6.3.1-1.fc25.x86_64
gcc-c++-6.3.1-1.fc25.x86_64
git-2.9.3-2.fc25.x86_64
glib2-devel-2.50.3-1.fc25.x86_64
libfdt-devel-1.4.2-1.fc25.x86_64
make-4.1-5.fc24.x86_64
mingw32-SDL-1.2.15-7.fc24.noarch
mingw32-bzip2-1.0.6-7.fc24.noarch
mingw32-curl-7.47.0-1.fc24.noarch
mingw32-glib2-2.50.1-1.fc25.noarch
mingw32-gmp-6.1.1-1.fc25.noarch
mingw32-gnutls-3.5.5-2.fc25.noarch
mingw32-gtk2-2.24.31-2.fc25.noarch
mingw32-gtk3-3.22.2-1.fc25.noarch
mingw32-libjpeg-turbo-1.5.1-1.fc25.noarch
mingw32-libpng-1.6.27-1.fc25.noarch
mingw32-libssh2-1.4.3-5.fc24.noarch
mingw32-libtasn1-4.9-1.fc25.noarch
mingw32-nettle-3.3-1.fc25.noarch
mingw32-pixman-0.34.0-1.fc25.noarch
mingw32-pkg-config-0.28-6.fc24.x86_64
mingw64-SDL-1.2.15-7.fc24.noarch
mingw64-bzip2-1.0.6-7.fc24.noarch
mingw64-curl-7.47.0-1.fc24.noarch
mingw64-glib2-2.50.1-1.fc25.noarch
mingw64-gmp-6.1.1-1.fc25.noarch
mingw64-gnutls-3.5.5-2.fc25.noarch
mingw64-gtk2-2.24.31-2.fc25.noarch
mingw64-gtk3-3.22.2-1.fc25.noarch
mingw64-libjpeg-turbo-1.5.1-1.fc25.noarch
mingw64-libpng-1.6.27-1.fc25.noarch
mingw64-libssh2-1.4.3-5.fc24.noarch
mingw64-libtasn1-4.9-1.fc25.noarch
mingw64-nettle-3.3-1.fc25.noarch
mingw64-pixman-0.34.0-1.fc25.noarch
mingw64-pkg-config-0.28-6.fc24.x86_64
package python2 is not installed
perl-5.24.1-385.fc25.x86_64
pixman-devel-0.34.0-2.fc24.x86_64
sparse-0.5.0-10.fc25.x86_64
tar-1.29-3.fc25.x86_64
which-2.21-1.fc25.x86_64
zlib-devel-1.2.8-10.fc24.x86_64
Environment variables:
FBR=f25
PACKAGES=ccache git tar PyYAML sparse flex bison python2 glib2-devel pixman-devel zlib-devel SDL-devel libfdt-devel gcc gcc-c++ clang make perl which bc findutils mingw32-pixman mingw32-glib2 mingw32-gmp mingw32-SDL mingw32-pkg-config mingw32-gtk2 mingw32-gtk3 mingw32-gnutls mingw32-nettle mingw32-libtasn1 mingw32-libjpeg-turbo mingw32-libpng mingw32-curl mingw32-libssh2 mingw32-bzip2 mingw64-pixman mingw64-glib2 mingw64-gmp mingw64-SDL mingw64-pkg-config mingw64-gtk2 mingw64-gtk3 mingw64-gnutls mingw64-nettle mingw64-libtasn1 mingw64-libjpeg-turbo mingw64-libpng mingw64-curl mingw64-libssh2 mingw64-bzip2
HOSTNAME=
TERM=xterm
MAKEFLAGS= -j8
HISTSIZE=1000
J=8
USER=root
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.m4a=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.oga=01;36:*.opus=01;36:*.spx=01;36:*.xspf=01;36:
CCACHE_DIR=/var/tmp/ccache
EXTRA_CONFIGURE_OPTS=
V=
SHOW_ENV=1
MAIL=/var/spool/mail/root
PATH=/usr/lib/ccache:/usr/lib64/ccache:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
TARGET_LIST=
HISTCONTROL=ignoredups
FGC=f25
SHLVL=1
HOME=/root
TEST_DIR=/tmp/qemu-test
DISTTAG=f25docker
LOGNAME=root
LESSOPEN=||/usr/bin/lesspipe.sh %s
FEATURES=mingw clang pyyaml dtc
DEBUG=
_=/usr/bin/env
Configure options:
--enable-werror --target-list=x86_64-softmmu,aarch64-softmmu --prefix=/var/tmp/qemu-build/install --cross-prefix=x86_64-w64-mingw32- --enable-trace-backends=simple --enable-debug --enable-gnutls --enable-nettle --enable-curl --enable-vnc --enable-bzip2 --enable-guest-agent --with-sdlabi=1.2 --with-gtkabi=2.0
Install prefix /var/tmp/qemu-build/install
BIOS directory /var/tmp/qemu-build/install
binary directory /var/tmp/qemu-build/install
library directory /var/tmp/qemu-build/install/lib
module directory /var/tmp/qemu-build/install/lib
libexec directory /var/tmp/qemu-build/install/libexec
include directory /var/tmp/qemu-build/install/include
config directory /var/tmp/qemu-build/install
local state directory queried at runtime
Windows SDK no
Source path /tmp/qemu-test/src
C compiler x86_64-w64-mingw32-gcc
Host C compiler cc
C++ compiler x86_64-w64-mingw32-g++
Objective-C compiler clang
ARFLAGS rv
CFLAGS -g
QEMU_CFLAGS -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/pixman-1 -I$(SRC_PATH)/dtc/libfdt -Werror -mms-bitfields -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/glib-2.0 -I/usr/x86_64-w64-mingw32/sys-root/mingw/lib/glib-2.0/include -I/usr/x86_64-w64-mingw32/sys-root/mingw/include -m64 -mcx16 -mthreads -D__USE_MINGW_ANSI_STDIO=1 -DWIN32_LEAN_AND_MEAN -DWINVER=0x501 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wstrict-prototypes -Wredundant-decls -Wall -Wundef -Wwrite-strings -Wmissing-prototypes -fno-strict-aliasing -fno-common -fwrapv -Wendif-labels -Wno-shift-negative-value -Wno-missing-include-dirs -Wempty-body -Wnested-externs -Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration -Wold-style-definition -Wtype-limits -fstack-protector-strong -I/usr/x86_64-w64-mingw32/sys-root/mingw/include -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/p11-kit-1 -I/usr/x86_64-w64-mingw32/sys-root/mingw/include -I/usr/x86_64-w64-mingw32/sys-root/mingw/include -I/usr/x86_64-w64-mingw32/sys-root/mingw/include/libpng16
LDFLAGS -Wl,--nxcompat -Wl,--no-seh -Wl,--dynamicbase -Wl,--warn-common -m64 -g
make make
install install
python python -B
smbd /usr/sbin/smbd
module support no
host CPU x86_64
host big endian no
target list x86_64-softmmu aarch64-softmmu
tcg debug enabled yes
gprof enabled no
sparse enabled no
strip binaries no
profiler no
static build no
pixman system
SDL support yes (1.2.15)
GTK support yes (2.24.31)
GTK GL support no
VTE support no
TLS priority NORMAL
GNUTLS support yes
GNUTLS rnd yes
libgcrypt no
libgcrypt kdf no
nettle yes (3.3)
nettle kdf yes
libtasn1 yes
curses support no
virgl support no
curl support yes
mingw32 support yes
Audio drivers dsound
Block whitelist (rw)
Block whitelist (ro)
VirtFS support no
VNC support yes
VNC SASL support no
VNC JPEG support yes
VNC PNG support yes
xen support no
brlapi support no
bluez support no
Documentation no
PIE no
vde support no
netmap support no
Linux AIO support no
ATTR/XATTR support no
Install blobs yes
KVM support no
HAX support yes
RDMA support no
TCG interpreter no
fdt support yes
preadv support no
fdatasync no
madvise no
posix_madvise no
libcap-ng support no
vhost-net support no
vhost-scsi support no
vhost-vsock support no
Trace backends simple
Trace output file trace-<pid>
spice support no
rbd support no
xfsctl support no
smartcard support no
libusb no
usb net redir no
OpenGL support no
OpenGL dmabufs no
libiscsi support no
libnfs support no
build guest agent yes
QGA VSS support no
QGA w32 disk info yes
QGA MSI support no
seccomp support no
coroutine backend win32
coroutine pool yes
debug stack usage no
GlusterFS support no
gcov gcov
gcov enabled no
TPM support yes
libssh2 support yes
TPM passthrough no
TPM emulator no
QOM debugging yes
lzo support no
snappy support no
bzip2 support yes
NUMA host support no
tcmalloc support no
jemalloc support no
avx2 optimization yes
replication support yes
mkdir -p dtc/libfdt
mkdir -p dtc/tests
GEN x86_64-softmmu/config-devices.mak.tmp
GEN config-host.h
GEN aarch64-softmmu/config-devices.mak.tmp
GEN qapi-types.h
GEN qmp-commands.h
GEN qemu-options.def
GEN qapi-visit.h
GEN qapi-event.h
GEN qmp-marshal.c
GEN x86_64-softmmu/config-devices.mak
GEN qapi-types.c
GEN aarch64-softmmu/config-devices.mak
GEN qapi-visit.c
GEN qapi-event.c
GEN qmp-introspect.h
GEN qmp-introspect.c
GEN trace/generated-tcg-tracers.h
GEN trace/generated-helpers-wrappers.h
GEN trace/generated-helpers.h
GEN trace/generated-helpers.c
GEN module_block.h
GEN tests/test-qapi-types.h
GEN tests/test-qapi-visit.h
GEN tests/test-qmp-commands.h
GEN tests/test-qapi-event.h
GEN tests/test-qmp-introspect.h
GEN trace-root.h
GEN util/trace.h
GEN crypto/trace.h
GEN io/trace.h
GEN migration/trace.h
GEN block/trace.h
GEN backends/trace.h
GEN hw/block/trace.h
GEN hw/block/dataplane/trace.h
GEN hw/char/trace.h
GEN hw/intc/trace.h
GEN hw/net/trace.h
GEN hw/virtio/trace.h
GEN hw/audio/trace.h
GEN hw/misc/trace.h
GEN hw/usb/trace.h
GEN hw/scsi/trace.h
GEN hw/nvram/trace.h
GEN hw/display/trace.h
GEN hw/input/trace.h
GEN hw/timer/trace.h
GEN hw/dma/trace.h
GEN hw/sparc/trace.h
GEN hw/sd/trace.h
GEN hw/isa/trace.h
GEN hw/mem/trace.h
GEN hw/i386/trace.h
GEN hw/i386/xen/trace.h
GEN hw/9pfs/trace.h
GEN hw/ppc/trace.h
GEN hw/pci/trace.h
GEN hw/s390x/trace.h
GEN hw/vfio/trace.h
GEN hw/acpi/trace.h
GEN hw/arm/trace.h
GEN hw/alpha/trace.h
GEN hw/xen/trace.h
GEN ui/trace.h
GEN audio/trace.h
GEN net/trace.h
GEN target/arm/trace.h
GEN target/i386/trace.h
GEN target/mips/trace.h
GEN target/sparc/trace.h
GEN target/s390x/trace.h
GEN target/ppc/trace.h
GEN qom/trace.h
GEN linux-user/trace.h
GEN qapi/trace.h
GEN trace-root.c
GEN util/trace.c
GEN crypto/trace.c
GEN io/trace.c
GEN migration/trace.c
GEN block/trace.c
GEN backends/trace.c
GEN hw/block/trace.c
GEN hw/block/dataplane/trace.c
GEN hw/char/trace.c
GEN hw/intc/trace.c
GEN hw/net/trace.c
GEN hw/virtio/trace.c
GEN hw/audio/trace.c
GEN hw/misc/trace.c
GEN hw/usb/trace.c
GEN hw/scsi/trace.c
GEN hw/nvram/trace.c
GEN hw/display/trace.c
GEN hw/input/trace.c
GEN hw/timer/trace.c
GEN hw/dma/trace.c
GEN hw/sparc/trace.c
GEN hw/sd/trace.c
GEN hw/isa/trace.c
GEN hw/mem/trace.c
GEN hw/i386/trace.c
GEN hw/i386/xen/trace.c
GEN hw/9pfs/trace.c
GEN hw/ppc/trace.c
GEN hw/pci/trace.c
GEN hw/s390x/trace.c
GEN hw/vfio/trace.c
GEN hw/acpi/trace.c
GEN hw/arm/trace.c
GEN hw/alpha/trace.c
GEN hw/xen/trace.c
GEN ui/trace.c
GEN audio/trace.c
GEN net/trace.c
GEN target/arm/trace.c
GEN target/i386/trace.c
GEN target/mips/trace.c
GEN target/sparc/trace.c
GEN target/s390x/trace.c
GEN target/ppc/trace.c
GEN qom/trace.c
GEN linux-user/trace.c
GEN qapi/trace.c
GEN config-all-devices.mak
DEP /tmp/qemu-test/src/dtc/tests/dumptrees.c
DEP /tmp/qemu-test/src/dtc/tests/trees.S
DEP /tmp/qemu-test/src/dtc/tests/testutils.c
DEP /tmp/qemu-test/src/dtc/tests/value-labels.c
DEP /tmp/qemu-test/src/dtc/tests/asm_tree_dump.c
DEP /tmp/qemu-test/src/dtc/tests/truncated_property.c
DEP /tmp/qemu-test/src/dtc/tests/check_path.c
DEP /tmp/qemu-test/src/dtc/tests/overlay.c
DEP /tmp/qemu-test/src/dtc/tests/overlay_bad_fixup.c
DEP /tmp/qemu-test/src/dtc/tests/subnode_iterate.c
DEP /tmp/qemu-test/src/dtc/tests/property_iterate.c
DEP /tmp/qemu-test/src/dtc/tests/integer-expressions.c
DEP /tmp/qemu-test/src/dtc/tests/utilfdt_test.c
DEP /tmp/qemu-test/src/dtc/tests/path_offset_aliases.c
DEP /tmp/qemu-test/src/dtc/tests/add_subnode_with_nops.c
DEP /tmp/qemu-test/src/dtc/tests/dtbs_equal_unordered.c
DEP /tmp/qemu-test/src/dtc/tests/dtb_reverse.c
DEP /tmp/qemu-test/src/dtc/tests/dtbs_equal_ordered.c
DEP /tmp/qemu-test/src/dtc/tests/extra-terminating-null.c
DEP /tmp/qemu-test/src/dtc/tests/incbin.c
DEP /tmp/qemu-test/src/dtc/tests/boot-cpuid.c
DEP /tmp/qemu-test/src/dtc/tests/phandle_format.c
DEP /tmp/qemu-test/src/dtc/tests/references.c
DEP /tmp/qemu-test/src/dtc/tests/path-references.c
DEP /tmp/qemu-test/src/dtc/tests/string_escapes.c
DEP /tmp/qemu-test/src/dtc/tests/propname_escapes.c
DEP /tmp/qemu-test/src/dtc/tests/appendprop2.c
DEP /tmp/qemu-test/src/dtc/tests/del_node.c
DEP /tmp/qemu-test/src/dtc/tests/appendprop1.c
DEP /tmp/qemu-test/src/dtc/tests/del_property.c
DEP /tmp/qemu-test/src/dtc/tests/setprop.c
DEP /tmp/qemu-test/src/dtc/tests/set_name.c
DEP /tmp/qemu-test/src/dtc/tests/rw_tree1.c
DEP /tmp/qemu-test/src/dtc/tests/open_pack.c
DEP /tmp/qemu-test/src/dtc/tests/nopulate.c
DEP /tmp/qemu-test/src/dtc/tests/mangle-layout.c
DEP /tmp/qemu-test/src/dtc/tests/move_and_save.c
DEP /tmp/qemu-test/src/dtc/tests/sw_tree1.c
DEP /tmp/qemu-test/src/dtc/tests/nop_node.c
DEP /tmp/qemu-test/src/dtc/tests/nop_property.c
DEP /tmp/qemu-test/src/dtc/tests/setprop_inplace.c
DEP /tmp/qemu-test/src/dtc/tests/stringlist.c
DEP /tmp/qemu-test/src/dtc/tests/addr_size_cells.c
DEP /tmp/qemu-test/src/dtc/tests/notfound.c
DEP /tmp/qemu-test/src/dtc/tests/sized_cells.c
DEP /tmp/qemu-test/src/dtc/tests/char_literal.c
DEP /tmp/qemu-test/src/dtc/tests/get_alias.c
DEP /tmp/qemu-test/src/dtc/tests/node_offset_by_compatible.c
DEP /tmp/qemu-test/src/dtc/tests/node_check_compatible.c
DEP /tmp/qemu-test/src/dtc/tests/node_offset_by_phandle.c
DEP /tmp/qemu-test/src/dtc/tests/node_offset_by_prop_value.c
DEP /tmp/qemu-test/src/dtc/tests/parent_offset.c
DEP /tmp/qemu-test/src/dtc/tests/supernode_atdepth_offset.c
DEP /tmp/qemu-test/src/dtc/tests/get_path.c
DEP /tmp/qemu-test/src/dtc/tests/get_phandle.c
DEP /tmp/qemu-test/src/dtc/tests/getprop.c
DEP /tmp/qemu-test/src/dtc/tests/get_name.c
DEP /tmp/qemu-test/src/dtc/tests/path_offset.c
DEP /tmp/qemu-test/src/dtc/tests/subnode_offset.c
DEP /tmp/qemu-test/src/dtc/tests/find_property.c
DEP /tmp/qemu-test/src/dtc/tests/root_node.c
DEP /tmp/qemu-test/src/dtc/tests/get_mem_rsv.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_overlay.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_addresses.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_empty_tree.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_strerror.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_rw.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_wip.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_sw.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt_ro.c
DEP /tmp/qemu-test/src/dtc/libfdt/fdt.c
DEP /tmp/qemu-test/src/dtc/util.c
DEP /tmp/qemu-test/src/dtc/fdtput.c
DEP /tmp/qemu-test/src/dtc/fdtget.c
DEP /tmp/qemu-test/src/dtc/fdtdump.c
LEX convert-dtsv0-lexer.lex.c
DEP /tmp/qemu-test/src/dtc/srcpos.c
BISON dtc-parser.tab.c
LEX dtc-lexer.lex.c
DEP /tmp/qemu-test/src/dtc/treesource.c
DEP /tmp/qemu-test/src/dtc/livetree.c
DEP /tmp/qemu-test/src/dtc/fstree.c
DEP /tmp/qemu-test/src/dtc/flattree.c
DEP /tmp/qemu-test/src/dtc/dtc.c
DEP /tmp/qemu-test/src/dtc/data.c
DEP /tmp/qemu-test/src/dtc/checks.c
DEP convert-dtsv0-lexer.lex.c
DEP dtc-parser.tab.c
DEP dtc-lexer.lex.c
CHK version_gen.h
UPD version_gen.h
DEP /tmp/qemu-test/src/dtc/util.c
CC libfdt/fdt.o
CC libfdt/fdt_ro.o
CC libfdt/fdt_sw.o
CC libfdt/fdt_wip.o
CC libfdt/fdt_rw.o
CC libfdt/fdt_strerror.o
CC libfdt/fdt_empty_tree.o
CC libfdt/fdt_addresses.o
CC libfdt/fdt_overlay.o
AR libfdt/libfdt.a
x86_64-w64-mingw32-ar: creating libfdt/libfdt.a
a - libfdt/fdt.o
a - libfdt/fdt_ro.o
a - libfdt/fdt_wip.o
a - libfdt/fdt_sw.o
a - libfdt/fdt_rw.o
a - libfdt/fdt_strerror.o
a - libfdt/fdt_empty_tree.o
a - libfdt/fdt_addresses.o
a - libfdt/fdt_overlay.o
RC version.o
GEN qga/qapi-generated/qga-qapi-types.h
GEN qga/qapi-generated/qga-qapi-visit.h
GEN qga/qapi-generated/qga-qmp-commands.h
GEN qga/qapi-generated/qga-qapi-visit.c
GEN qga/qapi-generated/qga-qapi-types.c
GEN qga/qapi-generated/qga-qmp-marshal.c
CC util/trace.o
CC trace-root.o
CC crypto/trace.o
CC io/trace.o
CC migration/trace.o
CC block/trace.o
CC backends/trace.o
CC hw/block/trace.o
CC hw/block/dataplane/trace.o
CC hw/char/trace.o
CC hw/intc/trace.o
CC hw/net/trace.o
CC hw/virtio/trace.o
CC hw/audio/trace.o
CC hw/misc/trace.o
CC hw/usb/trace.o
CC hw/scsi/trace.o
CC hw/nvram/trace.o
CC hw/display/trace.o
CC hw/input/trace.o
CC hw/timer/trace.o
CC hw/dma/trace.o
CC hw/sparc/trace.o
CC hw/sd/trace.o
CC hw/isa/trace.o
CC hw/mem/trace.o
CC hw/i386/trace.o
CC hw/i386/xen/trace.o
CC hw/9pfs/trace.o
CC hw/ppc/trace.o
CC hw/pci/trace.o
CC hw/s390x/trace.o
CC hw/vfio/trace.o
CC hw/acpi/trace.o
CC hw/arm/trace.o
CC hw/alpha/trace.o
CC hw/xen/trace.o
CC ui/trace.o
CC audio/trace.o
CC net/trace.o
CC target/arm/trace.o
CC target/i386/trace.o
CC target/mips/trace.o
CC target/sparc/trace.o
CC target/ppc/trace.o
CC target/s390x/trace.o
CC qom/trace.o
CC linux-user/trace.o
CC qapi/trace.o
CC qmp-introspect.o
CC qapi-types.o
CC qapi-visit.o
CC qapi-event.o
CC qapi/qapi-visit-core.o
CC qapi/qapi-dealloc-visitor.o
CC qapi/qobject-input-visitor.o
CC qapi/qobject-output-visitor.o
CC qapi/qmp-registry.o
CC qapi/qmp-dispatch.o
CC qapi/string-input-visitor.o
CC qapi/string-output-visitor.o
CC qapi/opts-visitor.o
CC qapi/qapi-clone-visitor.o
CC qapi/qmp-event.o
CC qapi/qapi-util.o
CC qobject/qnull.o
CC qobject/qint.o
CC qobject/qstring.o
CC qobject/qdict.o
CC qobject/qlist.o
CC qobject/qfloat.o
CC qobject/qbool.o
CC qobject/qjson.o
CC qobject/qobject.o
CC qobject/json-lexer.o
CC qobject/json-streamer.o
CC qobject/json-parser.o
CC trace/simple.o
CC trace/control.o
CC trace/qmp.o
CC util/osdep.o
CC util/cutils.o
CC util/unicode.o
CC util/qemu-timer-common.o
CC util/bufferiszero.o
CC util/lockcnt.o
CC util/aiocb.o
CC util/async.o
CC util/thread-pool.o
CC util/qemu-timer.o
CC util/main-loop.o
CC util/iohandler.o
CC util/aio-win32.o
CC util/event_notifier-win32.o
CC util/oslib-win32.o
CC util/qemu-thread-win32.o
CC util/envlist.o
CC util/path.o
CC util/module.o
CC util/host-utils.o
CC util/bitmap.o
CC util/bitops.o
CC util/hbitmap.o
CC util/fifo8.o
CC util/acl.o
CC util/error.o
CC util/qemu-error.o
CC util/id.o
CC util/iov.o
CC util/qemu-config.o
CC util/qemu-sockets.o
CC util/uri.o
CC util/notify.o
CC util/qemu-option.o
CC util/qemu-progress.o
CC util/keyval.o
CC util/hexdump.o
CC util/crc32c.o
CC util/uuid.o
CC util/throttle.o
CC util/getauxval.o
CC util/readline.o
CC util/rcu.o
CC util/qemu-coroutine.o
CC util/qemu-coroutine-lock.o
CC util/qemu-coroutine-io.o
CC util/qemu-coroutine-sleep.o
CC util/coroutine-win32.o
CC util/buffer.o
CC util/timed-average.o
CC util/base64.o
CC util/log.o
CC util/qdist.o
CC util/qht.o
CC util/range.o
CC util/systemd.o
CC crypto/pbkdf-stub.o
CC stubs/arch-query-cpu-def.o
CC stubs/arch-query-cpu-model-expansion.o
CC stubs/arch-query-cpu-model-comparison.o
CC stubs/arch-query-cpu-model-baseline.o
CC stubs/bdrv-next-monitor-owned.o
CC stubs/blk-commit-all.o
CC stubs/blockdev-close-all-bdrv-states.o
CC stubs/clock-warp.o
CC stubs/cpu-get-clock.o
CC stubs/cpu-get-icount.o
CC stubs/dump.o
CC stubs/error-printf.o
CC stubs/fdset.o
CC stubs/gdbstub.o
CC stubs/get-vm-name.o
CC stubs/iothread.o
CC stubs/iothread-lock.o
CC stubs/is-daemonized.o
CC stubs/machine-init-done.o
CC stubs/migr-blocker.o
CC stubs/monitor.o
CC stubs/notify-event.o
CC stubs/qtest.o
CC stubs/replay.o
CC stubs/runstate-check.o
CC stubs/set-fd-handler.o
CC stubs/slirp.o
CC stubs/sysbus.o
CC stubs/trace-control.o
CC stubs/uuid.o
CC stubs/vm-stop.o
CC stubs/vmstate.o
CC stubs/fd-register.o
CC stubs/qmp_pc_dimm_device_list.o
CC stubs/target-monitor-defs.o
CC stubs/target-get-monitor-def.o
CC stubs/pc_madt_cpu_entry.o
CC stubs/vmgenid.o
GEN qemu-img-cmds.h
CC block.o
CC blockjob.o
CC qemu-io-cmds.o
CC replication.o
CC block/raw-format.o
CC block/qcow.o
CC block/vdi.o
CC block/vmdk.o
CC block/cloop.o
CC block/bochs.o
CC block/vpc.o
CC block/vvfat.o
CC block/dmg.o
CC block/qcow2.o
CC block/qcow2-refcount.o
CC block/qcow2-cluster.o
CC block/qcow2-snapshot.o
CC block/qcow2-cache.o
CC block/qed.o
CC block/qed-gencb.o
CC block/qed-l2-cache.o
CC block/qed-table.o
CC block/qed-cluster.o
CC block/qed-check.o
CC block/vhdx.o
CC block/vhdx-endian.o
CC block/vhdx-log.o
CC block/quorum.o
CC block/parallels.o
CC block/blkdebug.o
CC block/blkverify.o
CC block/blkreplay.o
CC block/block-backend.o
CC block/snapshot.o
CC block/qapi.o
CC block/file-win32.o
CC block/win32-aio.o
CC block/null.o
CC block/mirror.o
CC block/commit.o
CC block/io.o
CC block/throttle-groups.o
CC block/nbd.o
CC block/nbd-client.o
CC block/sheepdog.o
CC block/accounting.o
CC block/dirty-bitmap.o
CC block/write-threshold.o
CC block/backup.o
CC block/replication.o
CC block/crypto.o
CC nbd/server.o
CC nbd/client.o
CC nbd/common.o
CC block/curl.o
CC block/ssh.o
CC block/dmg-bz2.o
CC crypto/init.o
CC crypto/hash.o
CC crypto/hash-nettle.o
CC crypto/hmac.o
CC crypto/hmac-nettle.o
CC crypto/aes.o
CC crypto/desrfb.o
CC crypto/tlscreds.o
CC crypto/cipher.o
CC crypto/tlscredsanon.o
CC crypto/tlscredsx509.o
CC crypto/tlssession.o
CC crypto/secret.o
CC crypto/random-gnutls.o
CC crypto/pbkdf.o
CC crypto/pbkdf-nettle.o
CC crypto/ivgen.o
CC crypto/ivgen-essiv.o
CC crypto/ivgen-plain.o
CC crypto/ivgen-plain64.o
CC crypto/afsplit.o
CC crypto/xts.o
CC crypto/block.o
CC crypto/block-qcow.o
CC crypto/block-luks.o
CC io/channel.o
CC io/channel-buffer.o
CC io/channel-command.o
CC io/channel-file.o
CC io/channel-socket.o
CC io/channel-tls.o
CC io/channel-watch.o
CC io/channel-websock.o
CC io/channel-util.o
CC io/dns-resolver.o
CC qom/object.o
CC io/task.o
CC qom/container.o
CC qom/qom-qobject.o
CC qom/object_interfaces.o
CC qemu-io.o
CC blockdev.o
CC blockdev-nbd.o
CC iothread.o
CC qdev-monitor.o
CC device-hotplug.o
CC os-win32.o
CC page_cache.o
CC accel.o
CC bt-host.o
CC bt-vhci.o
CC dma-helpers.o
CC vl.o
CC tpm.o
CC device_tree.o
CC qmp-marshal.o
CC qmp.o
CC hmp.o
CC cpus-common.o
CC audio/audio.o
CC audio/noaudio.o
CC audio/wavaudio.o
CC audio/mixeng.o
/tmp/qemu-test/src/hmp.c: In function 'hmp_info_tpm':
/tmp/qemu-test/src/hmp.c:980:50: error: format '%ld' expects argument of type 'long int', but argument 3 has type 'int64_t {aka long long int}' [-Werror=format=]
monitor_printf(mon, ",loglevel=%ld", teo->loglevel);
^
cc1: all warnings being treated as errors
/tmp/qemu-test/src/rules.mak:69: recipe for target 'hmp.o' failed
make: *** [hmp.o] Error 1
make: *** Waiting for unfinished jobs....
tests/docker/Makefile.include:118: recipe for target 'docker-run' failed
make[1]: *** [docker-run] Error 2
make[1]: Leaving directory '/var/tmp/patchew-tester-tmp-ylr_f574/src'
tests/docker/Makefile.include:149: recipe for target 'docker-run-test-mingw@fedora' failed
make: *** [docker-run-test-mingw@fedora] Error 2
=== OUTPUT END ===
Test command exited with code: 2
---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-03-31 13:10 [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator Amarnath Valluri
` (8 preceding siblings ...)
2017-04-02 8:33 ` [Qemu-devel] [PATCH 0/7] Provide support for the software " no-reply
@ 2017-04-03 17:07 ` Daniel P. Berrange
2017-04-03 17:18 ` Marc-André Lureau
` (4 more replies)
9 siblings, 5 replies; 37+ messages in thread
From: Daniel P. Berrange @ 2017-04-03 17:07 UTC (permalink / raw)
To: Amarnath Valluri; +Cc: qemu-devel, patrick.ohly, stefanb
On Fri, Mar 31, 2017 at 04:10:09PM +0300, Amarnath Valluri wrote:
> Briefly, Theses set of patches introduces:
> - new TPM backend driver to support software TPM emulators(swtpm(1)).
> - and few supported fixes/enhancements/cleanup to existing tpm backend code.
>
> The similar idea was initiated earliar(2) by Stefan Berger(CCed) with slightly
> different approach, using CUSE. As swtpm has excellent support for unix domain
> sockets, hence this implementation uses unix domain sockets to communicate with
> swtpm.
>
> When Qemu is configured with 'emulator' tpm backend, it spawns 'swtpm' and
> communicates its via Unix domain sockets.
I'm not convinced that having QEMU spawning swtpm itself is a desirable
approach, as it means QEMU needs to have all the privileges that swtpm
will need, so that swtpm can inherit them. At the very least I think we
need to have a way to disable this spawning, so it can connect to a
pre-existing swtpm process that's been spawned ahead of time. This will
let us have stricter privilege separation.
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://entangle-photo.org -o- http://search.cpan.org/~danberr/ :|
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-03 17:07 ` Daniel P. Berrange
@ 2017-04-03 17:18 ` Marc-André Lureau
2017-04-04 15:43 ` Daniel P. Berrange
2017-04-03 17:32 ` Patrick Ohly
` (3 subsequent siblings)
4 siblings, 1 reply; 37+ messages in thread
From: Marc-André Lureau @ 2017-04-03 17:18 UTC (permalink / raw)
To: Daniel P. Berrange, Amarnath Valluri; +Cc: patrick.ohly, qemu-devel, stefanb
Hi
On Mon, Apr 3, 2017 at 7:08 PM Daniel P. Berrange <berrange@redhat.com>
wrote:
> On Fri, Mar 31, 2017 at 04:10:09PM +0300, Amarnath Valluri wrote:
> > Briefly, Theses set of patches introduces:
> > - new TPM backend driver to support software TPM emulators(swtpm(1)).
> > - and few supported fixes/enhancements/cleanup to existing tpm backend
> code.
> >
> > The similar idea was initiated earliar(2) by Stefan Berger(CCed) with
> slightly
> > different approach, using CUSE. As swtpm has excellent support for unix
> domain
> > sockets, hence this implementation uses unix domain sockets to
> communicate with
> > swtpm.
> >
> > When Qemu is configured with 'emulator' tpm backend, it spawns 'swtpm'
> and
> > communicates its via Unix domain sockets.
>
> I'm not convinced that having QEMU spawning swtpm itself is a desirable
> approach, as it means QEMU needs to have all the privileges that swtpm
> will need, so that swtpm can inherit them. At the very least I think we
> need to have a way to disable this spawning, so it can connect to a
> pre-existing swtpm process that's been spawned ahead of time. This will
> let us have stricter privilege separation.
>
Could the security contexts be given as arguments to qemu for the
subprocesses? The reason to have qemu spawn its own subprocess is that it
would leave more flexibility on how and when to do it, or even to use
multiple subprcesses if some day that makes sense. If there is no reason to
make this interface public or shared by various other processes, I would
rather see it as internal to qemu rather than managed by other tools. It
also makes command line & testing easier.
Similarly, I think the swtpm protocol must offer enough guarantee about
stability, versionning / capabilities, that we can later extend it. swtpm
could likely be implemented in qemu (by using libswtpm), using a private
protocol. It's hard to estimate how much code that represents, but I think
by reusing glib & qemu common it should be fairly small & simple. I haven't
looked in details.
thanks
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-03 17:18 ` Marc-André Lureau
@ 2017-04-04 15:43 ` Daniel P. Berrange
2017-04-04 16:27 ` Stefan Berger
0 siblings, 1 reply; 37+ messages in thread
From: Daniel P. Berrange @ 2017-04-04 15:43 UTC (permalink / raw)
To: Marc-André Lureau
Cc: Amarnath Valluri, patrick.ohly, qemu-devel, stefanb
On Mon, Apr 03, 2017 at 05:18:37PM +0000, Marc-André Lureau wrote:
> Hi
>
> On Mon, Apr 3, 2017 at 7:08 PM Daniel P. Berrange <berrange@redhat.com>
> wrote:
>
> > On Fri, Mar 31, 2017 at 04:10:09PM +0300, Amarnath Valluri wrote:
> > > Briefly, Theses set of patches introduces:
> > > - new TPM backend driver to support software TPM emulators(swtpm(1)).
> > > - and few supported fixes/enhancements/cleanup to existing tpm backend
> > code.
> > >
> > > The similar idea was initiated earliar(2) by Stefan Berger(CCed) with
> > slightly
> > > different approach, using CUSE. As swtpm has excellent support for unix
> > domain
> > > sockets, hence this implementation uses unix domain sockets to
> > communicate with
> > > swtpm.
> > >
> > > When Qemu is configured with 'emulator' tpm backend, it spawns 'swtpm'
> > and
> > > communicates its via Unix domain sockets.
> >
> > I'm not convinced that having QEMU spawning swtpm itself is a desirable
> > approach, as it means QEMU needs to have all the privileges that swtpm
> > will need, so that swtpm can inherit them. At the very least I think we
> > need to have a way to disable this spawning, so it can connect to a
> > pre-existing swtpm process that's been spawned ahead of time. This will
> > let us have stricter privilege separation.
> >
>
> Could the security contexts be given as arguments to qemu for the
> subprocesses? The reason to have qemu spawn its own subprocess is that it
> would leave more flexibility on how and when to do it, or even to use
> multiple subprcesses if some day that makes sense. If there is no reason to
> make this interface public or shared by various other processes, I would
> rather see it as internal to qemu rather than managed by other tools. It
> also makes command line & testing easier.
If QEMU is responsible for spawning it, then swtpm would have to run as the
same user/group as QEMU, as we do not want QEMU to have ability to invoke
programs with setuid. This means any state files / config / devices that
swtpm has to access would also be accessible by QEMU directly (assuming just
DAC controls, no MAC like SELinux). It also means that swtpm would be able
to access QEMU resources - so a bug in swtpm would allow swtpm to compromise
the guest disk image and other resources QEMU access.
If by contrast, libvirtd is responsible for spawning it, or an even a higher
level mgmt app like OpenStack/oVirt, then swtpm can be run with completely
isolated user / group privileges. The only resource that QEMU needs access
to is the UNIX domain socket, and swtpm doesn't need to access anything
belonging to QEMU. This will give us much stronger security separation
between swtpm & QEMU. It will also allow us to write a more useful seccomp
policy that entirey blocks exec() from QEMU, further mitigating damage from
potential QEMU exploits.
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://entangle-photo.org -o- http://search.cpan.org/~danberr/ :|
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-04 15:43 ` Daniel P. Berrange
@ 2017-04-04 16:27 ` Stefan Berger
0 siblings, 0 replies; 37+ messages in thread
From: Stefan Berger @ 2017-04-04 16:27 UTC (permalink / raw)
To: Daniel P. Berrange, Marc-André Lureau
Cc: Amarnath Valluri, patrick.ohly, qemu-devel
On 04/04/2017 11:43 AM, Daniel P. Berrange wrote:
> On Mon, Apr 03, 2017 at 05:18:37PM +0000, Marc-André Lureau wrote:
>> Hi
>>
>> On Mon, Apr 3, 2017 at 7:08 PM Daniel P. Berrange <berrange@redhat.com>
>> wrote:
>>
>>> On Fri, Mar 31, 2017 at 04:10:09PM +0300, Amarnath Valluri wrote:
>>>> Briefly, Theses set of patches introduces:
>>>> - new TPM backend driver to support software TPM emulators(swtpm(1)).
>>>> - and few supported fixes/enhancements/cleanup to existing tpm backend
>>> code.
>>>> The similar idea was initiated earliar(2) by Stefan Berger(CCed) with
>>> slightly
>>>> different approach, using CUSE. As swtpm has excellent support for unix
>>> domain
>>>> sockets, hence this implementation uses unix domain sockets to
>>> communicate with
>>>> swtpm.
>>>>
>>>> When Qemu is configured with 'emulator' tpm backend, it spawns 'swtpm'
>>> and
>>>> communicates its via Unix domain sockets.
>>> I'm not convinced that having QEMU spawning swtpm itself is a desirable
>>> approach, as it means QEMU needs to have all the privileges that swtpm
>>> will need, so that swtpm can inherit them. At the very least I think we
>>> need to have a way to disable this spawning, so it can connect to a
>>> pre-existing swtpm process that's been spawned ahead of time. This will
>>> let us have stricter privilege separation.
>>>
>> Could the security contexts be given as arguments to qemu for the
>> subprocesses? The reason to have qemu spawn its own subprocess is that it
>> would leave more flexibility on how and when to do it, or even to use
>> multiple subprcesses if some day that makes sense. If there is no reason to
>> make this interface public or shared by various other processes, I would
>> rather see it as internal to qemu rather than managed by other tools. It
>> also makes command line & testing easier.
> If QEMU is responsible for spawning it, then swtpm would have to run as the
> same user/group as QEMU, as we do not want QEMU to have ability to invoke
> programs with setuid. This means any state files / config / devices that
> swtpm has to access would also be accessible by QEMU directly (assuming just
> DAC controls, no MAC like SELinux). It also means that swtpm would be able
> to access QEMU resources - so a bug in swtpm would allow swtpm to compromise
> the guest disk image and other resources QEMU access.
>
> If by contrast, libvirtd is responsible for spawning it, or an even a higher
> level mgmt app like OpenStack/oVirt, then swtpm can be run with completely
> isolated user / group privileges. The only resource that QEMU needs access
> to is the UNIX domain socket, and swtpm doesn't need to access anything
> belonging to QEMU. This will give us much stronger security separation
> between swtpm & QEMU. It will also allow us to write a more useful seccomp
> policy that entirey blocks exec() from QEMU, further mitigating damage from
> potential QEMU exploits.
Here are my patches for libvirt. They are pretty old by now. (won't
forward port unless...)
https://github.com/stefanberger/libvirt-tpm/commits/v1.2.14-maint-vtpm
Stefan
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-03 17:07 ` Daniel P. Berrange
2017-04-03 17:18 ` Marc-André Lureau
@ 2017-04-03 17:32 ` Patrick Ohly
2017-04-03 17:38 ` Dr. David Alan Gilbert
2017-04-03 17:34 ` Dr. David Alan Gilbert
` (2 subsequent siblings)
4 siblings, 1 reply; 37+ messages in thread
From: Patrick Ohly @ 2017-04-03 17:32 UTC (permalink / raw)
To: Daniel P. Berrange; +Cc: Amarnath Valluri, qemu-devel, stefanb
On Mon, 2017-04-03 at 18:07 +0100, Daniel P. Berrange wrote:
> On Fri, Mar 31, 2017 at 04:10:09PM +0300, Amarnath Valluri wrote:
> > Briefly, Theses set of patches introduces:
> > - new TPM backend driver to support software TPM emulators(swtpm(1)).
> > - and few supported fixes/enhancements/cleanup to existing tpm backend code.
> >
> > The similar idea was initiated earliar(2) by Stefan Berger(CCed) with slightly
> > different approach, using CUSE. As swtpm has excellent support for unix domain
> > sockets, hence this implementation uses unix domain sockets to communicate with
> > swtpm.
> >
> > When Qemu is configured with 'emulator' tpm backend, it spawns 'swtpm' and
> > communicates its via Unix domain sockets.
>
> I'm not convinced that having QEMU spawning swtpm itself is a desirable
> approach, as it means QEMU needs to have all the privileges that swtpm
> will need, so that swtpm can inherit them.
The intended usage is for emulating a TPM in software, for example to do
automated testing of an OS which requires a TPM or to do software
development in an environment were it is easy to reset the TPM. That
doesn't require any privileges, because swtpm just reads and writes
files owned by the user who calls qemu.
> At the very least I think we
> need to have a way to disable this spawning, so it can connect to a
> pre-existing swtpm process that's been spawned ahead of time. This will
> let us have stricter privilege separation.
Which privileges and use cases did you have in mind?
swtpm already can be started so that it listens on a Unix domain socket,
instead of inheriting something from the parent. It shouldn't be hard to
add that as an alternative to the existing spawning code.
I can think of one use case: spawning swtpm in advance under debugging
tools like gdb or valgrind. Is that enough justification for adding more
code?
--
Best Regards, Patrick Ohly
The content of this message is my personal opinion only and although
I am an employee of Intel, the statements I make here in no way
represent Intel's position on the issue, nor am I authorized to speak
on behalf of Intel on this matter.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-03 17:32 ` Patrick Ohly
@ 2017-04-03 17:38 ` Dr. David Alan Gilbert
2017-04-03 19:41 ` Patrick Ohly
0 siblings, 1 reply; 37+ messages in thread
From: Dr. David Alan Gilbert @ 2017-04-03 17:38 UTC (permalink / raw)
To: Patrick Ohly; +Cc: Daniel P. Berrange, Amarnath Valluri, qemu-devel, stefanb
* Patrick Ohly (patrick.ohly@intel.com) wrote:
> On Mon, 2017-04-03 at 18:07 +0100, Daniel P. Berrange wrote:
> > On Fri, Mar 31, 2017 at 04:10:09PM +0300, Amarnath Valluri wrote:
> > > Briefly, Theses set of patches introduces:
> > > - new TPM backend driver to support software TPM emulators(swtpm(1)).
> > > - and few supported fixes/enhancements/cleanup to existing tpm backend code.
> > >
> > > The similar idea was initiated earliar(2) by Stefan Berger(CCed) with slightly
> > > different approach, using CUSE. As swtpm has excellent support for unix domain
> > > sockets, hence this implementation uses unix domain sockets to communicate with
> > > swtpm.
> > >
> > > When Qemu is configured with 'emulator' tpm backend, it spawns 'swtpm' and
> > > communicates its via Unix domain sockets.
> >
> > I'm not convinced that having QEMU spawning swtpm itself is a desirable
> > approach, as it means QEMU needs to have all the privileges that swtpm
> > will need, so that swtpm can inherit them.
>
> The intended usage is for emulating a TPM in software, for example to do
> automated testing of an OS which requires a TPM or to do software
> development in an environment were it is easy to reset the TPM. That
> doesn't require any privileges, because swtpm just reads and writes
> files owned by the user who calls qemu.
Being able to do fancier permissions would let you use it in a real VM
situation so that the virtual guest sees it's own TPM; you would then
want to protect the TPM data files pretty carefully - for example stop
one compromised guest sniffing around the TPM data for another.
> > At the very least I think we
> > need to have a way to disable this spawning, so it can connect to a
> > pre-existing swtpm process that's been spawned ahead of time. This will
> > let us have stricter privilege separation.
>
> Which privileges and use cases did you have in mind?
>
> swtpm already can be started so that it listens on a Unix domain socket,
> instead of inheriting something from the parent. It shouldn't be hard to
> add that as an alternative to the existing spawning code.
>
> I can think of one use case: spawning swtpm in advance under debugging
> tools like gdb or valgrind. Is that enough justification for adding more
> code?
Or you could just remove the spawning code and use existing sockets; less code!
Dave
> --
> Best Regards, Patrick Ohly
>
> The content of this message is my personal opinion only and although
> I am an employee of Intel, the statements I make here in no way
> represent Intel's position on the issue, nor am I authorized to speak
> on behalf of Intel on this matter.
>
>
>
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-03 17:38 ` Dr. David Alan Gilbert
@ 2017-04-03 19:41 ` Patrick Ohly
2017-04-04 8:02 ` Dr. David Alan Gilbert
0 siblings, 1 reply; 37+ messages in thread
From: Patrick Ohly @ 2017-04-03 19:41 UTC (permalink / raw)
To: Dr. David Alan Gilbert
Cc: Daniel P. Berrange, Amarnath Valluri, qemu-devel, stefanb
On Mon, 2017-04-03 at 18:38 +0100, Dr. David Alan Gilbert wrote:
> Or you could just remove the spawning code and use existing sockets; less code!
That would be harder to use reliably in the automated testing that this
feature is targeting.
With this mechanism, it is guaranteed that both processes notice when
the other dies because the connection gets disconnected. There's never a
time period where one process listens for a connection from a process
that might have died already, or never got started.
It's also easier that the scripts calling qemu only need to deal with
one process, as before, and just need to pass some additional
parameters.
Can we agree that both usage models are valid and thus support both?
--
Best Regards, Patrick Ohly
The content of this message is my personal opinion only and although
I am an employee of Intel, the statements I make here in no way
represent Intel's position on the issue, nor am I authorized to speak
on behalf of Intel on this matter.
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-03 19:41 ` Patrick Ohly
@ 2017-04-04 8:02 ` Dr. David Alan Gilbert
0 siblings, 0 replies; 37+ messages in thread
From: Dr. David Alan Gilbert @ 2017-04-04 8:02 UTC (permalink / raw)
To: Patrick Ohly; +Cc: Daniel P. Berrange, Amarnath Valluri, qemu-devel, stefanb
* Patrick Ohly (patrick.ohly@intel.com) wrote:
> On Mon, 2017-04-03 at 18:38 +0100, Dr. David Alan Gilbert wrote:
> > Or you could just remove the spawning code and use existing sockets; less code!
>
> That would be harder to use reliably in the automated testing that this
> feature is targeting.
>
> With this mechanism, it is guaranteed that both processes notice when
> the other dies because the connection gets disconnected. There's never a
> time period where one process listens for a connection from a process
> that might have died already, or never got started.
>
> It's also easier that the scripts calling qemu only need to deal with
> one process, as before, and just need to pass some additional
> parameters.
>
> Can we agree that both usage models are valid and thus support both?
Yep, that's fine.
Dave
> --
> Best Regards, Patrick Ohly
>
> The content of this message is my personal opinion only and although
> I am an employee of Intel, the statements I make here in no way
> represent Intel's position on the issue, nor am I authorized to speak
> on behalf of Intel on this matter.
>
>
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-03 17:07 ` Daniel P. Berrange
2017-04-03 17:18 ` Marc-André Lureau
2017-04-03 17:32 ` Patrick Ohly
@ 2017-04-03 17:34 ` Dr. David Alan Gilbert
2017-04-04 12:08 ` Stefan Berger
2017-04-05 7:09 ` Amarnath Valluri
4 siblings, 0 replies; 37+ messages in thread
From: Dr. David Alan Gilbert @ 2017-04-03 17:34 UTC (permalink / raw)
To: Daniel P. Berrange; +Cc: Amarnath Valluri, patrick.ohly, qemu-devel, stefanb
* Daniel P. Berrange (berrange@redhat.com) wrote:
> On Fri, Mar 31, 2017 at 04:10:09PM +0300, Amarnath Valluri wrote:
> > Briefly, Theses set of patches introduces:
> > - new TPM backend driver to support software TPM emulators(swtpm(1)).
> > - and few supported fixes/enhancements/cleanup to existing tpm backend code.
> >
> > The similar idea was initiated earliar(2) by Stefan Berger(CCed) with slightly
> > different approach, using CUSE. As swtpm has excellent support for unix domain
> > sockets, hence this implementation uses unix domain sockets to communicate with
> > swtpm.
> >
> > When Qemu is configured with 'emulator' tpm backend, it spawns 'swtpm' and
> > communicates its via Unix domain sockets.
>
> I'm not convinced that having QEMU spawning swtpm itself is a desirable
> approach, as it means QEMU needs to have all the privileges that swtpm
> will need, so that swtpm can inherit them. At the very least I think we
> need to have a way to disable this spawning, so it can connect to a
> pre-existing swtpm process that's been spawned ahead of time. This will
> let us have stricter privilege separation.
I agree, just letting something external start the swtpm and using
a chardev to talk to it would seem to work wouldn't it?
However, generally I prefer this mechanism of avoiding CUSE.
Dave
> Regards,
> Daniel
> --
> |: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
> |: http://libvirt.org -o- http://virt-manager.org :|
> |: http://entangle-photo.org -o- http://search.cpan.org/~danberr/ :|
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-03 17:07 ` Daniel P. Berrange
` (2 preceding siblings ...)
2017-04-03 17:34 ` Dr. David Alan Gilbert
@ 2017-04-04 12:08 ` Stefan Berger
2017-04-05 7:09 ` Amarnath Valluri
4 siblings, 0 replies; 37+ messages in thread
From: Stefan Berger @ 2017-04-04 12:08 UTC (permalink / raw)
To: Daniel P. Berrange, Amarnath Valluri; +Cc: patrick.ohly, qemu-devel
On 04/03/2017 01:07 PM, Daniel P. Berrange wrote:
> On Fri, Mar 31, 2017 at 04:10:09PM +0300, Amarnath Valluri wrote:
>> Briefly, Theses set of patches introduces:
>> - new TPM backend driver to support software TPM emulators(swtpm(1)).
>> - and few supported fixes/enhancements/cleanup to existing tpm backend code.
>>
>> The similar idea was initiated earliar(2) by Stefan Berger(CCed) with slightly
>> different approach, using CUSE. As swtpm has excellent support for unix domain
>> sockets, hence this implementation uses unix domain sockets to communicate with
>> swtpm.
>>
>> When Qemu is configured with 'emulator' tpm backend, it spawns 'swtpm' and
>> communicates its via Unix domain sockets.
> I'm not convinced that having QEMU spawning swtpm itself is a desirable
> approach, as it means QEMU needs to have all the privileges that swtpm
> will need, so that swtpm can inherit them. At the very least I think we
> need to have a way to disable this spawning, so it can connect to a
> pre-existing swtpm process that's been spawned ahead of time. This will
> let us have stricter privilege separation.
I had implemented it like that. For this I have a libvirt driver that
starts swtpm, sets up cgroups for swtpm (e.g., CPU consumption limits),
and drops unnecessary Linux capabilities...
Stefan
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-03 17:07 ` Daniel P. Berrange
` (3 preceding siblings ...)
2017-04-04 12:08 ` Stefan Berger
@ 2017-04-05 7:09 ` Amarnath Valluri
2017-04-05 15:04 ` Stefan Berger
4 siblings, 1 reply; 37+ messages in thread
From: Amarnath Valluri @ 2017-04-05 7:09 UTC (permalink / raw)
To: Daniel P. Berrange; +Cc: qemu-devel, patrick.ohly, stefanb
On 03.04.2017 20:07, Daniel P. Berrange wrote:
> On Fri, Mar 31, 2017 at 04:10:09PM +0300, Amarnath Valluri wrote:
>> Briefly, Theses set of patches introduces:
>> - new TPM backend driver to support software TPM emulators(swtpm(1)).
>> - and few supported fixes/enhancements/cleanup to existing tpm backend code.
>>
>> The similar idea was initiated earliar(2) by Stefan Berger(CCed) with slightly
>> different approach, using CUSE. As swtpm has excellent support for unix domain
>> sockets, hence this implementation uses unix domain sockets to communicate with
>> swtpm.
>>
>> When Qemu is configured with 'emulator' tpm backend, it spawns 'swtpm' and
>> communicates its via Unix domain sockets.
> I'm not convinced that having QEMU spawning swtpm itself is a desirable
> approach, as it means QEMU needs to have all the privileges that swtpm
> will need, so that swtpm can inherit them. At the very least I think we
> need to have a way to disable this spawning, so it can connect to a
> pre-existing swtpm process that's been spawned ahead of time. This will
> let us have stricter privilege separation.
Both spawning inside qemu and connecting to already running swtpm has
its own pros, Hence we can make this spawning as backend configuration
detail, So it looks like this:
-tpmdev
emulator,id=id,tpmstatedir=dir[,spawn=[on|off],data-path=path,ctrl-path=path,logfile=path,loglevel=number]
Options details:
tpmstatedir - Directory path, which swtpm should use for storing
TPM state
*spawn - should spawn new process, defaults to 'off'
*path - swtpm binary path to spawn, ignored if spawn is off
*data-path - Socket path to use/connect for data messages
*ctrl-path - Socket path to use/connect for out-of-band control
messages
*logfile - File path to use for swtpm logs
*loglevel - log level number, defaults to 5 (ignored if no
logfile provided)
- If spawn is off, data-path and ctrl-path must be provided to qemu,
where to connect already running swtpm
- If spawn if on, both data-path and ctrl-path are optional. If not
provided, qemu uses socket pairs to communicates with swptm, as it is
doing now.
Hope this satisfies all usecases, if everyone here happy with this i can
submit the new patch with these changes.
- Amarnath
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-05 7:09 ` Amarnath Valluri
@ 2017-04-05 15:04 ` Stefan Berger
2017-04-05 15:08 ` Marc-André Lureau
0 siblings, 1 reply; 37+ messages in thread
From: Stefan Berger @ 2017-04-05 15:04 UTC (permalink / raw)
To: qemu-devel
On 04/05/2017 03:09 AM, Amarnath Valluri wrote:
>
>
> On 03.04.2017 20:07, Daniel P. Berrange wrote:
>> On Fri, Mar 31, 2017 at 04:10:09PM +0300, Amarnath Valluri wrote:
>>> Briefly, Theses set of patches introduces:
>>> - new TPM backend driver to support software TPM emulators(swtpm(1)).
>>> - and few supported fixes/enhancements/cleanup to existing tpm
>>> backend code.
>>>
>>> The similar idea was initiated earliar(2) by Stefan Berger(CCed)
>>> with slightly
>>> different approach, using CUSE. As swtpm has excellent support for
>>> unix domain
>>> sockets, hence this implementation uses unix domain sockets to
>>> communicate with
>>> swtpm.
>>>
>>> When Qemu is configured with 'emulator' tpm backend, it spawns
>>> 'swtpm' and
>>> communicates its via Unix domain sockets.
>> I'm not convinced that having QEMU spawning swtpm itself is a desirable
>> approach, as it means QEMU needs to have all the privileges that swtpm
>> will need, so that swtpm can inherit them. At the very least I think we
>> need to have a way to disable this spawning, so it can connect to a
>> pre-existing swtpm process that's been spawned ahead of time. This will
>> let us have stricter privilege separation.
> Both spawning inside qemu and connecting to already running swtpm has
> its own pros, Hence we can make this spawning as backend configuration
> detail, So it looks like this:
>
> -tpmdev
> emulator,id=id,tpmstatedir=dir[,spawn=[on|off],data-path=path,ctrl-path=path,logfile=path,loglevel=number]
> Options details:
> tpmstatedir - Directory path, which swtpm should use for
> storing TPM state
> *spawn - should spawn new process, defaults to 'off'
> *path - swtpm binary path to spawn, ignored if spawn is off
> *data-path - Socket path to use/connect for data messages
> *ctrl-path - Socket path to use/connect for out-of-band control
> messages
FD passing would work?
> *logfile - File path to use for swtpm logs
> *loglevel - log level number, defaults to 5 (ignored if no
> logfile provided)
>
> - If spawn is off, data-path and ctrl-path must be provided to qemu,
> where to connect already running swtpm
> - If spawn if on, both data-path and ctrl-path are optional. If not
> provided, qemu uses socket pairs to communicates with swptm, as it is
> doing now.
>
> Hope this satisfies all usecases, if everyone here happy with this i
> can submit the new patch with these changes.
>
> - Amarnath
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-05 15:04 ` Stefan Berger
@ 2017-04-05 15:08 ` Marc-André Lureau
2017-04-05 17:32 ` Stefan Berger
0 siblings, 1 reply; 37+ messages in thread
From: Marc-André Lureau @ 2017-04-05 15:08 UTC (permalink / raw)
To: Stefan Berger, qemu-devel
Hi
On Wed, Apr 5, 2017 at 5:04 PM Stefan Berger <stefanb@linux.vnet.ibm.com>
wrote:
> On 04/05/2017 03:09 AM, Amarnath Valluri wrote:
> >
> >
> > On 03.04.2017 20 <03%2004%2020%2017%2020>:07, Daniel P. Berrange wrote:
> >> On Fri, Mar 31, 2017 at 04:10:09PM +0300, Amarnath Valluri wrote:
> >>> Briefly, Theses set of patches introduces:
> >>> - new TPM backend driver to support software TPM emulators(swtpm(1)).
> >>> - and few supported fixes/enhancements/cleanup to existing tpm
> >>> backend code.
> >>>
> >>> The similar idea was initiated earliar(2) by Stefan Berger(CCed)
> >>> with slightly
> >>> different approach, using CUSE. As swtpm has excellent support for
> >>> unix domain
> >>> sockets, hence this implementation uses unix domain sockets to
> >>> communicate with
> >>> swtpm.
> >>>
> >>> When Qemu is configured with 'emulator' tpm backend, it spawns
> >>> 'swtpm' and
> >>> communicates its via Unix domain sockets.
> >> I'm not convinced that having QEMU spawning swtpm itself is a desirable
> >> approach, as it means QEMU needs to have all the privileges that swtpm
> >> will need, so that swtpm can inherit them. At the very least I think we
> >> need to have a way to disable this spawning, so it can connect to a
> >> pre-existing swtpm process that's been spawned ahead of time. This will
> >> let us have stricter privilege separation.
> > Both spawning inside qemu and connecting to already running swtpm has
> > its own pros, Hence we can make this spawning as backend configuration
> > detail, So it looks like this:
> >
> > -tpmdev
> >
> emulator,id=id,tpmstatedir=dir[,spawn=[on|off],data-path=path,ctrl-path=path,logfile=path,loglevel=number]
> > Options details:
> > tpmstatedir - Directory path, which swtpm should use for
> > storing TPM state
> > *spawn - should spawn new process, defaults to 'off'
> > *path - swtpm binary path to spawn, ignored if spawn is off
> > *data-path - Socket path to use/connect for data messages
> > *ctrl-path - Socket path to use/connect for out-of-band control
> > messages
>
> FD passing would work?
>
Could with /dev/fdset in theory, but it would be better to use chardevs
instead.
Is there any reason left to have 2 sockets? Couldn't the data be sent as
another message on the "ctrl-path" ?
> > *logfile - File path to use for swtpm logs
> > *loglevel - log level number, defaults to 5 (ignored if no
> > logfile provided)
> >
> > - If spawn is off, data-path and ctrl-path must be provided to qemu,
> > where to connect already running swtpm
> > - If spawn if on, both data-path and ctrl-path are optional. If not
> > provided, qemu uses socket pairs to communicates with swptm, as it is
> > doing now.
> >
> > Hope this satisfies all usecases, if everyone here happy with this i
> > can submit the new patch with these changes.
> >
> > - Amarnath
> >
>
>
> --
Marc-André Lureau
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-05 15:08 ` Marc-André Lureau
@ 2017-04-05 17:32 ` Stefan Berger
2017-04-05 17:49 ` Marc-André Lureau
0 siblings, 1 reply; 37+ messages in thread
From: Stefan Berger @ 2017-04-05 17:32 UTC (permalink / raw)
To: qemu-devel
On 04/05/2017 11:08 AM, Marc-André Lureau wrote:
> Hi
>
> On Wed, Apr 5, 2017 at 5:04 PM Stefan Berger <stefanb@linux.vnet.ibm.com>
> wrote:
>
>> On 04/05/2017 03:09 AM, Amarnath Valluri wrote:
>>>
>>> On 03.04.2017 20 <03%2004%2020%2017%2020>:07, Daniel P. Berrange wrote:
>>>> On Fri, Mar 31, 2017 at 04:10:09PM +0300, Amarnath Valluri wrote:
>>>>> Briefly, Theses set of patches introduces:
>>>>> - new TPM backend driver to support software TPM emulators(swtpm(1)).
>>>>> - and few supported fixes/enhancements/cleanup to existing tpm
>>>>> backend code.
>>>>>
>>>>> The similar idea was initiated earliar(2) by Stefan Berger(CCed)
>>>>> with slightly
>>>>> different approach, using CUSE. As swtpm has excellent support for
>>>>> unix domain
>>>>> sockets, hence this implementation uses unix domain sockets to
>>>>> communicate with
>>>>> swtpm.
>>>>>
>>>>> When Qemu is configured with 'emulator' tpm backend, it spawns
>>>>> 'swtpm' and
>>>>> communicates its via Unix domain sockets.
>>>> I'm not convinced that having QEMU spawning swtpm itself is a desirable
>>>> approach, as it means QEMU needs to have all the privileges that swtpm
>>>> will need, so that swtpm can inherit them. At the very least I think we
>>>> need to have a way to disable this spawning, so it can connect to a
>>>> pre-existing swtpm process that's been spawned ahead of time. This will
>>>> let us have stricter privilege separation.
>>> Both spawning inside qemu and connecting to already running swtpm has
>>> its own pros, Hence we can make this spawning as backend configuration
>>> detail, So it looks like this:
>>>
>>> -tpmdev
>>>
>> emulator,id=id,tpmstatedir=dir[,spawn=[on|off],data-path=path,ctrl-path=path,logfile=path,loglevel=number]
>>> Options details:
>>> tpmstatedir - Directory path, which swtpm should use for
>>> storing TPM state
>>> *spawn - should spawn new process, defaults to 'off'
>>> *path - swtpm binary path to spawn, ignored if spawn is off
>>> *data-path - Socket path to use/connect for data messages
>>> *ctrl-path - Socket path to use/connect for out-of-band control
>>> messages
>> FD passing would work?
>>
> Could with /dev/fdset in theory, but it would be better to use chardevs
> instead.
>
> Is there any reason left to have 2 sockets? Couldn't the data be sent as
> another message on the "ctrl-path" ?
Better to keep them separate so whatever comes out of a VM will never be
mistaken for a control command.
>
>
>>> *logfile - File path to use for swtpm logs
>>> *loglevel - log level number, defaults to 5 (ignored if no
>>> logfile provided)
>>>
>>> - If spawn is off, data-path and ctrl-path must be provided to qemu,
>>> where to connect already running swtpm
>>> - If spawn if on, both data-path and ctrl-path are optional. If not
>>> provided, qemu uses socket pairs to communicates with swptm, as it is
>>> doing now.
>>>
>>> Hope this satisfies all usecases, if everyone here happy with this i
>>> can submit the new patch with these changes.
>>>
>>> - Amarnath
>>>
>>
>> --
> Marc-André Lureau
>
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-05 17:32 ` Stefan Berger
@ 2017-04-05 17:49 ` Marc-André Lureau
2017-04-05 18:00 ` Stefan Berger
0 siblings, 1 reply; 37+ messages in thread
From: Marc-André Lureau @ 2017-04-05 17:49 UTC (permalink / raw)
To: Stefan Berger, qemu-devel
Hi
On Wed, Apr 5, 2017 at 7:32 PM Stefan Berger <stefanb@linux.vnet.ibm.com>
wrote:
> On 04/05/2017 11:08 AM, Marc-André Lureau wrote:
> > Hi
> >
> > On Wed, Apr 5, 2017 at 5:04 PM Stefan Berger <stefanb@linux.vnet.ibm.com
> >
> > wrote:
> >
> >> On 04/05/2017 03:09 AM, Amarnath Valluri wrote:
> >>>
> >>> On 03.04.2017 20 <03%2004%2020%2017%2020>
> <03%2004%2020%2017%2020>:07, Daniel P. Berrange wrote:
> >>>> On Fri, Mar 31, 2017 at 04:10:09PM +0300, Amarnath Valluri wrote:
> >>>>> Briefly, Theses set of patches introduces:
> >>>>> - new TPM backend driver to support software TPM
> emulators(swtpm(1)).
> >>>>> - and few supported fixes/enhancements/cleanup to existing tpm
> >>>>> backend code.
> >>>>>
> >>>>> The similar idea was initiated earliar(2) by Stefan Berger(CCed)
> >>>>> with slightly
> >>>>> different approach, using CUSE. As swtpm has excellent support for
> >>>>> unix domain
> >>>>> sockets, hence this implementation uses unix domain sockets to
> >>>>> communicate with
> >>>>> swtpm.
> >>>>>
> >>>>> When Qemu is configured with 'emulator' tpm backend, it spawns
> >>>>> 'swtpm' and
> >>>>> communicates its via Unix domain sockets.
> >>>> I'm not convinced that having QEMU spawning swtpm itself is a
> desirable
> >>>> approach, as it means QEMU needs to have all the privileges that swtpm
> >>>> will need, so that swtpm can inherit them. At the very least I think
> we
> >>>> need to have a way to disable this spawning, so it can connect to a
> >>>> pre-existing swtpm process that's been spawned ahead of time. This
> will
> >>>> let us have stricter privilege separation.
> >>> Both spawning inside qemu and connecting to already running swtpm has
> >>> its own pros, Hence we can make this spawning as backend configuration
> >>> detail, So it looks like this:
> >>>
> >>> -tpmdev
> >>>
> >>
> emulator,id=id,tpmstatedir=dir[,spawn=[on|off],data-path=path,ctrl-path=path,logfile=path,loglevel=number]
> >>> Options details:
> >>> tpmstatedir - Directory path, which swtpm should use for
> >>> storing TPM state
> >>> *spawn - should spawn new process, defaults to 'off'
> >>> *path - swtpm binary path to spawn, ignored if spawn is
> off
> >>> *data-path - Socket path to use/connect for data messages
> >>> *ctrl-path - Socket path to use/connect for out-of-band control
> >>> messages
> >> FD passing would work?
> >>
> > Could with /dev/fdset in theory, but it would be better to use chardevs
> > instead.
> >
> > Is there any reason left to have 2 sockets? Couldn't the data be sent as
> > another message on the "ctrl-path" ?
>
> Better to keep them separate so whatever comes out of a VM will never be
> mistaken for a control command.
>
This is a moot argument, there is no reason the code would mix the two,
An alternative to make the setup easier is to pass the data socket through
the ctrl socket, perhaps.
> >
> >
> >>> *logfile - File path to use for swtpm logs
> >>> *loglevel - log level number, defaults to 5 (ignored if no
> >>> logfile provided)
> >>>
> >>> - If spawn is off, data-path and ctrl-path must be provided to qemu,
> >>> where to connect already running swtpm
> >>> - If spawn if on, both data-path and ctrl-path are optional. If not
> >>> provided, qemu uses socket pairs to communicates with swptm, as it is
> >>> doing now.
> >>>
> >>> Hope this satisfies all usecases, if everyone here happy with this i
> >>> can submit the new patch with these changes.
> >>>
> >>> - Amarnath
> >>>
> >>
> >> --
> > Marc-André Lureau
> >
>
>
> --
Marc-André Lureau
^ permalink raw reply [flat|nested] 37+ messages in thread
* Re: [Qemu-devel] [PATCH 0/7] Provide support for the software TPM emulator
2017-04-05 17:49 ` Marc-André Lureau
@ 2017-04-05 18:00 ` Stefan Berger
0 siblings, 0 replies; 37+ messages in thread
From: Stefan Berger @ 2017-04-05 18:00 UTC (permalink / raw)
To: Marc-André Lureau, qemu-devel
On 04/05/2017 01:49 PM, Marc-André Lureau wrote:
> Hi
>
> On Wed, Apr 5, 2017 at 7:32 PM Stefan Berger
> <stefanb@linux.vnet.ibm.com <mailto:stefanb@linux.vnet.ibm.com>> wrote:
>
> On 04/05/2017 11:08 AM, Marc-André Lureau wrote:
> > Hi
> >
> > On Wed, Apr 5, 2017 at 5:04 PM Stefan Berger
> <stefanb@linux.vnet.ibm.com <mailto:stefanb@linux.vnet.ibm.com>>
> > wrote:
> >
> >> On 04/05/2017 03:09 AM, Amarnath Valluri wrote:
> >>>
> >>> On 03.04.2017 20 <tel:03%2004%2020%2017%2020>
> <03%2004%2020%2017%2020>:07, Daniel P. Berrange wrote:
> >>>> On Fri, Mar 31, 2017 at 04:10:09PM +0300, Amarnath Valluri wrote:
> >>>>> Briefly, Theses set of patches introduces:
> >>>>> - new TPM backend driver to support software TPM
> emulators(swtpm(1)).
> >>>>> - and few supported fixes/enhancements/cleanup to
> existing tpm
> >>>>> backend code.
> >>>>>
> >>>>> The similar idea was initiated earliar(2) by Stefan Berger(CCed)
> >>>>> with slightly
> >>>>> different approach, using CUSE. As swtpm has excellent
> support for
> >>>>> unix domain
> >>>>> sockets, hence this implementation uses unix domain sockets to
> >>>>> communicate with
> >>>>> swtpm.
> >>>>>
> >>>>> When Qemu is configured with 'emulator' tpm backend, it spawns
> >>>>> 'swtpm' and
> >>>>> communicates its via Unix domain sockets.
> >>>> I'm not convinced that having QEMU spawning swtpm itself is a
> desirable
> >>>> approach, as it means QEMU needs to have all the privileges
> that swtpm
> >>>> will need, so that swtpm can inherit them. At the very least
> I think we
> >>>> need to have a way to disable this spawning, so it can
> connect to a
> >>>> pre-existing swtpm process that's been spawned ahead of time.
> This will
> >>>> let us have stricter privilege separation.
> >>> Both spawning inside qemu and connecting to already running
> swtpm has
> >>> its own pros, Hence we can make this spawning as backend
> configuration
> >>> detail, So it looks like this:
> >>>
> >>> -tpmdev
> >>>
> >>
> emulator,id=id,tpmstatedir=dir[,spawn=[on|off],data-path=path,ctrl-path=path,logfile=path,loglevel=number]
> >>> Options details:
> >>> tpmstatedir - Directory path, which swtpm should use for
> >>> storing TPM state
> >>> *spawn - should spawn new process, defaults to 'off'
> >>> *path - swtpm binary path to spawn, ignored if
> spawn is off
> >>> *data-path - Socket path to use/connect for data messages
> >>> *ctrl-path - Socket path to use/connect for
> out-of-band control
> >>> messages
> >> FD passing would work?
> >>
> > Could with /dev/fdset in theory, but it would be better to use
> chardevs
> > instead.
> >
> > Is there any reason left to have 2 sockets? Couldn't the data be
> sent as
> > another message on the "ctrl-path" ?
>
> Better to keep them separate so whatever comes out of a VM will
> never be
> mistaken for a control command.
>
>
> This is a moot argument, there is no reason the code would mix the two,
>
> An alternative to make the setup easier is to pass the data socket
> through the ctrl socket, perhaps.
Libvirt could open two sockets and pass them via command line. I don't
think there's a problem in this case.
With command line it may be a bit more typing, but passing the data
socket through the ctrl socket doesn't seem to work so easily, so one
may have to resort to typing the paths.
^ permalink raw reply [flat|nested] 37+ messages in thread