1 | From: James Bottomley <James.Bottomley@HansenPartnership.com> | ||
---|---|---|---|
2 | |||
3 | The requested feedback was to convert the tpmdev handler to being json | 1 | The requested feedback was to convert the tpmdev handler to being json |
4 | based, which requires rethreading all the backends. The good news is | 2 | based, which requires rethreading all the backends. The good news is |
5 | this reduced quite a bit of code (especially as I converted it to | 3 | this reduced quite a bit of code (especially as I converted it to |
6 | error_fatal handling as well, which removes the return status | 4 | error_fatal handling as well, which removes the return status |
7 | threading). The bad news is I can't test any of the conversions. | 5 | threading). |
8 | swtpm still isn't building on opensuse and, apparently, passthrough | 6 | |
9 | doesn't like my native TPM because it doesn't allow cancellation. | 7 | v3 pulls out more unneeded code in the visitor conversion, makes |
8 | migration work on external state preservation of the simulator and | ||
9 | adds documentation | ||
10 | |||
11 | v4 puts back the wrapper options (but doesn't add any for mssim since | ||
12 | it post dates the necessity) | ||
13 | |||
14 | v5 rebases to the latest master branch and adjusts for removed use_FOO ptrs | ||
15 | |||
16 | v5 updates help to exit zero; does some checkpatch tidying | ||
17 | |||
18 | v7 merge review feedback and add acks. | ||
19 | |||
20 | v8 adds better error handling, more code tidies and adds command | ||
21 | socket disconnection/reconnection (instead of trying to keep the | ||
22 | socket open the whole time). This adds overhead, but makes | ||
23 | debugging guest kernel TPM issues much easier. | ||
24 | |||
25 | v9 Fix merge conflict with optarg->optstr conversion | ||
26 | |||
27 | v10 Fix more merge conflicts and update API versions | ||
28 | |||
29 | v11 Fix another merge conflict and correct a warm reboot problem where | ||
30 | the TPM isn't getting reset (meaning the PCR values are wrong). | ||
10 | 31 | ||
11 | James | 32 | James |
12 | 33 | ||
13 | --- | 34 | --- |
14 | 35 | ||
15 | James Bottomley (2): | 36 | James Bottomley (2): |
16 | tpm: convert tpmdev options processing to new visitor format | 37 | tpm: convert tpmdev options processing to new visitor format |
17 | tpm: add backend for mssim | 38 | tpm: add backend for mssim |
18 | 39 | ||
19 | MAINTAINERS | 5 + | 40 | MAINTAINERS | 6 + |
20 | backends/tpm/Kconfig | 5 + | 41 | backends/tpm/Kconfig | 5 + |
21 | backends/tpm/meson.build | 1 + | 42 | backends/tpm/meson.build | 1 + |
22 | backends/tpm/tpm_emulator.c | 35 ++--- | 43 | backends/tpm/tpm_emulator.c | 25 +-- |
23 | backends/tpm/tpm_mssim.c | 251 +++++++++++++++++++++++++++++++++ | 44 | backends/tpm/tpm_mssim.c | 335 +++++++++++++++++++++++++++++++++ |
24 | backends/tpm/tpm_mssim.h | 43 ++++++ | 45 | backends/tpm/tpm_mssim.h | 44 +++++ |
25 | backends/tpm/tpm_passthrough.c | 37 ++--- | 46 | backends/tpm/tpm_passthrough.c | 23 +-- |
26 | include/sysemu/tpm.h | 2 +- | 47 | docs/specs/tpm.rst | 39 ++++ |
48 | include/sysemu/tpm.h | 5 +- | ||
27 | include/sysemu/tpm_backend.h | 2 +- | 49 | include/sysemu/tpm_backend.h | 2 +- |
28 | monitor/hmp-cmds.c | 11 +- | 50 | qapi/tpm.json | 50 ++++- |
29 | qapi/tpm.json | 37 ++--- | 51 | system/tpm-hmp-cmds.c | 9 + |
30 | softmmu/tpm.c | 84 +++++------ | 52 | system/tpm.c | 91 ++++----- |
31 | softmmu/vl.c | 4 +- | 53 | system/vl.c | 19 +- |
32 | 13 files changed, 398 insertions(+), 119 deletions(-) | 54 | 14 files changed, 546 insertions(+), 108 deletions(-) |
33 | create mode 100644 backends/tpm/tpm_mssim.c | 55 | create mode 100644 backends/tpm/tpm_mssim.c |
34 | create mode 100644 backends/tpm/tpm_mssim.h | 56 | create mode 100644 backends/tpm/tpm_mssim.h |
35 | 57 | ||
36 | -- | 58 | -- |
37 | 2.35.3 | 59 | 2.35.3 | diff view generated by jsdifflib |
1 | From: James Bottomley <James.Bottomley@HansenPartnership.com> | ||
---|---|---|---|
2 | |||
3 | Instead of processing the tpmdev options using the old qemu options, | 1 | Instead of processing the tpmdev options using the old qemu options, |
4 | convert to the new visitor format which also allows the passing of | 2 | convert to the new visitor format which also allows the passing of |
5 | json on the command line. | 3 | json on the command line. |
6 | 4 | ||
7 | Signed-off-by: James Bottomley <jejb@linux.ibm.com> | 5 | Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> |
6 | Tested-by: Stefan Berger <stefanb@linux.ibm.com> | ||
7 | Reviewed-by: Stefan Berger <stefanb@linux.ibm.com> | ||
8 | |||
8 | --- | 9 | --- |
9 | backends/tpm/tpm_emulator.c | 35 ++++++-------- | 10 | v4: add TpmConfiOptions |
10 | backends/tpm/tpm_passthrough.c | 37 +++++---------- | 11 | v5: exit(0) for help |
11 | include/sysemu/tpm.h | 2 +- | 12 | v7: adjust line lengths, free options |
13 | v8: minor updates; add tested/reviewed-by | ||
14 | v9: optarg->optstr | ||
15 | --- | ||
16 | backends/tpm/tpm_emulator.c | 25 ++++------ | ||
17 | backends/tpm/tpm_passthrough.c | 23 +++------ | ||
18 | include/sysemu/tpm.h | 5 +- | ||
12 | include/sysemu/tpm_backend.h | 2 +- | 19 | include/sysemu/tpm_backend.h | 2 +- |
13 | monitor/hmp-cmds.c | 4 +- | 20 | qapi/tpm.json | 21 ++++++++ |
14 | qapi/tpm.json | 26 ++--------- | 21 | system/tpm.c | 91 ++++++++++++++-------------------- |
15 | softmmu/tpm.c | 84 +++++++++++++++------------------- | 22 | system/vl.c | 19 +------ |
16 | softmmu/vl.c | 4 +- | 23 | 7 files changed, 81 insertions(+), 105 deletions(-) |
17 | 8 files changed, 71 insertions(+), 123 deletions(-) | ||
18 | 24 | ||
19 | diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c | 25 | diff --git a/backends/tpm/tpm_emulator.c b/backends/tpm/tpm_emulator.c |
20 | index XXXXXXX..XXXXXXX 100644 | 26 | index XXXXXXX..XXXXXXX 100644 |
21 | --- a/backends/tpm/tpm_emulator.c | 27 | --- a/backends/tpm/tpm_emulator.c |
22 | +++ b/backends/tpm/tpm_emulator.c | 28 | +++ b/backends/tpm/tpm_emulator.c |
23 | @@ -XXX,XX +XXX,XX @@ typedef struct TPMBlobBuffers { | ||
24 | struct TPMEmulator { | ||
25 | TPMBackend parent; | ||
26 | |||
27 | - TPMEmulatorOptions *options; | ||
28 | + TpmTypeOptions *options; | ||
29 | CharBackend ctrl_chr; | ||
30 | QIOChannel *data_ioc; | ||
31 | TPMVersion tpm_version; | ||
32 | @@ -XXX,XX +XXX,XX @@ err_exit: | 29 | @@ -XXX,XX +XXX,XX @@ err_exit: |
33 | return -1; | 30 | return -1; |
34 | } | 31 | } |
35 | 32 | ||
36 | -static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts) | 33 | -static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts) |
37 | +static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, TpmTypeOptions *opts) | 34 | +static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, |
35 | + TpmCreateOptions *opts) | ||
38 | { | 36 | { |
39 | - const char *value; | 37 | - const char *value; |
40 | Error *err = NULL; | 38 | Error *err = NULL; |
41 | Chardev *dev; | 39 | Chardev *dev; |
42 | 40 | ||
43 | - value = qemu_opt_get(opts, "chardev"); | 41 | - value = qemu_opt_get(opts, "chardev"); |
44 | - if (!value) { | 42 | - if (!value) { |
45 | - error_report("tpm-emulator: parameter 'chardev' is missing"); | 43 | - error_report("tpm-emulator: parameter 'chardev' is missing"); |
46 | - goto err; | 44 | - goto err; |
47 | - } | 45 | - } |
48 | + tpm_emu->options = opts; | 46 | + tpm_emu->options = QAPI_CLONE(TPMEmulatorOptions, &opts->u.emulator); |
49 | + tpm_emu->data_ioc = NULL; | 47 | + tpm_emu->data_ioc = NULL; |
50 | 48 | ||
51 | - dev = qemu_chr_find(value); | 49 | - dev = qemu_chr_find(value); |
52 | + dev = qemu_chr_find(opts->u.emulator.chardev); | 50 | + dev = qemu_chr_find(opts->u.emulator.chardev); |
53 | if (!dev) { | 51 | if (!dev) { |
54 | - error_report("tpm-emulator: tpm chardev '%s' not found", value); | 52 | - error_report("tpm-emulator: tpm chardev '%s' not found", value); |
55 | + error_report("tpm-emulator: tpm chardev '%s' not found", | 53 | + error_report("tpm-emulator: tpm chardev '%s' not found", |
56 | + opts->u.emulator.chardev); | 54 | + opts->u.emulator.chardev); |
57 | goto err; | 55 | goto err; |
58 | } | 56 | } |
59 | 57 | ||
60 | if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) { | 58 | if (!qemu_chr_fe_init(&tpm_emu->ctrl_chr, dev, &err)) { |
61 | error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':", | 59 | error_prepend(&err, "tpm-emulator: No valid chardev found at '%s':", |
... | ... | ||
68 | - tpm_emu->options->chardev = g_strdup(value); | 66 | - tpm_emu->options->chardev = g_strdup(value); |
69 | - | 67 | - |
70 | if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) { | 68 | if (tpm_emulator_prepare_data_fd(tpm_emu) < 0) { |
71 | goto err; | 69 | goto err; |
72 | } | 70 | } |
73 | @@ -XXX,XX +XXX,XX @@ static int tpm_emulator_handle_device_opts(TPMEmulator *tpm_emu, QemuOpts *opts) | ||
74 | if (tpm_util_test_tpmdev(QIO_CHANNEL_SOCKET(tpm_emu->data_ioc)->fd, | ||
75 | &tpm_emu->tpm_version)) { | ||
76 | error_report("'%s' is not emulating TPM device. Error: %s", | ||
77 | - tpm_emu->options->chardev, strerror(errno)); | ||
78 | + tpm_emu->options->u.emulator.chardev, strerror(errno)); | ||
79 | goto err; | ||
80 | } | ||
81 | |||
82 | @@ -XXX,XX +XXX,XX @@ err: | 71 | @@ -XXX,XX +XXX,XX @@ err: |
83 | return -1; | 72 | return -1; |
84 | } | 73 | } |
85 | 74 | ||
86 | -static TPMBackend *tpm_emulator_create(QemuOpts *opts) | 75 | -static TPMBackend *tpm_emulator_create(QemuOpts *opts) |
87 | +static TPMBackend *tpm_emulator_create(TpmTypeOptions *opts) | 76 | +static TPMBackend *tpm_emulator_create(TpmCreateOptions *opts) |
88 | { | 77 | { |
89 | TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR)); | 78 | TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR)); |
90 | 79 | ||
91 | @@ -XXX,XX +XXX,XX @@ static TPMBackend *tpm_emulator_create(QemuOpts *opts) | ||
92 | static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb) | ||
93 | { | ||
94 | TPMEmulator *tpm_emu = TPM_EMULATOR(tb); | ||
95 | - TpmTypeOptions *options = g_new0(TpmTypeOptions, 1); | ||
96 | + TpmTypeOptions *options; | ||
97 | |||
98 | - options->type = TPM_TYPE_EMULATOR; | ||
99 | - options->u.emulator.data = QAPI_CLONE(TPMEmulatorOptions, tpm_emu->options); | ||
100 | + options = QAPI_CLONE(TpmTypeOptions, tpm_emu->options); | ||
101 | |||
102 | return options; | ||
103 | } | ||
104 | @@ -XXX,XX +XXX,XX @@ static void tpm_emulator_inst_init(Object *obj) | 80 | @@ -XXX,XX +XXX,XX @@ static void tpm_emulator_inst_init(Object *obj) |
105 | 81 | ||
106 | trace_tpm_emulator_inst_init(); | 82 | trace_tpm_emulator_inst_init(); |
107 | 83 | ||
108 | - tpm_emu->options = g_new0(TPMEmulatorOptions, 1); | 84 | - tpm_emu->options = g_new0(TPMEmulatorOptions, 1); |
... | ... | ||
116 | - if (!tpm_emu->options->chardev) { | 92 | - if (!tpm_emu->options->chardev) { |
117 | + if (!tpm_emu->data_ioc) { | 93 | + if (!tpm_emu->data_ioc) { |
118 | /* was never properly initialized */ | 94 | /* was never properly initialized */ |
119 | return; | 95 | return; |
120 | } | 96 | } |
121 | @@ -XXX,XX +XXX,XX @@ static void tpm_emulator_inst_finalize(Object *obj) | ||
122 | |||
123 | qemu_chr_fe_deinit(&tpm_emu->ctrl_chr, false); | ||
124 | |||
125 | - qapi_free_TPMEmulatorOptions(tpm_emu->options); | ||
126 | + qapi_free_TpmTypeOptions(tpm_emu->options); | ||
127 | |||
128 | if (tpm_emu->migration_blocker) { | ||
129 | migrate_del_blocker(tpm_emu->migration_blocker); | ||
130 | diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c | 97 | diff --git a/backends/tpm/tpm_passthrough.c b/backends/tpm/tpm_passthrough.c |
131 | index XXXXXXX..XXXXXXX 100644 | 98 | index XXXXXXX..XXXXXXX 100644 |
132 | --- a/backends/tpm/tpm_passthrough.c | 99 | --- a/backends/tpm/tpm_passthrough.c |
133 | +++ b/backends/tpm/tpm_passthrough.c | 100 | +++ b/backends/tpm/tpm_passthrough.c |
134 | @@ -XXX,XX +XXX,XX @@ OBJECT_DECLARE_SIMPLE_TYPE(TPMPassthruState, TPM_PASSTHROUGH) | ||
135 | struct TPMPassthruState { | ||
136 | TPMBackend parent; | ||
137 | |||
138 | - TPMPassthroughOptions *options; | ||
139 | + TpmTypeOptions *options; | ||
140 | const char *tpm_dev; | ||
141 | int tpm_fd; | ||
142 | bool tpm_executing; | ||
143 | @@ -XXX,XX +XXX,XX @@ static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt) | 101 | @@ -XXX,XX +XXX,XX @@ static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt) |
144 | char *dev; | 102 | } |
145 | char path[PATH_MAX]; | ||
146 | |||
147 | - if (tpm_pt->options->cancel_path) { | ||
148 | - fd = qemu_open_old(tpm_pt->options->cancel_path, O_WRONLY); | ||
149 | + if (tpm_pt->options->u.passthrough.cancel_path) { | ||
150 | + fd = qemu_open_old(tpm_pt->options->u.passthrough.cancel_path, O_WRONLY); | ||
151 | if (fd < 0) { | ||
152 | error_report("tpm_passthrough: Could not open TPM cancel path: %s", | ||
153 | strerror(errno)); | ||
154 | @@ -XXX,XX +XXX,XX @@ static int tpm_passthrough_open_sysfs_cancel(TPMPassthruState *tpm_pt) | ||
155 | if (fd < 0) { | ||
156 | error_report("tpm_passthrough: Could not guess TPM cancel path"); | ||
157 | } else { | ||
158 | - tpm_pt->options->cancel_path = g_strdup(path); | ||
159 | + tpm_pt->options->u.passthrough.cancel_path = g_strdup(path); | ||
160 | } | ||
161 | |||
162 | return fd; | ||
163 | } | ||
164 | 103 | ||
165 | static int | 104 | static int |
166 | -tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts) | 105 | -tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts) |
167 | +tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, TpmTypeOptions *opts) | 106 | +tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, |
107 | + TpmCreateOptions *opts) | ||
168 | { | 108 | { |
169 | - const char *value; | 109 | - const char *value; |
170 | + tpm_pt->options = opts; | 110 | + tpm_pt->options = QAPI_CLONE(TPMPassthroughOptions, &opts->u.passthrough); |
171 | 111 | ||
172 | - value = qemu_opt_get(opts, "cancel-path"); | 112 | - value = qemu_opt_get(opts, "cancel-path"); |
173 | - if (value) { | 113 | - if (value) { |
174 | - tpm_pt->options->cancel_path = g_strdup(value); | 114 | - tpm_pt->options->cancel_path = g_strdup(value); |
175 | - tpm_pt->options->has_cancel_path = true; | ||
176 | - } | 115 | - } |
177 | - | 116 | - |
178 | - value = qemu_opt_get(opts, "path"); | 117 | - value = qemu_opt_get(opts, "path"); |
179 | - if (value) { | 118 | - if (value) { |
180 | - tpm_pt->options->has_path = true; | ||
181 | - tpm_pt->options->path = g_strdup(value); | 119 | - tpm_pt->options->path = g_strdup(value); |
182 | - } | 120 | - } |
183 | - | 121 | - |
184 | - tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE; | 122 | - tpm_pt->tpm_dev = value ? value : TPM_PASSTHROUGH_DEFAULT_DEVICE; |
185 | + tpm_pt->tpm_dev = opts->u.passthrough.has_path ? opts->u.passthrough.path : TPM_PASSTHROUGH_DEFAULT_DEVICE; | 123 | + tpm_pt->tpm_dev = opts->u.passthrough.path ? opts->u.passthrough.path : |
124 | + TPM_PASSTHROUGH_DEFAULT_DEVICE; | ||
186 | tpm_pt->tpm_fd = qemu_open_old(tpm_pt->tpm_dev, O_RDWR); | 125 | tpm_pt->tpm_fd = qemu_open_old(tpm_pt->tpm_dev, O_RDWR); |
187 | if (tpm_pt->tpm_fd < 0) { | 126 | if (tpm_pt->tpm_fd < 0) { |
188 | error_report("Cannot access TPM device using '%s': %s", | 127 | error_report("Cannot access TPM device using '%s': %s", |
189 | @@ -XXX,XX +XXX,XX @@ tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts) | 128 | @@ -XXX,XX +XXX,XX @@ tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts) |
190 | return 0; | 129 | return 0; |
191 | } | 130 | } |
192 | 131 | ||
193 | -static TPMBackend *tpm_passthrough_create(QemuOpts *opts) | 132 | -static TPMBackend *tpm_passthrough_create(QemuOpts *opts) |
194 | +static TPMBackend *tpm_passthrough_create(TpmTypeOptions *tto) | 133 | +static TPMBackend *tpm_passthrough_create(TpmCreateOptions *tco) |
195 | { | 134 | { |
196 | Object *obj = object_new(TYPE_TPM_PASSTHROUGH); | 135 | Object *obj = object_new(TYPE_TPM_PASSTHROUGH); |
197 | 136 | ||
198 | - if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) { | 137 | - if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) { |
199 | + if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), tto)) { | 138 | + if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), tco)) { |
200 | object_unref(obj); | 139 | object_unref(obj); |
201 | return NULL; | 140 | return NULL; |
202 | } | 141 | } |
203 | @@ -XXX,XX +XXX,XX @@ static TpmTypeOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb) | ||
204 | { | ||
205 | TpmTypeOptions *options = g_new0(TpmTypeOptions, 1); | ||
206 | |||
207 | - options->type = TPM_TYPE_PASSTHROUGH; | ||
208 | - options->u.passthrough.data = QAPI_CLONE(TPMPassthroughOptions, | ||
209 | - TPM_PASSTHROUGH(tb)->options); | ||
210 | + options = QAPI_CLONE(TpmTypeOptions, TPM_PASSTHROUGH(tb)->options); | ||
211 | |||
212 | return options; | ||
213 | } | ||
214 | @@ -XXX,XX +XXX,XX @@ static void tpm_passthrough_inst_init(Object *obj) | 142 | @@ -XXX,XX +XXX,XX @@ static void tpm_passthrough_inst_init(Object *obj) |
215 | { | 143 | { |
216 | TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj); | 144 | TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(obj); |
217 | 145 | ||
218 | - tpm_pt->options = g_new0(TPMPassthroughOptions, 1); | 146 | - tpm_pt->options = g_new0(TPMPassthroughOptions, 1); |
219 | tpm_pt->tpm_fd = -1; | 147 | tpm_pt->tpm_fd = -1; |
220 | tpm_pt->cancel_fd = -1; | 148 | tpm_pt->cancel_fd = -1; |
221 | } | 149 | } |
222 | @@ -XXX,XX +XXX,XX @@ static void tpm_passthrough_inst_finalize(Object *obj) | ||
223 | if (tpm_pt->cancel_fd >= 0) { | ||
224 | qemu_close(tpm_pt->cancel_fd); | ||
225 | } | ||
226 | - qapi_free_TPMPassthroughOptions(tpm_pt->options); | ||
227 | + qapi_free_TpmTypeOptions(tpm_pt->options); | ||
228 | } | ||
229 | |||
230 | static void tpm_passthrough_class_init(ObjectClass *klass, void *data) | ||
231 | diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h | 150 | diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h |
232 | index XXXXXXX..XXXXXXX 100644 | 151 | index XXXXXXX..XXXXXXX 100644 |
233 | --- a/include/sysemu/tpm.h | 152 | --- a/include/sysemu/tpm.h |
234 | +++ b/include/sysemu/tpm.h | 153 | +++ b/include/sysemu/tpm.h |
235 | @@ -XXX,XX +XXX,XX @@ | 154 | @@ -XXX,XX +XXX,XX @@ |
155 | |||
236 | #ifdef CONFIG_TPM | 156 | #ifdef CONFIG_TPM |
237 | 157 | ||
238 | int tpm_config_parse(QemuOptsList *opts_list, const char *optarg); | 158 | -int tpm_config_parse(QemuOptsList *opts_list, const char *optstr); |
239 | -int tpm_init(void); | 159 | -int tpm_init(void); |
160 | +void tpm_config_parse(const char *optstr); | ||
240 | +void tpm_init(void); | 161 | +void tpm_init(void); |
162 | + | ||
241 | void tpm_cleanup(void); | 163 | void tpm_cleanup(void); |
242 | 164 | ||
243 | typedef enum TPMVersion { | 165 | typedef enum TPMVersion { |
244 | diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h | 166 | diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h |
245 | index XXXXXXX..XXXXXXX 100644 | 167 | index XXXXXXX..XXXXXXX 100644 |
... | ... | ||
248 | @@ -XXX,XX +XXX,XX @@ struct TPMBackendClass { | 170 | @@ -XXX,XX +XXX,XX @@ struct TPMBackendClass { |
249 | /* get a descriptive text of the backend to display to the user */ | 171 | /* get a descriptive text of the backend to display to the user */ |
250 | const char *desc; | 172 | const char *desc; |
251 | 173 | ||
252 | - TPMBackend *(*create)(QemuOpts *opts); | 174 | - TPMBackend *(*create)(QemuOpts *opts); |
253 | + TPMBackend *(*create)(TpmTypeOptions *tto); | 175 | + TPMBackend *(*create)(TpmCreateOptions *tco); |
254 | 176 | ||
255 | /* start up the TPM on the backend - optional */ | 177 | /* start up the TPM on the backend - optional */ |
256 | int (*startup_tpm)(TPMBackend *t, size_t buffersize); | 178 | int (*startup_tpm)(TPMBackend *t, size_t buffersize); |
257 | diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c | ||
258 | index XXXXXXX..XXXXXXX 100644 | ||
259 | --- a/monitor/hmp-cmds.c | ||
260 | +++ b/monitor/hmp-cmds.c | ||
261 | @@ -XXX,XX +XXX,XX @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) | ||
262 | |||
263 | switch (ti->options->type) { | ||
264 | case TPM_TYPE_PASSTHROUGH: | ||
265 | - tpo = ti->options->u.passthrough.data; | ||
266 | + tpo = &ti->options->u.passthrough; | ||
267 | monitor_printf(mon, "%s%s%s%s", | ||
268 | tpo->has_path ? ",path=" : "", | ||
269 | tpo->has_path ? tpo->path : "", | ||
270 | @@ -XXX,XX +XXX,XX @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) | ||
271 | tpo->has_cancel_path ? tpo->cancel_path : ""); | ||
272 | break; | ||
273 | case TPM_TYPE_EMULATOR: | ||
274 | - teo = ti->options->u.emulator.data; | ||
275 | + teo = &ti->options->u.emulator; | ||
276 | monitor_printf(mon, ",chardev=%s", teo->chardev); | ||
277 | break; | ||
278 | case TPM_TYPE__MAX: | ||
279 | diff --git a/qapi/tpm.json b/qapi/tpm.json | 179 | diff --git a/qapi/tpm.json b/qapi/tpm.json |
280 | index XXXXXXX..XXXXXXX 100644 | 180 | index XXXXXXX..XXXXXXX 100644 |
281 | --- a/qapi/tpm.json | 181 | --- a/qapi/tpm.json |
282 | +++ b/qapi/tpm.json | 182 | +++ b/qapi/tpm.json |
283 | @@ -XXX,XX +XXX,XX @@ | 183 | @@ -XXX,XX +XXX,XX @@ |
284 | { 'struct': 'TPMEmulatorOptions', 'data': { 'chardev' : 'str' }, | 184 | 'emulator': 'TPMEmulatorOptionsWrapper' }, |
285 | 'if': 'CONFIG_TPM' } | 185 | 'if': 'CONFIG_TPM' } |
286 | 186 | ||
287 | -## | 187 | +## |
288 | -# @TPMPassthroughOptionsWrapper: | 188 | +# @TpmCreateOptions: |
289 | -# | 189 | +# |
290 | -# Since: 1.5 | 190 | +# A union referencing different TPM backend types' configuration options |
291 | -## | 191 | +# without the wrapper to be usable by visitors. |
292 | -{ 'struct': 'TPMPassthroughOptionsWrapper', | 192 | +# |
293 | - 'data': { 'data': 'TPMPassthroughOptions' }, | 193 | +# @type: - 'passthrough' The configuration options for the TPM passthrough type |
294 | - 'if': 'CONFIG_TPM' } | 194 | +# - 'emulator' The configuration options for TPM emulator backend type |
295 | - | 195 | +# |
296 | -## | 196 | +# @id: The Id of the TPM |
297 | -# @TPMEmulatorOptionsWrapper: | 197 | +# |
298 | -# | 198 | +# Since: 9.0 |
299 | -# Since: 2.11 | 199 | +## |
300 | -## | 200 | +{ 'union': 'TpmCreateOptions', |
301 | -{ 'struct': 'TPMEmulatorOptionsWrapper', | ||
302 | - 'data': { 'data': 'TPMEmulatorOptions' }, | ||
303 | - 'if': 'CONFIG_TPM' } | ||
304 | - | ||
305 | ## | ||
306 | # @TpmTypeOptions: | ||
307 | # | ||
308 | # A union referencing different TPM backend types' configuration options | ||
309 | # | ||
310 | +# @id: identifier of the backend | ||
311 | # @type: - 'passthrough' The configuration options for the TPM passthrough type | ||
312 | # - 'emulator' The configuration options for TPM emulator backend type | ||
313 | # | ||
314 | # Since: 1.5 | ||
315 | ## | ||
316 | { 'union': 'TpmTypeOptions', | ||
317 | - 'base': { 'type': 'TpmType' }, | ||
318 | + 'base': { 'type': 'TpmType', | 201 | + 'base': { 'type': 'TpmType', |
319 | + 'id': 'str' }, | 202 | + 'id' : 'str' }, |
320 | 'discriminator': 'type', | 203 | + 'discriminator': 'type', |
321 | - 'data': { 'passthrough' : 'TPMPassthroughOptionsWrapper', | ||
322 | - 'emulator': 'TPMEmulatorOptionsWrapper' }, | ||
323 | + 'data': { 'passthrough' : 'TPMPassthroughOptions', | 204 | + 'data': { 'passthrough' : 'TPMPassthroughOptions', |
324 | + 'emulator': 'TPMEmulatorOptions' }, | 205 | + 'emulator': 'TPMEmulatorOptions' }, |
325 | 'if': 'CONFIG_TPM' } | 206 | + 'if': 'CONFIG_TPM' } |
326 | 207 | + | |
327 | ## | 208 | ## |
328 | diff --git a/softmmu/tpm.c b/softmmu/tpm.c | 209 | # @TPMInfo: |
329 | index XXXXXXX..XXXXXXX 100644 | 210 | # |
330 | --- a/softmmu/tpm.c | 211 | diff --git a/system/tpm.c b/system/tpm.c |
331 | +++ b/softmmu/tpm.c | 212 | index XXXXXXX..XXXXXXX 100644 |
213 | --- a/system/tpm.c | ||
214 | +++ b/system/tpm.c | ||
332 | @@ -XXX,XX +XXX,XX @@ | 215 | @@ -XXX,XX +XXX,XX @@ |
333 | #include "qapi/error.h" | 216 | #include "qapi/error.h" |
334 | #include "qapi/qapi-commands-tpm.h" | 217 | #include "qapi/qapi-commands-tpm.h" |
335 | #include "qapi/qmp/qerror.h" | 218 | #include "qapi/qmp/qerror.h" |
336 | +#include "qapi/qobject-input-visitor.h" | 219 | +#include "qapi/qobject-input-visitor.h" |
... | ... | ||
342 | +#include "qemu/help_option.h" | 225 | +#include "qemu/help_option.h" |
343 | 226 | ||
344 | static QLIST_HEAD(, TPMBackend) tpm_backends = | 227 | static QLIST_HEAD(, TPMBackend) tpm_backends = |
345 | QLIST_HEAD_INITIALIZER(tpm_backends); | 228 | QLIST_HEAD_INITIALIZER(tpm_backends); |
346 | 229 | ||
347 | +typedef struct TpmTypeOptionsQueueEntry { | 230 | +typedef struct TpmCreateOptionsQueueEntry { |
348 | + TpmTypeOptions *tto; | 231 | + TpmCreateOptions *tco; |
349 | + QSIMPLEQ_ENTRY(TpmTypeOptionsQueueEntry) entry; | 232 | + QSIMPLEQ_ENTRY(TpmCreateOptionsQueueEntry) entry; |
350 | +} TpmTypeOptionsQueueEntry; | 233 | +} TpmCreateOptionsQueueEntry; |
351 | + | 234 | + |
352 | +typedef QSIMPLEQ_HEAD(, TpmTypeOptionsQueueEntry) TpmTypeOptionsQueue; | 235 | +typedef QSIMPLEQ_HEAD(, TpmCreateOptionsQueueEntry) TpmCreateOptionsQueue; |
353 | + | 236 | + |
354 | +static TpmTypeOptionsQueue tto_queue = QSIMPLEQ_HEAD_INITIALIZER(tto_queue); | 237 | +static TpmCreateOptionsQueue tco_queue = QSIMPLEQ_HEAD_INITIALIZER(tco_queue); |
355 | + | 238 | + |
356 | static const TPMBackendClass * | 239 | static const TPMBackendClass * |
357 | tpm_be_find_by_type(enum TpmType type) | 240 | tpm_be_find_by_type(enum TpmType type) |
358 | { | 241 | { |
359 | @@ -XXX,XX +XXX,XX @@ TPMBackend *qemu_find_tpm_be(const char *id) | 242 | @@ -XXX,XX +XXX,XX @@ TPMBackend *qemu_find_tpm_be(const char *id) |
360 | return NULL; | 243 | return NULL; |
361 | } | 244 | } |
362 | 245 | ||
363 | -static int tpm_init_tpmdev(void *dummy, QemuOpts *opts, Error **errp) | 246 | -static int tpm_init_tpmdev(void *dummy, QemuOpts *opts, Error **errp) |
364 | +static void tpm_init_tpmdev(TpmTypeOptions *tto) | 247 | +static void tpm_init_tpmdev(TpmCreateOptions *tco) |
365 | { | 248 | { |
366 | - /* | 249 | - /* |
367 | - * Use of error_report() in a function with an Error ** parameter | 250 | - * Use of error_report() in a function with an Error ** parameter |
368 | - * is suspicious. It is okay here. The parameter only exists to | 251 | - * is suspicious. It is okay here. The parameter only exists to |
369 | - * make the function usable with qemu_opts_foreach(). It is not | 252 | - * make the function usable with qemu_opts_foreach(). It is not |
... | ... | ||
382 | + exit(1); | 265 | + exit(1); |
383 | } | 266 | } |
384 | 267 | ||
385 | - id = qemu_opts_id(opts); | 268 | - id = qemu_opts_id(opts); |
386 | - if (id == NULL) { | 269 | - if (id == NULL) { |
387 | + if (!tto->id) { | 270 | - error_report(QERR_MISSING_PARAMETER, "id"); |
388 | error_report(QERR_MISSING_PARAMETER, "id"); | 271 | - return 1; |
389 | - return 1; | 272 | - } |
390 | + exit(1); | 273 | - |
391 | } | ||
392 | |||
393 | - value = qemu_opt_get(opts, "type"); | 274 | - value = qemu_opt_get(opts, "type"); |
394 | - if (!value) { | 275 | - if (!value) { |
395 | - error_report(QERR_MISSING_PARAMETER, "type"); | 276 | - error_report(QERR_MISSING_PARAMETER, "type"); |
396 | - tpm_display_backend_drivers(); | 277 | - tpm_display_backend_drivers(); |
397 | - return 1; | 278 | - return 1; |
398 | - } | 279 | - } |
399 | - | 280 | - |
400 | - i = qapi_enum_parse(&TpmType_lookup, value, -1, NULL); | 281 | - i = qapi_enum_parse(&TpmType_lookup, value, -1, NULL); |
401 | - be = i >= 0 ? tpm_be_find_by_type(i) : NULL; | 282 | - be = i >= 0 ? tpm_be_find_by_type(i) : NULL; |
402 | + be = tto->type >= 0 ? tpm_be_find_by_type(tto->type) : NULL; | 283 | + be = tco->type >= 0 ? tpm_be_find_by_type(tco->type) : NULL; |
403 | if (be == NULL) { | 284 | if (be == NULL) { |
404 | error_report(QERR_INVALID_PARAMETER_VALUE, | 285 | error_report(QERR_INVALID_PARAMETER_VALUE, |
405 | "type", "a TPM backend type"); | 286 | "type", "a TPM backend type"); |
406 | tpm_display_backend_drivers(); | 287 | tpm_display_backend_drivers(); |
407 | - return 1; | 288 | - return 1; |
... | ... | ||
413 | - return 1; | 294 | - return 1; |
414 | + exit(1); | 295 | + exit(1); |
415 | } | 296 | } |
416 | 297 | ||
417 | - drv = be->create(opts); | 298 | - drv = be->create(opts); |
418 | + drv = be->create(tto); | 299 | + drv = be->create(tco); |
419 | if (!drv) { | 300 | if (!drv) { |
420 | - return 1; | 301 | - return 1; |
421 | + exit(1); | 302 | + exit(1); |
422 | } | 303 | } |
423 | 304 | ||
424 | - drv->id = g_strdup(id); | 305 | - drv->id = g_strdup(id); |
425 | + drv->id = g_strdup(tto->id); | 306 | + drv->id = g_strdup(tco->id); |
426 | QLIST_INSERT_HEAD(&tpm_backends, drv, list); | 307 | QLIST_INSERT_HEAD(&tpm_backends, drv, list); |
427 | - | 308 | - |
428 | - return 0; | 309 | - return 0; |
429 | } | 310 | } |
430 | 311 | ||
... | ... | ||
438 | { | 319 | { |
439 | - if (qemu_opts_foreach(qemu_find_opts("tpmdev"), | 320 | - if (qemu_opts_foreach(qemu_find_opts("tpmdev"), |
440 | - tpm_init_tpmdev, NULL, NULL)) { | 321 | - tpm_init_tpmdev, NULL, NULL)) { |
441 | - return -1; | 322 | - return -1; |
442 | - } | 323 | - } |
443 | + while (!QSIMPLEQ_EMPTY(&tto_queue)) { | 324 | + while (!QSIMPLEQ_EMPTY(&tco_queue)) { |
444 | + TpmTypeOptionsQueueEntry *ttoqe = QSIMPLEQ_FIRST(&tto_queue); | 325 | + TpmCreateOptionsQueueEntry *tcoqe = QSIMPLEQ_FIRST(&tco_queue); |
445 | 326 | ||
446 | - return 0; | 327 | - return 0; |
447 | + QSIMPLEQ_REMOVE_HEAD(&tto_queue, entry); | 328 | + QSIMPLEQ_REMOVE_HEAD(&tco_queue, entry); |
448 | + tpm_init_tpmdev(ttoqe->tto); | 329 | + tpm_init_tpmdev(tcoqe->tco); |
449 | + g_free(ttoqe); | 330 | + qapi_free_TpmCreateOptions(tcoqe->tco); |
331 | + g_free(tcoqe); | ||
450 | + } | 332 | + } |
451 | } | 333 | } |
452 | 334 | ||
453 | /* | 335 | /* |
454 | @@ -XXX,XX +XXX,XX @@ int tpm_init(void) | 336 | * Parse the TPM configuration options. |
337 | * To display all available TPM backends the user may use '-tpmdev help' | ||
455 | */ | 338 | */ |
456 | int tpm_config_parse(QemuOptsList *opts_list, const char *optarg) | 339 | -int tpm_config_parse(QemuOptsList *opts_list, const char *optstr) |
340 | +void tpm_config_parse(const char *optstr) | ||
457 | { | 341 | { |
458 | - QemuOpts *opts; | 342 | - QemuOpts *opts; |
459 | + Visitor *v; | 343 | + Visitor *v; |
460 | + TpmTypeOptionsQueueEntry *toqe; | 344 | + TpmCreateOptionsQueueEntry *tcqe; |
461 | 345 | ||
462 | - if (!strcmp(optarg, "help")) { | 346 | - if (!strcmp(optstr, "help")) { |
463 | + if (is_help_option(optarg)) { | 347 | + if (is_help_option(optstr)) { |
464 | tpm_display_backend_drivers(); | 348 | tpm_display_backend_drivers(); |
465 | return -1; | 349 | - return -1; |
466 | } | 350 | - } |
467 | - opts = qemu_opts_parse_noisily(opts_list, optarg, true); | 351 | - opts = qemu_opts_parse_noisily(opts_list, optstr, true); |
468 | - if (!opts) { | 352 | - if (!opts) { |
469 | - return -1; | 353 | - return -1; |
470 | - } | 354 | + exit(0); |
471 | + v = qobject_input_visitor_new_str(optarg, "type", &error_fatal); | 355 | } |
472 | + toqe = g_new(TpmTypeOptionsQueueEntry, 1); | 356 | - return 0; |
473 | + visit_type_TpmTypeOptions(v, NULL, &toqe->tto, &error_fatal); | 357 | + v = qobject_input_visitor_new_str(optstr, "type", &error_fatal); |
358 | + tcqe = g_new(TpmCreateOptionsQueueEntry, 1); | ||
359 | + visit_type_TpmCreateOptions(v, NULL, &tcqe->tco, &error_fatal); | ||
474 | + visit_free(v); | 360 | + visit_free(v); |
475 | + QSIMPLEQ_INSERT_TAIL(&tto_queue, toqe, entry); | 361 | + QSIMPLEQ_INSERT_TAIL(&tco_queue, tcqe, entry); |
476 | return 0; | 362 | } |
477 | } | 363 | |
478 | 364 | /* | |
479 | diff --git a/softmmu/vl.c b/softmmu/vl.c | 365 | diff --git a/system/vl.c b/system/vl.c |
480 | index XXXXXXX..XXXXXXX 100644 | 366 | index XXXXXXX..XXXXXXX 100644 |
481 | --- a/softmmu/vl.c | 367 | --- a/system/vl.c |
482 | +++ b/softmmu/vl.c | 368 | +++ b/system/vl.c |
369 | @@ -XXX,XX +XXX,XX @@ static QemuOptsList qemu_object_opts = { | ||
370 | }, | ||
371 | }; | ||
372 | |||
373 | -static QemuOptsList qemu_tpmdev_opts = { | ||
374 | - .name = "tpmdev", | ||
375 | - .implied_opt_name = "type", | ||
376 | - .head = QTAILQ_HEAD_INITIALIZER(qemu_tpmdev_opts.head), | ||
377 | - .desc = { | ||
378 | - /* options are defined in the TPM backends */ | ||
379 | - { /* end of list */ } | ||
380 | - }, | ||
381 | -}; | ||
382 | - | ||
383 | static QemuOptsList qemu_overcommit_opts = { | ||
384 | .name = "overcommit", | ||
385 | .head = QTAILQ_HEAD_INITIALIZER(qemu_overcommit_opts.head), | ||
483 | @@ -XXX,XX +XXX,XX @@ static void qemu_create_late_backends(void) | 386 | @@ -XXX,XX +XXX,XX @@ static void qemu_create_late_backends(void) |
484 | 387 | exit(1); | |
485 | object_option_foreach_add(object_create_late); | 388 | } |
486 | 389 | ||
487 | - if (tpm_init() < 0) { | 390 | - if (tpm_init() < 0) { |
488 | - exit(1); | 391 | - exit(1); |
489 | - } | 392 | - } |
490 | + tpm_init(); | 393 | + tpm_init(); |
491 | 394 | ||
492 | qemu_opts_foreach(qemu_find_opts("mon"), | 395 | qemu_opts_foreach(qemu_find_opts("mon"), |
493 | mon_init_func, NULL, &error_fatal); | 396 | mon_init_func, NULL, &error_fatal); |
397 | @@ -XXX,XX +XXX,XX @@ void qemu_init(int argc, char **argv) | ||
398 | qemu_add_opts(&qemu_boot_opts); | ||
399 | qemu_add_opts(&qemu_add_fd_opts); | ||
400 | qemu_add_opts(&qemu_object_opts); | ||
401 | - qemu_add_opts(&qemu_tpmdev_opts); | ||
402 | qemu_add_opts(&qemu_overcommit_opts); | ||
403 | qemu_add_opts(&qemu_msg_opts); | ||
404 | qemu_add_opts(&qemu_name_opts); | ||
405 | @@ -XXX,XX +XXX,XX @@ void qemu_init(int argc, char **argv) | ||
406 | break; | ||
407 | #ifdef CONFIG_TPM | ||
408 | case QEMU_OPTION_tpmdev: | ||
409 | - if (tpm_config_parse(qemu_find_opts("tpmdev"), optarg) < 0) { | ||
410 | - exit(1); | ||
411 | - } | ||
412 | + tpm_config_parse(optarg); | ||
413 | break; | ||
414 | #endif | ||
415 | case QEMU_OPTION_mempath: | ||
494 | -- | 416 | -- |
495 | 2.35.3 | 417 | 2.35.3 | diff view generated by jsdifflib |
1 | From: James Bottomley <James.Bottomley@HansenPartnership.com> | ||
---|---|---|---|
2 | |||
3 | The Microsoft Simulator (mssim) is the reference emulation platform | 1 | The Microsoft Simulator (mssim) is the reference emulation platform |
4 | for the TCG TPM 2.0 specification. | 2 | for the TCG TPM 2.0 specification. |
5 | 3 | ||
6 | https://github.com/Microsoft/ms-tpm-20-ref.git | 4 | https://github.com/Microsoft/ms-tpm-20-ref.git |
7 | 5 | ||
8 | It exports a fairly simple network socket baset protocol on two | 6 | It exports a fairly simple network socket based protocol on two |
9 | sockets, one for command (default 2321) and one for control (default | 7 | sockets, one for command (default 2321) and one for control (default |
10 | 2322). This patch adds a simple backend that can speak the mssim | 8 | 2322). This patch adds a simple backend that can speak the mssim |
11 | protocol over the network. It also allows the host, and two ports to | 9 | protocol over the network. It also allows the two sockets to be |
12 | be specified on the qemu command line. The benefits are twofold: | 10 | specified on the command line. The benefits are twofold: firstly it |
13 | firstly it gives us a backend that actually speaks a standard TPM | 11 | gives us a backend that actually speaks a standard TPM emulation |
14 | emulation protocol instead of the linux specific TPM driver format of | 12 | protocol instead of the linux specific TPM driver format of the |
15 | the current emulated TPM backend and secondly, using the microsoft | 13 | current emulated TPM backend and secondly, using the microsoft |
16 | protocol, the end point of the emulator can be anywhere on the | 14 | protocol, the end point of the emulator can be anywhere on the |
17 | network, facilitating the cloud use case where a central TPM service | 15 | network, facilitating the cloud use case where a central TPM service |
18 | can be used over a control network. | 16 | can be used over a control network. |
19 | 17 | ||
20 | The implementation does basic control commands like power off/on, but | 18 | The implementation does basic control commands like power off/on, but |
... | ... | ||
34 | 32 | ||
35 | -tpmdev "{'type':'mssim','id':'tpm0','command':{'type':inet,'host':'remote','port':'2321'}}" | 33 | -tpmdev "{'type':'mssim','id':'tpm0','command':{'type':inet,'host':'remote','port':'2321'}}" |
36 | 34 | ||
37 | tpm-tis also works as the backend. | 35 | tpm-tis also works as the backend. |
38 | 36 | ||
39 | Signed-off-by: James Bottomley <jejb@linux.ibm.com> | 37 | Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> |
38 | Acked-by: Markus Armbruster <armbru@redhat.com> | ||
40 | 39 | ||
41 | --- | 40 | --- |
42 | 41 | ||
43 | v2: convert to SocketAddr json and use qio_channel_socket_connect_sync() | 42 | v2: convert to SocketAddr json and use qio_channel_socket_connect_sync() |
43 | v3: gate control power off by migration state keep control socket disconnected | ||
44 | to test outside influence and add docs. | ||
45 | v7: TPMmssim -> TPMMssim; doc and json fixes | ||
46 | Make command socket open each time (makes OS debugging easier) | ||
47 | v11: add startup method to make sure TPM is reset on reboot | ||
44 | --- | 48 | --- |
45 | MAINTAINERS | 5 + | 49 | MAINTAINERS | 6 + |
46 | backends/tpm/Kconfig | 5 + | 50 | backends/tpm/Kconfig | 5 + |
47 | backends/tpm/meson.build | 1 + | 51 | backends/tpm/meson.build | 1 + |
48 | backends/tpm/tpm_mssim.c | 251 +++++++++++++++++++++++++++++++++++++++ | 52 | backends/tpm/tpm_mssim.c | 335 +++++++++++++++++++++++++++++++++++++++ |
49 | backends/tpm/tpm_mssim.h | 43 +++++++ | 53 | backends/tpm/tpm_mssim.h | 44 +++++ |
50 | monitor/hmp-cmds.c | 7 ++ | 54 | docs/specs/tpm.rst | 39 +++++ |
51 | qapi/tpm.json | 25 +++- | 55 | qapi/tpm.json | 31 +++- |
52 | 7 files changed, 334 insertions(+), 3 deletions(-) | 56 | system/tpm-hmp-cmds.c | 9 ++ |
57 | 8 files changed, 466 insertions(+), 4 deletions(-) | ||
53 | create mode 100644 backends/tpm/tpm_mssim.c | 58 | create mode 100644 backends/tpm/tpm_mssim.c |
54 | create mode 100644 backends/tpm/tpm_mssim.h | 59 | create mode 100644 backends/tpm/tpm_mssim.h |
55 | 60 | ||
56 | diff --git a/MAINTAINERS b/MAINTAINERS | 61 | diff --git a/MAINTAINERS b/MAINTAINERS |
57 | index XXXXXXX..XXXXXXX 100644 | 62 | index XXXXXXX..XXXXXXX 100644 |
58 | --- a/MAINTAINERS | 63 | --- a/MAINTAINERS |
59 | +++ b/MAINTAINERS | 64 | +++ b/MAINTAINERS |
60 | @@ -XXX,XX +XXX,XX @@ F: backends/tpm/ | 65 | @@ -XXX,XX +XXX,XX @@ F: include/hw/acpi/tpm.h |
66 | F: include/sysemu/tpm* | ||
67 | F: qapi/tpm.json | ||
68 | F: backends/tpm/ | ||
69 | +X: backends/tpm/tpm_mssim.* | ||
61 | F: tests/qtest/*tpm* | 70 | F: tests/qtest/*tpm* |
71 | F: docs/specs/tpm.rst | ||
62 | T: git https://github.com/stefanberger/qemu-tpm.git tpm-next | 72 | T: git https://github.com/stefanberger/qemu-tpm.git tpm-next |
63 | 73 | ||
64 | +MSSIM TPM Backend | 74 | +MSSIM TPM Backend |
65 | +M: James Bottomley <jejb@linux.ibm.com> | 75 | +M: James Bottomley <jejb@linux.ibm.com> |
66 | +S: Maintained | 76 | +S: Maintained |
67 | +F: backends/tpm/tpm_mssim.* | 77 | +F: backends/tpm/tpm_mssim.* |
68 | + | 78 | + |
69 | Checkpatch | 79 | SPDM |
70 | S: Odd Fixes | 80 | M: Alistair Francis <alistair.francis@wdc.com> |
71 | F: scripts/checkpatch.pl | 81 | S: Maintained |
72 | diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig | 82 | diff --git a/backends/tpm/Kconfig b/backends/tpm/Kconfig |
73 | index XXXXXXX..XXXXXXX 100644 | 83 | index XXXXXXX..XXXXXXX 100644 |
74 | --- a/backends/tpm/Kconfig | 84 | --- a/backends/tpm/Kconfig |
75 | +++ b/backends/tpm/Kconfig | 85 | +++ b/backends/tpm/Kconfig |
76 | @@ -XXX,XX +XXX,XX @@ config TPM_EMULATOR | 86 | @@ -XXX,XX +XXX,XX @@ config TPM_EMULATOR |
... | ... | ||
85 | diff --git a/backends/tpm/meson.build b/backends/tpm/meson.build | 95 | diff --git a/backends/tpm/meson.build b/backends/tpm/meson.build |
86 | index XXXXXXX..XXXXXXX 100644 | 96 | index XXXXXXX..XXXXXXX 100644 |
87 | --- a/backends/tpm/meson.build | 97 | --- a/backends/tpm/meson.build |
88 | +++ b/backends/tpm/meson.build | 98 | +++ b/backends/tpm/meson.build |
89 | @@ -XXX,XX +XXX,XX @@ if have_tpm | 99 | @@ -XXX,XX +XXX,XX @@ if have_tpm |
90 | softmmu_ss.add(files('tpm_util.c')) | 100 | system_ss.add(files('tpm_util.c')) |
91 | softmmu_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: files('tpm_passthrough.c')) | 101 | system_ss.add(when: 'CONFIG_TPM_PASSTHROUGH', if_true: files('tpm_passthrough.c')) |
92 | softmmu_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c')) | 102 | system_ss.add(when: 'CONFIG_TPM_EMULATOR', if_true: files('tpm_emulator.c')) |
93 | + softmmu_ss.add(when: 'CONFIG_TPM_MSSIM', if_true: files('tpm_mssim.c')) | 103 | + system_ss.add(when: 'CONFIG_TPM_MSSIM', if_true: files('tpm_mssim.c')) |
94 | endif | 104 | endif |
95 | diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c | 105 | diff --git a/backends/tpm/tpm_mssim.c b/backends/tpm/tpm_mssim.c |
96 | new file mode 100644 | 106 | new file mode 100644 |
97 | index XXXXXXX..XXXXXXX | 107 | index XXXXXXX..XXXXXXX |
98 | --- /dev/null | 108 | --- /dev/null |
... | ... | ||
113 | +#include "qapi/clone-visitor.h" | 123 | +#include "qapi/clone-visitor.h" |
114 | +#include "qapi/qapi-visit-tpm.h" | 124 | +#include "qapi/qapi-visit-tpm.h" |
115 | + | 125 | + |
116 | +#include "io/channel-socket.h" | 126 | +#include "io/channel-socket.h" |
117 | + | 127 | + |
128 | +#include "sysemu/runstate.h" | ||
118 | +#include "sysemu/tpm_backend.h" | 129 | +#include "sysemu/tpm_backend.h" |
119 | +#include "sysemu/tpm_util.h" | 130 | +#include "sysemu/tpm_util.h" |
120 | + | 131 | + |
121 | +#include "qom/object.h" | 132 | +#include "qom/object.h" |
122 | + | 133 | + |
123 | +#include "tpm_int.h" | 134 | +#include "tpm_int.h" |
124 | +#include "tpm_mssim.h" | 135 | +#include "tpm_mssim.h" |
125 | + | 136 | + |
126 | +#define ERROR_PREFIX "TPM mssim Emulator: " | 137 | +#define ERROR_PREFIX "TPM mssim Emulator: " |
127 | + | 138 | + |
128 | +#define TYPE_TPM_MSSIM "tpm-mssim" | 139 | +#define TYPE_TPM_MSSIM "tpm-mssim" |
129 | +OBJECT_DECLARE_SIMPLE_TYPE(TPMmssim, TPM_MSSIM) | 140 | +OBJECT_DECLARE_SIMPLE_TYPE(TPMMssim, TPM_MSSIM) |
130 | + | 141 | + |
131 | +struct TPMmssim { | 142 | +struct TPMMssim { |
132 | + TPMBackend parent; | 143 | + TPMBackend parent; |
133 | + | 144 | + |
134 | + TpmTypeOptions *opts; | 145 | + TPMMssimOptions opts; |
135 | + | 146 | + |
136 | + QIOChannelSocket *cmd_qc, *ctrl_qc; | 147 | + QIOChannelSocket *cmd_qc, *ctrl_qc; |
137 | +}; | 148 | +}; |
138 | + | 149 | + |
139 | +static int tpm_send_ctrl(TPMmssim *t, uint32_t cmd, Error **errp) | 150 | +static int tpm_send_ctrl(TPMMssim *t, uint32_t cmd, Error **errp) |
140 | +{ | 151 | +{ |
141 | + int ret; | 152 | + int ret, retc; |
142 | + | 153 | + Error *local_err = NULL; |
154 | + | ||
155 | + ret = qio_channel_socket_connect_sync(t->ctrl_qc, t->opts.control, errp); | ||
156 | + if (ret != 0) { | ||
157 | + return ret; | ||
158 | + } | ||
143 | + cmd = htonl(cmd); | 159 | + cmd = htonl(cmd); |
144 | + ret = qio_channel_write_all(QIO_CHANNEL(t->ctrl_qc), (char *)&cmd, sizeof(cmd), errp); | 160 | + ret = qio_channel_write_all(QIO_CHANNEL(t->ctrl_qc), |
145 | + if (ret != 0) | 161 | + (char *)&cmd, sizeof(cmd), errp); |
146 | + return ret; | 162 | + if (ret != 0) { |
147 | + ret = qio_channel_read_all(QIO_CHANNEL(t->ctrl_qc), (char *)&cmd, sizeof(cmd), errp); | 163 | + goto out; |
148 | + if (ret != 0) | 164 | + } |
149 | + return ret; | 165 | + |
166 | + ret = qio_channel_read_all(QIO_CHANNEL(t->ctrl_qc), | ||
167 | + (char *)&cmd, sizeof(cmd), errp); | ||
168 | + if (ret != 0) { | ||
169 | + goto out; | ||
170 | + } | ||
150 | + if (cmd != 0) { | 171 | + if (cmd != 0) { |
151 | + error_setg(errp, ERROR_PREFIX "Incorrect ACK recieved on control channel 0x%x\n", cmd); | 172 | + error_setg(errp, ERROR_PREFIX |
152 | + return -1; | 173 | + "Incorrect ACK recieved on control channel 0x%x", cmd); |
153 | + } | 174 | + ret = -1; |
154 | + return 0; | 175 | + } |
176 | + out: | ||
177 | + /* | ||
178 | + * need to close the channel here, but if that fails report it | ||
179 | + * while not letting a prior failure get overwritten | ||
180 | + */ | ||
181 | + retc = qio_channel_close(QIO_CHANNEL(t->ctrl_qc), &local_err); | ||
182 | + error_propagate(errp, local_err); | ||
183 | + return retc ? retc : ret; | ||
155 | +} | 184 | +} |
156 | + | 185 | + |
157 | +static void tpm_mssim_instance_init(Object *obj) | 186 | +static void tpm_mssim_instance_init(Object *obj) |
158 | +{ | 187 | +{ |
159 | +} | 188 | +} |
160 | + | 189 | + |
161 | +static void tpm_mssim_instance_finalize(Object *obj) | 190 | +static void tpm_mssim_instance_finalize(Object *obj) |
162 | +{ | 191 | +{ |
163 | + TPMmssim *t = TPM_MSSIM(obj); | 192 | + TPMMssim *t = TPM_MSSIM(obj); |
164 | + | 193 | + |
165 | + if (t->ctrl_qc) | 194 | + if (t->cmd_qc && !runstate_check(RUN_STATE_POSTMIGRATE)) { |
166 | + tpm_send_ctrl(t, TPM_SIGNAL_POWER_OFF, NULL); | 195 | + Error *errp = NULL; |
196 | + int ret; | ||
197 | + | ||
198 | + ret = tpm_send_ctrl(t, TPM_SIGNAL_POWER_OFF, &errp); | ||
199 | + if (ret != 0) { | ||
200 | + error_report_err(errp); | ||
201 | + } | ||
202 | + } | ||
167 | + | 203 | + |
168 | + object_unref(OBJECT(t->ctrl_qc)); | 204 | + object_unref(OBJECT(t->ctrl_qc)); |
169 | + object_unref(OBJECT(t->cmd_qc)); | 205 | + object_unref(OBJECT(t->cmd_qc)); |
170 | +} | 206 | +} |
171 | + | 207 | + |
... | ... | ||
185 | + return 4096; | 221 | + return 4096; |
186 | +} | 222 | +} |
187 | + | 223 | + |
188 | +static TpmTypeOptions *tpm_mssim_get_opts(TPMBackend *tb) | 224 | +static TpmTypeOptions *tpm_mssim_get_opts(TPMBackend *tb) |
189 | +{ | 225 | +{ |
190 | + TPMmssim *t = TPM_MSSIM(tb); | 226 | + TPMMssim *t = TPM_MSSIM(tb); |
191 | + TpmTypeOptions *opts; | 227 | + TpmTypeOptions *opts = g_new0(TpmTypeOptions, 1); |
192 | + | 228 | + |
193 | + opts = QAPI_CLONE(TpmTypeOptions, t->opts); | 229 | + opts->type = TPM_TYPE_MSSIM; |
230 | + QAPI_CLONE_MEMBERS(TPMMssimOptions, &opts->u.mssim, &t->opts); | ||
194 | + | 231 | + |
195 | + return opts; | 232 | + return opts; |
196 | +} | 233 | +} |
197 | + | 234 | + |
198 | +static void tpm_mssim_handle_request(TPMBackend *tb, TPMBackendCmd *cmd, | 235 | +static void tpm_mssim_handle_request(TPMBackend *tb, TPMBackendCmd *cmd, |
199 | + Error **errp) | 236 | + Error **errp) |
200 | +{ | 237 | +{ |
201 | + TPMmssim *t = TPM_MSSIM(tb); | 238 | + TPMMssim *t = TPM_MSSIM(tb); |
202 | + uint32_t header, len; | 239 | + uint32_t header, len; |
203 | + uint8_t locality = cmd->locty; | 240 | + uint8_t locality = cmd->locty; |
204 | + struct iovec iov[4]; | 241 | + struct iovec iov[4]; |
205 | + int ret; | 242 | + int ret; |
243 | + | ||
244 | + ret = qio_channel_socket_connect_sync(t->cmd_qc, t->opts.command, errp); | ||
245 | + if (ret != 0) { | ||
246 | + goto fail_msg; | ||
247 | + } | ||
206 | + | 248 | + |
207 | + header = htonl(TPM_SEND_COMMAND); | 249 | + header = htonl(TPM_SEND_COMMAND); |
208 | + len = htonl(cmd->in_len); | 250 | + len = htonl(cmd->in_len); |
209 | + | 251 | + |
210 | + iov[0].iov_base = &header; | 252 | + iov[0].iov_base = &header; |
... | ... | ||
215 | + iov[2].iov_len = sizeof(len); | 257 | + iov[2].iov_len = sizeof(len); |
216 | + iov[3].iov_base = (void *)cmd->in; | 258 | + iov[3].iov_base = (void *)cmd->in; |
217 | + iov[3].iov_len = cmd->in_len; | 259 | + iov[3].iov_len = cmd->in_len; |
218 | + | 260 | + |
219 | + ret = qio_channel_writev_all(QIO_CHANNEL(t->cmd_qc), iov, 4, errp); | 261 | + ret = qio_channel_writev_all(QIO_CHANNEL(t->cmd_qc), iov, 4, errp); |
220 | + if (ret != 0) | 262 | + if (ret != 0) { |
221 | + goto fail; | 263 | + goto fail; |
222 | + | 264 | + } |
223 | + ret = qio_channel_read_all(QIO_CHANNEL(t->cmd_qc), (char *)&len, sizeof(len), errp); | 265 | + |
224 | + if (ret != 0) | 266 | + ret = qio_channel_read_all(QIO_CHANNEL(t->cmd_qc), |
225 | + goto fail; | 267 | + (char *)&len, sizeof(len), errp); |
268 | + if (ret != 0) { | ||
269 | + goto fail; | ||
270 | + } | ||
271 | + | ||
226 | + len = ntohl(len); | 272 | + len = ntohl(len); |
227 | + if (len > cmd->out_len) { | 273 | + if (len > cmd->out_len) { |
228 | + error_setg(errp, "receive size is too large"); | 274 | + error_setg(errp, "receive size is too large"); |
229 | + goto fail; | 275 | + goto fail; |
230 | + } | 276 | + } |
231 | + ret = qio_channel_read_all(QIO_CHANNEL(t->cmd_qc), (char *)cmd->out, len, errp); | 277 | + ret = qio_channel_read_all(QIO_CHANNEL(t->cmd_qc), |
232 | + if (ret != 0) | 278 | + (char *)cmd->out, len, errp); |
233 | + goto fail; | 279 | + if (ret != 0) { |
280 | + goto fail; | ||
281 | + } | ||
282 | + | ||
234 | + /* ACK packet */ | 283 | + /* ACK packet */ |
235 | + ret = qio_channel_read_all(QIO_CHANNEL(t->cmd_qc), (char *)&header, sizeof(header), errp); | 284 | + ret = qio_channel_read_all(QIO_CHANNEL(t->cmd_qc), |
236 | + if (ret != 0) | 285 | + (char *)&header, sizeof(header), errp); |
237 | + goto fail; | 286 | + if (ret != 0) { |
287 | + goto fail; | ||
288 | + } | ||
238 | + if (header != 0) { | 289 | + if (header != 0) { |
239 | + error_setg(errp, "incorrect ACK received on command channel 0x%x", len); | 290 | + error_setg(errp, "incorrect ACK received on command channel 0x%x", len); |
240 | + goto fail; | 291 | + goto fail; |
241 | + } | 292 | + } |
242 | + | 293 | + |
294 | + ret = qio_channel_close(QIO_CHANNEL(t->cmd_qc), errp); | ||
295 | + if (ret != 0) { | ||
296 | + goto fail_msg; | ||
297 | + } | ||
298 | + | ||
243 | + return; | 299 | + return; |
244 | + | 300 | + |
245 | + fail: | 301 | + fail: |
302 | + /* we're already failing, so don't worry if this fails too */ | ||
303 | + qio_channel_close(QIO_CHANNEL(t->cmd_qc), NULL); | ||
304 | + fail_msg: | ||
246 | + error_prepend(errp, ERROR_PREFIX); | 305 | + error_prepend(errp, ERROR_PREFIX); |
247 | + tpm_util_write_fatal_error_response(cmd->out, cmd->out_len); | 306 | + tpm_util_write_fatal_error_response(cmd->out, cmd->out_len); |
248 | +} | 307 | +} |
249 | + | 308 | + |
250 | +static TPMBackend *tpm_mssim_create(TpmTypeOptions *opts) | 309 | +static int tpm_mssim_startup(TPMBackend *tb, size_t buffersize) |
310 | +{ | ||
311 | + TPMMssim *t = TPM_MSSIM(tb); | ||
312 | + Error *errp = NULL; | ||
313 | + int ret; | ||
314 | + | ||
315 | + if (runstate_check(RUN_STATE_INMIGRATE)) { | ||
316 | + return 0; | ||
317 | + } | ||
318 | + | ||
319 | + /* | ||
320 | + * reset the TPM using a power cycle sequence, in case someone has | ||
321 | + * previously powered it up | ||
322 | + */ | ||
323 | + ret = tpm_send_ctrl(t, TPM_SIGNAL_POWER_OFF, &errp); | ||
324 | + if (ret != 0) { | ||
325 | + goto fail; | ||
326 | + } | ||
327 | + | ||
328 | + ret = tpm_send_ctrl(t, TPM_SIGNAL_POWER_ON, &errp); | ||
329 | + if (ret != 0) { | ||
330 | + goto fail; | ||
331 | + } | ||
332 | + | ||
333 | + ret = tpm_send_ctrl(t, TPM_SIGNAL_NV_ON, &errp); | ||
334 | + if (ret != 0) { | ||
335 | + goto fail; | ||
336 | + } | ||
337 | + | ||
338 | + return 0; | ||
339 | + | ||
340 | + fail: | ||
341 | + error_report_err(errp); | ||
342 | + return -1; | ||
343 | +} | ||
344 | + | ||
345 | +static TPMBackend *tpm_mssim_create(TpmCreateOptions *opts) | ||
251 | +{ | 346 | +{ |
252 | + TPMBackend *be = TPM_BACKEND(object_new(TYPE_TPM_MSSIM)); | 347 | + TPMBackend *be = TPM_BACKEND(object_new(TYPE_TPM_MSSIM)); |
253 | + TPMmssim *t = TPM_MSSIM(be); | 348 | + TPMMssim *t = TPM_MSSIM(be); |
254 | + int sock; | ||
255 | + Error *errp = NULL; | 349 | + Error *errp = NULL; |
256 | + TPMmssimOptions *mo = &opts->u.mssim; | 350 | + TPMMssimOptions *mo = &opts->u.mssim; |
257 | + | 351 | + |
258 | + t->opts = opts; | 352 | + if (!mo->command) { |
259 | + if (!mo->has_command) { | ||
260 | + mo->has_command = true; | ||
261 | + mo->command = g_new0(SocketAddress, 1); | 353 | + mo->command = g_new0(SocketAddress, 1); |
262 | + mo->command->type = SOCKET_ADDRESS_TYPE_INET; | 354 | + mo->command->type = SOCKET_ADDRESS_TYPE_INET; |
263 | + mo->command->u.inet.host = g_strdup("localhost"); | 355 | + mo->command->u.inet.host = g_strdup("localhost"); |
264 | + mo->command->u.inet.port = g_strdup("2321"); | 356 | + mo->command->u.inet.port = g_strdup("2321"); |
265 | + } | 357 | + } |
266 | + if (!mo->has_control) { | 358 | + if (!mo->control) { |
267 | + mo->has_control = true; | 359 | + int port; |
360 | + | ||
268 | + mo->control = g_new0(SocketAddress, 1); | 361 | + mo->control = g_new0(SocketAddress, 1); |
269 | + mo->control->type = SOCKET_ADDRESS_TYPE_INET; | 362 | + mo->control->type = SOCKET_ADDRESS_TYPE_INET; |
270 | + mo->control->u.inet.host = g_strdup(mo->command->u.inet.host); | 363 | + mo->control->u.inet.host = g_strdup(mo->command->u.inet.host); |
271 | + mo->control->u.inet.port = g_strdup("2322"); | 364 | + /* |
272 | + } | 365 | + * in the reference implementation, the control port is |
273 | + | 366 | + * always one above the command port |
367 | + */ | ||
368 | + port = atoi(mo->command->u.inet.port) + 1; | ||
369 | + mo->control->u.inet.port = g_strdup_printf("%d", port); | ||
370 | + } | ||
371 | + | ||
372 | + QAPI_CLONE_MEMBERS(TPMMssimOptions, &t->opts, &opts->u.mssim); | ||
274 | + t->cmd_qc = qio_channel_socket_new(); | 373 | + t->cmd_qc = qio_channel_socket_new(); |
275 | + t->ctrl_qc = qio_channel_socket_new(); | 374 | + t->ctrl_qc = qio_channel_socket_new(); |
276 | + | 375 | + |
277 | + if (qio_channel_socket_connect_sync(t->cmd_qc, mo->command, &errp) < 0) | 376 | + if (qio_channel_socket_connect_sync(t->cmd_qc, mo->command, &errp) < 0) { |
278 | + goto fail; | 377 | + goto fail; |
279 | + | 378 | + } |
280 | + if (qio_channel_socket_connect_sync(t->ctrl_qc, mo->control, &errp) < 0) | 379 | + |
281 | + goto fail; | 380 | + if (qio_channel_socket_connect_sync(t->ctrl_qc, mo->control, &errp) < 0) { |
282 | + | 381 | + goto fail; |
283 | + /* reset the TPM using a power cycle sequence, in case someone | 382 | + } |
284 | + * has previously powered it up */ | 383 | + qio_channel_close(QIO_CHANNEL(t->ctrl_qc), NULL); |
285 | + sock = tpm_send_ctrl(t, TPM_SIGNAL_POWER_OFF, &errp); | 384 | + qio_channel_close(QIO_CHANNEL(t->cmd_qc), NULL); |
286 | + if (sock != 0) | 385 | + |
287 | + goto fail; | ||
288 | + sock = tpm_send_ctrl(t, TPM_SIGNAL_POWER_ON, &errp); | ||
289 | + if (sock != 0) | ||
290 | + goto fail; | ||
291 | + sock = tpm_send_ctrl(t, TPM_SIGNAL_NV_ON, &errp); | ||
292 | + if (sock != 0) | ||
293 | + goto fail; | ||
294 | + | 386 | + |
295 | + return be; | 387 | + return be; |
296 | + | 388 | + |
297 | + fail: | 389 | + fail: |
298 | + object_unref(OBJECT(t->ctrl_qc)); | 390 | + object_unref(OBJECT(t->ctrl_qc)); |
299 | + object_unref(OBJECT(t->cmd_qc)); | 391 | + object_unref(OBJECT(t->cmd_qc)); |
300 | + t->ctrl_qc = NULL; | 392 | + t->ctrl_qc = NULL; |
393 | + t->cmd_qc = NULL; | ||
301 | + error_prepend(&errp, ERROR_PREFIX); | 394 | + error_prepend(&errp, ERROR_PREFIX); |
302 | + error_report_err(errp); | 395 | + error_report_err(errp); |
303 | + object_unref(OBJECT(be)); | 396 | + object_unref(OBJECT(be)); |
304 | + | 397 | + |
305 | + return NULL; | 398 | + return NULL; |
... | ... | ||
326 | + cl->type = TPM_TYPE_MSSIM; | 419 | + cl->type = TPM_TYPE_MSSIM; |
327 | + cl->opts = tpm_mssim_cmdline_opts; | 420 | + cl->opts = tpm_mssim_cmdline_opts; |
328 | + cl->desc = "TPM mssim emulator backend driver"; | 421 | + cl->desc = "TPM mssim emulator backend driver"; |
329 | + cl->create = tpm_mssim_create; | 422 | + cl->create = tpm_mssim_create; |
330 | + cl->cancel_cmd = tpm_mssim_cancel_cmd; | 423 | + cl->cancel_cmd = tpm_mssim_cancel_cmd; |
424 | + cl->startup_tpm = tpm_mssim_startup; | ||
331 | + cl->get_tpm_version = tpm_mssim_get_version; | 425 | + cl->get_tpm_version = tpm_mssim_get_version; |
332 | + cl->get_buffer_size = tpm_mssim_get_buffer_size; | 426 | + cl->get_buffer_size = tpm_mssim_get_buffer_size; |
333 | + cl->get_tpm_options = tpm_mssim_get_opts; | 427 | + cl->get_tpm_options = tpm_mssim_get_opts; |
334 | + cl->handle_request = tpm_mssim_handle_request; | 428 | + cl->handle_request = tpm_mssim_handle_request; |
335 | +} | 429 | +} |
336 | + | 430 | + |
337 | +static const TypeInfo tpm_mssim_info = { | 431 | +static const TypeInfo tpm_mssim_info = { |
338 | + .name = TYPE_TPM_MSSIM, | 432 | + .name = TYPE_TPM_MSSIM, |
339 | + .parent = TYPE_TPM_BACKEND, | 433 | + .parent = TYPE_TPM_BACKEND, |
340 | + .instance_size = sizeof(TPMmssim), | 434 | + .instance_size = sizeof(TPMMssim), |
341 | + .class_init = tpm_mssim_class_init, | 435 | + .class_init = tpm_mssim_class_init, |
342 | + .instance_init = tpm_mssim_instance_init, | 436 | + .instance_init = tpm_mssim_instance_init, |
343 | + .instance_finalize = tpm_mssim_instance_finalize, | 437 | + .instance_finalize = tpm_mssim_instance_finalize, |
344 | +}; | 438 | +}; |
345 | + | 439 | + |
... | ... | ||
369 | +#define TPM_SIGNAL_POWER_OFF 2 | 463 | +#define TPM_SIGNAL_POWER_OFF 2 |
370 | +#define TPM_SIGNAL_PHYS_PRES_ON 3 | 464 | +#define TPM_SIGNAL_PHYS_PRES_ON 3 |
371 | +#define TPM_SIGNAL_PHYS_PRES_OFF 4 | 465 | +#define TPM_SIGNAL_PHYS_PRES_OFF 4 |
372 | +#define TPM_SIGNAL_HASH_START 5 | 466 | +#define TPM_SIGNAL_HASH_START 5 |
373 | +#define TPM_SIGNAL_HASH_DATA 6 | 467 | +#define TPM_SIGNAL_HASH_DATA 6 |
374 | + // {uint32_t BufferSize, uint8_t[BufferSize] Buffer} | 468 | +/* {uint32_t BufferSize, uint8_t[BufferSize] Buffer} */ |
375 | +#define TPM_SIGNAL_HASH_END 7 | 469 | +#define TPM_SIGNAL_HASH_END 7 |
376 | +#define TPM_SEND_COMMAND 8 | 470 | +#define TPM_SEND_COMMAND 8 |
377 | + // {uint8_t Locality, uint32_t InBufferSize, uint8_t[InBufferSize] InBuffer} -> | 471 | +/* |
378 | + // {uint32_t OutBufferSize, uint8_t[OutBufferSize] OutBuffer} | 472 | + * {uint8_t Locality, uint32_t InBufferSize, uint8_t[InBufferSize] InBuffer} -> |
379 | + | 473 | + * {uint32_t OutBufferSize, uint8_t[OutBufferSize] OutBuffer} |
474 | + */ | ||
380 | +#define TPM_SIGNAL_CANCEL_ON 9 | 475 | +#define TPM_SIGNAL_CANCEL_ON 9 |
381 | +#define TPM_SIGNAL_CANCEL_OFF 10 | 476 | +#define TPM_SIGNAL_CANCEL_OFF 10 |
382 | +#define TPM_SIGNAL_NV_ON 11 | 477 | +#define TPM_SIGNAL_NV_ON 11 |
383 | +#define TPM_SIGNAL_NV_OFF 12 | 478 | +#define TPM_SIGNAL_NV_OFF 12 |
384 | +#define TPM_SIGNAL_KEY_CACHE_ON 13 | 479 | +#define TPM_SIGNAL_KEY_CACHE_ON 13 |
... | ... | ||
396 | +#define TPM_GET_COMMAND_RESPONSE_SIZES 25 | 491 | +#define TPM_GET_COMMAND_RESPONSE_SIZES 25 |
397 | + | 492 | + |
398 | +#define TPM_ACT_GET_SIGNALED 26 | 493 | +#define TPM_ACT_GET_SIGNALED 26 |
399 | + | 494 | + |
400 | +#define TPM_TEST_FAILURE_MODE 30 | 495 | +#define TPM_TEST_FAILURE_MODE 30 |
401 | diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c | 496 | diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst |
402 | index XXXXXXX..XXXXXXX 100644 | 497 | index XXXXXXX..XXXXXXX 100644 |
403 | --- a/monitor/hmp-cmds.c | 498 | --- a/docs/specs/tpm.rst |
404 | +++ b/monitor/hmp-cmds.c | 499 | +++ b/docs/specs/tpm.rst |
500 | @@ -XXX,XX +XXX,XX @@ available as a module (assuming a TPM 2 is passed through): | ||
501 | /sys/devices/LNXSYSTEM:00/LNXSYBUS:00/MSFT0101:00/tpm/tpm0/pcr-sha256/9 | ||
502 | ... | ||
503 | |||
504 | +The QEMU TPM Microsoft Simulator Device | ||
505 | +--------------------------------------- | ||
506 | + | ||
507 | +The Microsoft Simulator (mssim) is the reference emulation platform | ||
508 | +for the TCG TPM 2.0 specification. It provides a reference | ||
509 | +implementation for the TPM 2.0 written by Microsoft (See | ||
510 | +`ms-tpm-20-ref`_ on github). The reference implementation starts a | ||
511 | +network server and listens for TPM commands on port 2321 and TPM | ||
512 | +Platform control commands on port 2322, although these can be altered. | ||
513 | +The QEMU mssim TPM backend talks to this implementation. By default | ||
514 | +it connects to the default ports on localhost: | ||
515 | + | ||
516 | +.. code-block:: console | ||
517 | + | ||
518 | + qemu-system-x86_64 <qemu-options> \ | ||
519 | + -tpmdev mssim,id=tpm0 \ | ||
520 | + -device tpm-crb,tpmdev=tpm0 | ||
521 | + | ||
522 | + | ||
523 | +Although it can also communicate with a remote host, which must be | ||
524 | +specified as a SocketAddress via json or dotted keys on the command | ||
525 | +line for each of the command and control ports: | ||
526 | + | ||
527 | +.. code-block:: console | ||
528 | + | ||
529 | + qemu-system-x86_64 <qemu-options> \ | ||
530 | + -tpmdev "{'type':'mssim','id':'tpm0','command':{'type':'inet','host':'remote','port':'2321'},'control':{'type':'inet','host':'remote','port':'2322'}}" \ | ||
531 | + -device tpm-crb,tpmdev=tpm0 | ||
532 | + | ||
533 | + | ||
534 | +The mssim backend supports snapshotting and migration by not resetting | ||
535 | +the TPM on start up and not powering it down on halt if the VM is in | ||
536 | +migration, but the state of the Microsoft Simulator server must be | ||
537 | +preserved (or the server kept running) outside of QEMU for restore to | ||
538 | +be successful. | ||
539 | + | ||
540 | The QEMU TPM emulator device | ||
541 | ---------------------------- | ||
542 | |||
543 | @@ -XXX,XX +XXX,XX @@ the following: | ||
544 | |||
545 | .. _SWTPM protocol: | ||
546 | https://github.com/stefanberger/swtpm/blob/master/man/man3/swtpm_ioctls.pod | ||
547 | + | ||
548 | +.. _ms-tpm-20-ref: | ||
549 | + https://github.com/microsoft/ms-tpm-20-ref | ||
550 | diff --git a/qapi/tpm.json b/qapi/tpm.json | ||
551 | index XXXXXXX..XXXXXXX 100644 | ||
552 | --- a/qapi/tpm.json | ||
553 | +++ b/qapi/tpm.json | ||
554 | @@ -XXX,XX +XXX,XX @@ | ||
555 | # = TPM (trusted platform module) devices | ||
556 | ## | ||
557 | |||
558 | +{ 'include': 'sockets.json' } | ||
559 | + | ||
560 | ## | ||
561 | # @TpmModel: | ||
562 | # | ||
563 | @@ -XXX,XX +XXX,XX @@ | ||
564 | # | ||
565 | # @emulator: Software Emulator TPM type (since 2.11) | ||
566 | # | ||
567 | +# @mssim: Microsoft TPM Emulator (since 9.0) | ||
568 | +# | ||
569 | # Since: 1.5 | ||
570 | ## | ||
571 | -{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ], | ||
572 | +{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator', 'mssim' ], | ||
573 | 'if': 'CONFIG_TPM' } | ||
574 | |||
575 | ## | ||
576 | @@ -XXX,XX +XXX,XX @@ | ||
577 | # .. qmp-example:: | ||
578 | # | ||
579 | # -> { "execute": "query-tpm-types" } | ||
580 | -# <- { "return": [ "passthrough", "emulator" ] } | ||
581 | +# <- { "return": [ "passthrough", "emulator", "mssim" ] } | ||
582 | ## | ||
583 | { 'command': 'query-tpm-types', 'returns': ['TpmType'], | ||
584 | 'if': 'CONFIG_TPM' } | ||
585 | @@ -XXX,XX +XXX,XX @@ | ||
586 | 'data': { 'data': 'TPMEmulatorOptions' }, | ||
587 | 'if': 'CONFIG_TPM' } | ||
588 | |||
589 | +## | ||
590 | +# @TPMMssimOptions: | ||
591 | +# | ||
592 | +# Information for the mssim emulator connection | ||
593 | +# | ||
594 | +# @command: command socket for the TPM emulator | ||
595 | +# | ||
596 | +# @control: control socket for the TPM emulator | ||
597 | +# | ||
598 | +# Since: 9.0 | ||
599 | +## | ||
600 | +{ 'struct': 'TPMMssimOptions', | ||
601 | + 'data': { '*command': 'SocketAddress', | ||
602 | + '*control': 'SocketAddress' }, | ||
603 | + 'if': 'CONFIG_TPM' } | ||
604 | + | ||
605 | ## | ||
606 | # @TpmTypeOptions: | ||
607 | # | ||
608 | @@ -XXX,XX +XXX,XX @@ | ||
609 | # passthrough type | ||
610 | # - 'emulator' The configuration options for TPM emulator backend | ||
611 | # type | ||
612 | +# - 'mssim' The configuration options for TPM emulator mssim type | ||
613 | # | ||
614 | # Since: 1.5 | ||
615 | ## | ||
616 | @@ -XXX,XX +XXX,XX @@ | ||
617 | 'base': { 'type': 'TpmType' }, | ||
618 | 'discriminator': 'type', | ||
619 | 'data': { 'passthrough' : 'TPMPassthroughOptionsWrapper', | ||
620 | - 'emulator': 'TPMEmulatorOptionsWrapper' }, | ||
621 | + 'emulator': 'TPMEmulatorOptionsWrapper', | ||
622 | + 'mssim' : 'TPMMssimOptions' }, | ||
623 | 'if': 'CONFIG_TPM' } | ||
624 | |||
625 | ## | ||
626 | @@ -XXX,XX +XXX,XX @@ | ||
627 | 'id' : 'str' }, | ||
628 | 'discriminator': 'type', | ||
629 | 'data': { 'passthrough' : 'TPMPassthroughOptions', | ||
630 | - 'emulator': 'TPMEmulatorOptions' }, | ||
631 | + 'emulator': 'TPMEmulatorOptions', | ||
632 | + 'mssim': 'TPMMssimOptions' }, | ||
633 | 'if': 'CONFIG_TPM' } | ||
634 | |||
635 | ## | ||
636 | diff --git a/system/tpm-hmp-cmds.c b/system/tpm-hmp-cmds.c | ||
637 | index XXXXXXX..XXXXXXX 100644 | ||
638 | --- a/system/tpm-hmp-cmds.c | ||
639 | +++ b/system/tpm-hmp-cmds.c | ||
405 | @@ -XXX,XX +XXX,XX @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) | 640 | @@ -XXX,XX +XXX,XX @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) |
406 | unsigned int c = 0; | 641 | unsigned int c = 0; |
407 | TPMPassthroughOptions *tpo; | 642 | TPMPassthroughOptions *tpo; |
408 | TPMEmulatorOptions *teo; | 643 | TPMEmulatorOptions *teo; |
409 | + TPMmssimOptions *tmo; | 644 | + TPMMssimOptions *tmo; |
410 | 645 | ||
411 | info_list = qmp_query_tpm(&err); | 646 | info_list = qmp_query_tpm(&err); |
412 | if (err) { | 647 | if (err) { |
413 | @@ -XXX,XX +XXX,XX @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) | 648 | @@ -XXX,XX +XXX,XX @@ void hmp_info_tpm(Monitor *mon, const QDict *qdict) |
414 | teo = &ti->options->u.emulator; | 649 | teo = ti->options->u.emulator.data; |
415 | monitor_printf(mon, ",chardev=%s", teo->chardev); | 650 | monitor_printf(mon, ",chardev=%s", teo->chardev); |
416 | break; | 651 | break; |
417 | + case TPM_TYPE_MSSIM: | 652 | + case TPM_TYPE_MSSIM: |
418 | + tmo = &ti->options->u.mssim; | 653 | + tmo = &ti->options->u.mssim; |
419 | + monitor_printf(mon, ",command=%s:%s,control=%s:%s", | 654 | + monitor_printf(mon, ",command=%s:%s,control=%s:%s", |
420 | + tmo->command->u.inet.host, tmo->command->u.inet.port, | 655 | + tmo->command->u.inet.host, |
421 | + tmo->control->u.inet.host, tmo->control->u.inet.port); | 656 | + tmo->command->u.inet.port, |
657 | + tmo->control->u.inet.host, | ||
658 | + tmo->control->u.inet.port); | ||
422 | + break; | 659 | + break; |
423 | case TPM_TYPE__MAX: | 660 | case TPM_TYPE__MAX: |
424 | break; | 661 | break; |
425 | } | 662 | } |
426 | diff --git a/qapi/tpm.json b/qapi/tpm.json | ||
427 | index XXXXXXX..XXXXXXX 100644 | ||
428 | --- a/qapi/tpm.json | ||
429 | +++ b/qapi/tpm.json | ||
430 | @@ -XXX,XX +XXX,XX @@ | ||
431 | ## | ||
432 | # = TPM (trusted platform module) devices | ||
433 | ## | ||
434 | +{ 'include': 'sockets.json' } | ||
435 | |||
436 | ## | ||
437 | # @TpmModel: | ||
438 | @@ -XXX,XX +XXX,XX @@ | ||
439 | # | ||
440 | # Since: 1.5 | ||
441 | ## | ||
442 | -{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator' ], | ||
443 | +{ 'enum': 'TpmType', 'data': [ 'passthrough', 'emulator', 'mssim' ], | ||
444 | 'if': 'CONFIG_TPM' } | ||
445 | |||
446 | ## | ||
447 | @@ -XXX,XX +XXX,XX @@ | ||
448 | # Example: | ||
449 | # | ||
450 | # -> { "execute": "query-tpm-types" } | ||
451 | -# <- { "return": [ "passthrough", "emulator" ] } | ||
452 | +# <- { "return": [ "passthrough", "emulator", "mssim" ] } | ||
453 | # | ||
454 | ## | ||
455 | { 'command': 'query-tpm-types', 'returns': ['TpmType'], | ||
456 | @@ -XXX,XX +XXX,XX @@ | ||
457 | { 'struct': 'TPMEmulatorOptions', 'data': { 'chardev' : 'str' }, | ||
458 | 'if': 'CONFIG_TPM' } | ||
459 | |||
460 | +## | ||
461 | +# @TPMmssimOptions: | ||
462 | +# | ||
463 | +# Information for the mssim emulator connection | ||
464 | +# | ||
465 | +# @command: command socket for the TPM emulator | ||
466 | +# @control: control socket for the TPM emulator | ||
467 | +# | ||
468 | +# Since: 7.2.0 | ||
469 | +## | ||
470 | +{ 'struct': 'TPMmssimOptions', | ||
471 | + 'data': { | ||
472 | + '*command': 'SocketAddress', | ||
473 | + '*control': 'SocketAddress' }, | ||
474 | + 'if': 'CONFIG_TPM' } | ||
475 | + | ||
476 | ## | ||
477 | # @TpmTypeOptions: | ||
478 | # | ||
479 | @@ -XXX,XX +XXX,XX @@ | ||
480 | # @id: identifier of the backend | ||
481 | # @type: - 'passthrough' The configuration options for the TPM passthrough type | ||
482 | # - 'emulator' The configuration options for TPM emulator backend type | ||
483 | +# - 'mssim' The configuration options for TPM emulator mssim type | ||
484 | # | ||
485 | # Since: 1.5 | ||
486 | ## | ||
487 | @@ -XXX,XX +XXX,XX @@ | ||
488 | 'id': 'str' }, | ||
489 | 'discriminator': 'type', | ||
490 | 'data': { 'passthrough' : 'TPMPassthroughOptions', | ||
491 | - 'emulator': 'TPMEmulatorOptions' }, | ||
492 | + 'emulator': 'TPMEmulatorOptions', | ||
493 | + 'mssim': 'TPMmssimOptions' }, | ||
494 | 'if': 'CONFIG_TPM' } | ||
495 | |||
496 | ## | ||
497 | -- | 663 | -- |
498 | 2.35.3 | 664 | 2.35.3 | diff view generated by jsdifflib |