root / tpm.c @ feature-archipelago
History | View | Annotate | Download (7.6 kB)
1 | d1a0cf73 | Stefan Berger | /*
|
---|---|---|---|
2 | d1a0cf73 | Stefan Berger | * TPM configuration
|
3 | d1a0cf73 | Stefan Berger | *
|
4 | d1a0cf73 | Stefan Berger | * Copyright (C) 2011-2013 IBM Corporation
|
5 | d1a0cf73 | Stefan Berger | *
|
6 | d1a0cf73 | Stefan Berger | * Authors:
|
7 | d1a0cf73 | Stefan Berger | * Stefan Berger <stefanb@us.ibm.com>
|
8 | d1a0cf73 | Stefan Berger | *
|
9 | d1a0cf73 | Stefan Berger | * This work is licensed under the terms of the GNU GPL, version 2 or later.
|
10 | d1a0cf73 | Stefan Berger | * See the COPYING file in the top-level directory.
|
11 | d1a0cf73 | Stefan Berger | *
|
12 | d1a0cf73 | Stefan Berger | * Based on net.c
|
13 | d1a0cf73 | Stefan Berger | */
|
14 | d1a0cf73 | Stefan Berger | #include "config-host.h" |
15 | d1a0cf73 | Stefan Berger | |
16 | d1a0cf73 | Stefan Berger | #include "monitor/monitor.h" |
17 | d1a0cf73 | Stefan Berger | #include "qapi/qmp/qerror.h" |
18 | dccfcd0e | Paolo Bonzini | #include "sysemu/tpm_backend.h" |
19 | bdee56f5 | Paolo Bonzini | #include "sysemu/tpm.h" |
20 | d1a0cf73 | Stefan Berger | #include "qemu/config-file.h" |
21 | d1a0cf73 | Stefan Berger | #include "qmp-commands.h" |
22 | d1a0cf73 | Stefan Berger | |
23 | d1a0cf73 | Stefan Berger | static QLIST_HEAD(, TPMBackend) tpm_backends =
|
24 | d1a0cf73 | Stefan Berger | QLIST_HEAD_INITIALIZER(tpm_backends); |
25 | d1a0cf73 | Stefan Berger | |
26 | d1a0cf73 | Stefan Berger | |
27 | d1a0cf73 | Stefan Berger | #define TPM_MAX_MODELS 1 |
28 | d1a0cf73 | Stefan Berger | #define TPM_MAX_DRIVERS 1 |
29 | d1a0cf73 | Stefan Berger | |
30 | d1a0cf73 | Stefan Berger | static TPMDriverOps const *be_drivers[TPM_MAX_DRIVERS] = { |
31 | d1a0cf73 | Stefan Berger | NULL,
|
32 | d1a0cf73 | Stefan Berger | }; |
33 | d1a0cf73 | Stefan Berger | |
34 | d1a0cf73 | Stefan Berger | static enum TpmModel tpm_models[TPM_MAX_MODELS] = { |
35 | 8cdd2e0a | Peter Maydell | TPM_MODEL_MAX, |
36 | d1a0cf73 | Stefan Berger | }; |
37 | d1a0cf73 | Stefan Berger | |
38 | d1a0cf73 | Stefan Berger | int tpm_register_model(enum TpmModel model) |
39 | d1a0cf73 | Stefan Berger | { |
40 | d1a0cf73 | Stefan Berger | int i;
|
41 | d1a0cf73 | Stefan Berger | |
42 | d1a0cf73 | Stefan Berger | for (i = 0; i < TPM_MAX_MODELS; i++) { |
43 | 8cdd2e0a | Peter Maydell | if (tpm_models[i] == TPM_MODEL_MAX) {
|
44 | d1a0cf73 | Stefan Berger | tpm_models[i] = model; |
45 | d1a0cf73 | Stefan Berger | return 0; |
46 | d1a0cf73 | Stefan Berger | } |
47 | d1a0cf73 | Stefan Berger | } |
48 | d1a0cf73 | Stefan Berger | error_report("Could not register TPM model");
|
49 | d1a0cf73 | Stefan Berger | return 1; |
50 | d1a0cf73 | Stefan Berger | } |
51 | d1a0cf73 | Stefan Berger | |
52 | d1a0cf73 | Stefan Berger | static bool tpm_model_is_registered(enum TpmModel model) |
53 | d1a0cf73 | Stefan Berger | { |
54 | d1a0cf73 | Stefan Berger | int i;
|
55 | d1a0cf73 | Stefan Berger | |
56 | d1a0cf73 | Stefan Berger | for (i = 0; i < TPM_MAX_MODELS; i++) { |
57 | d1a0cf73 | Stefan Berger | if (tpm_models[i] == model) {
|
58 | d1a0cf73 | Stefan Berger | return true; |
59 | d1a0cf73 | Stefan Berger | } |
60 | d1a0cf73 | Stefan Berger | } |
61 | d1a0cf73 | Stefan Berger | return false; |
62 | d1a0cf73 | Stefan Berger | } |
63 | 4549a8b7 | Stefan Berger | |
64 | d1a0cf73 | Stefan Berger | const TPMDriverOps *tpm_get_backend_driver(const char *type) |
65 | d1a0cf73 | Stefan Berger | { |
66 | d1a0cf73 | Stefan Berger | int i;
|
67 | d1a0cf73 | Stefan Berger | |
68 | d1a0cf73 | Stefan Berger | for (i = 0; i < TPM_MAX_DRIVERS && be_drivers[i] != NULL; i++) { |
69 | d1a0cf73 | Stefan Berger | if (!strcmp(TpmType_lookup[be_drivers[i]->type], type)) {
|
70 | d1a0cf73 | Stefan Berger | return be_drivers[i];
|
71 | d1a0cf73 | Stefan Berger | } |
72 | d1a0cf73 | Stefan Berger | } |
73 | d1a0cf73 | Stefan Berger | |
74 | d1a0cf73 | Stefan Berger | return NULL; |
75 | d1a0cf73 | Stefan Berger | } |
76 | d1a0cf73 | Stefan Berger | |
77 | d1a0cf73 | Stefan Berger | #ifdef CONFIG_TPM
|
78 | d1a0cf73 | Stefan Berger | |
79 | d1a0cf73 | Stefan Berger | int tpm_register_driver(const TPMDriverOps *tdo) |
80 | d1a0cf73 | Stefan Berger | { |
81 | d1a0cf73 | Stefan Berger | int i;
|
82 | d1a0cf73 | Stefan Berger | |
83 | d1a0cf73 | Stefan Berger | for (i = 0; i < TPM_MAX_DRIVERS; i++) { |
84 | d1a0cf73 | Stefan Berger | if (!be_drivers[i]) {
|
85 | d1a0cf73 | Stefan Berger | be_drivers[i] = tdo; |
86 | d1a0cf73 | Stefan Berger | return 0; |
87 | d1a0cf73 | Stefan Berger | } |
88 | d1a0cf73 | Stefan Berger | } |
89 | d1a0cf73 | Stefan Berger | error_report("Could not register TPM driver");
|
90 | d1a0cf73 | Stefan Berger | return 1; |
91 | d1a0cf73 | Stefan Berger | } |
92 | d1a0cf73 | Stefan Berger | |
93 | d1a0cf73 | Stefan Berger | /*
|
94 | d1a0cf73 | Stefan Berger | * Walk the list of available TPM backend drivers and display them on the
|
95 | d1a0cf73 | Stefan Berger | * screen.
|
96 | d1a0cf73 | Stefan Berger | */
|
97 | bdee56f5 | Paolo Bonzini | static void tpm_display_backend_drivers(void) |
98 | d1a0cf73 | Stefan Berger | { |
99 | d1a0cf73 | Stefan Berger | int i;
|
100 | d1a0cf73 | Stefan Berger | |
101 | d1a0cf73 | Stefan Berger | fprintf(stderr, "Supported TPM types (choose only one):\n");
|
102 | d1a0cf73 | Stefan Berger | |
103 | d1a0cf73 | Stefan Berger | for (i = 0; i < TPM_MAX_DRIVERS && be_drivers[i] != NULL; i++) { |
104 | d1a0cf73 | Stefan Berger | fprintf(stderr, "%12s %s\n",
|
105 | d1a0cf73 | Stefan Berger | TpmType_lookup[be_drivers[i]->type], be_drivers[i]->desc()); |
106 | d1a0cf73 | Stefan Berger | } |
107 | d1a0cf73 | Stefan Berger | fprintf(stderr, "\n");
|
108 | d1a0cf73 | Stefan Berger | } |
109 | d1a0cf73 | Stefan Berger | |
110 | d1a0cf73 | Stefan Berger | /*
|
111 | d1a0cf73 | Stefan Berger | * Find the TPM with the given Id
|
112 | d1a0cf73 | Stefan Berger | */
|
113 | d1a0cf73 | Stefan Berger | TPMBackend *qemu_find_tpm(const char *id) |
114 | d1a0cf73 | Stefan Berger | { |
115 | d1a0cf73 | Stefan Berger | TPMBackend *drv; |
116 | d1a0cf73 | Stefan Berger | |
117 | d1a0cf73 | Stefan Berger | if (id) {
|
118 | d1a0cf73 | Stefan Berger | QLIST_FOREACH(drv, &tpm_backends, list) { |
119 | d1a0cf73 | Stefan Berger | if (!strcmp(drv->id, id)) {
|
120 | d1a0cf73 | Stefan Berger | return drv;
|
121 | d1a0cf73 | Stefan Berger | } |
122 | d1a0cf73 | Stefan Berger | } |
123 | d1a0cf73 | Stefan Berger | } |
124 | d1a0cf73 | Stefan Berger | |
125 | d1a0cf73 | Stefan Berger | return NULL; |
126 | d1a0cf73 | Stefan Berger | } |
127 | d1a0cf73 | Stefan Berger | |
128 | d1a0cf73 | Stefan Berger | static int configure_tpm(QemuOpts *opts) |
129 | d1a0cf73 | Stefan Berger | { |
130 | d1a0cf73 | Stefan Berger | const char *value; |
131 | d1a0cf73 | Stefan Berger | const char *id; |
132 | d1a0cf73 | Stefan Berger | const TPMDriverOps *be;
|
133 | d1a0cf73 | Stefan Berger | TPMBackend *drv; |
134 | 8f0605cc | Stefan Berger | Error *local_err = NULL;
|
135 | d1a0cf73 | Stefan Berger | |
136 | d1a0cf73 | Stefan Berger | if (!QLIST_EMPTY(&tpm_backends)) {
|
137 | d1a0cf73 | Stefan Berger | error_report("Only one TPM is allowed.\n");
|
138 | d1a0cf73 | Stefan Berger | return 1; |
139 | d1a0cf73 | Stefan Berger | } |
140 | d1a0cf73 | Stefan Berger | |
141 | d1a0cf73 | Stefan Berger | id = qemu_opts_id(opts); |
142 | d1a0cf73 | Stefan Berger | if (id == NULL) { |
143 | d1a0cf73 | Stefan Berger | qerror_report(QERR_MISSING_PARAMETER, "id");
|
144 | d1a0cf73 | Stefan Berger | return 1; |
145 | d1a0cf73 | Stefan Berger | } |
146 | d1a0cf73 | Stefan Berger | |
147 | d1a0cf73 | Stefan Berger | value = qemu_opt_get(opts, "type");
|
148 | d1a0cf73 | Stefan Berger | if (!value) {
|
149 | d1a0cf73 | Stefan Berger | qerror_report(QERR_MISSING_PARAMETER, "type");
|
150 | d1a0cf73 | Stefan Berger | tpm_display_backend_drivers(); |
151 | d1a0cf73 | Stefan Berger | return 1; |
152 | d1a0cf73 | Stefan Berger | } |
153 | d1a0cf73 | Stefan Berger | |
154 | d1a0cf73 | Stefan Berger | be = tpm_get_backend_driver(value); |
155 | d1a0cf73 | Stefan Berger | if (be == NULL) { |
156 | d1a0cf73 | Stefan Berger | qerror_report(QERR_INVALID_PARAMETER_VALUE, "type",
|
157 | d1a0cf73 | Stefan Berger | "a TPM backend type");
|
158 | d1a0cf73 | Stefan Berger | tpm_display_backend_drivers(); |
159 | d1a0cf73 | Stefan Berger | return 1; |
160 | d1a0cf73 | Stefan Berger | } |
161 | d1a0cf73 | Stefan Berger | |
162 | bb716238 | Stefan Berger | /* validate backend specific opts */
|
163 | bb716238 | Stefan Berger | qemu_opts_validate(opts, be->opts, &local_err); |
164 | 84d18f06 | Markus Armbruster | if (local_err) {
|
165 | bb716238 | Stefan Berger | qerror_report_err(local_err); |
166 | bb716238 | Stefan Berger | error_free(local_err); |
167 | bb716238 | Stefan Berger | return 1; |
168 | bb716238 | Stefan Berger | } |
169 | bb716238 | Stefan Berger | |
170 | d1a0cf73 | Stefan Berger | drv = be->create(opts, id); |
171 | d1a0cf73 | Stefan Berger | if (!drv) {
|
172 | d1a0cf73 | Stefan Berger | return 1; |
173 | d1a0cf73 | Stefan Berger | } |
174 | d1a0cf73 | Stefan Berger | |
175 | 8f0605cc | Stefan Berger | tpm_backend_open(drv, &local_err); |
176 | 8f0605cc | Stefan Berger | if (local_err) {
|
177 | 8f0605cc | Stefan Berger | qerror_report_err(local_err); |
178 | 8f0605cc | Stefan Berger | error_free(local_err); |
179 | 8f0605cc | Stefan Berger | return 1; |
180 | 8f0605cc | Stefan Berger | } |
181 | 8f0605cc | Stefan Berger | |
182 | d1a0cf73 | Stefan Berger | QLIST_INSERT_HEAD(&tpm_backends, drv, list); |
183 | d1a0cf73 | Stefan Berger | |
184 | d1a0cf73 | Stefan Berger | return 0; |
185 | d1a0cf73 | Stefan Berger | } |
186 | d1a0cf73 | Stefan Berger | |
187 | d1a0cf73 | Stefan Berger | static int tpm_init_tpmdev(QemuOpts *opts, void *dummy) |
188 | d1a0cf73 | Stefan Berger | { |
189 | d1a0cf73 | Stefan Berger | return configure_tpm(opts);
|
190 | d1a0cf73 | Stefan Berger | } |
191 | d1a0cf73 | Stefan Berger | |
192 | d1a0cf73 | Stefan Berger | /*
|
193 | d1a0cf73 | Stefan Berger | * Walk the list of TPM backend drivers that are in use and call their
|
194 | d1a0cf73 | Stefan Berger | * destroy function to have them cleaned up.
|
195 | d1a0cf73 | Stefan Berger | */
|
196 | d1a0cf73 | Stefan Berger | void tpm_cleanup(void) |
197 | d1a0cf73 | Stefan Berger | { |
198 | d1a0cf73 | Stefan Berger | TPMBackend *drv, *next; |
199 | d1a0cf73 | Stefan Berger | |
200 | d1a0cf73 | Stefan Berger | QLIST_FOREACH_SAFE(drv, &tpm_backends, list, next) { |
201 | d1a0cf73 | Stefan Berger | QLIST_REMOVE(drv, list); |
202 | 8f0605cc | Stefan Berger | tpm_backend_destroy(drv); |
203 | d1a0cf73 | Stefan Berger | } |
204 | d1a0cf73 | Stefan Berger | } |
205 | d1a0cf73 | Stefan Berger | |
206 | d1a0cf73 | Stefan Berger | /*
|
207 | d1a0cf73 | Stefan Berger | * Initialize the TPM. Process the tpmdev command line options describing the
|
208 | d1a0cf73 | Stefan Berger | * TPM backend.
|
209 | d1a0cf73 | Stefan Berger | */
|
210 | d1a0cf73 | Stefan Berger | int tpm_init(void) |
211 | d1a0cf73 | Stefan Berger | { |
212 | d1a0cf73 | Stefan Berger | if (qemu_opts_foreach(qemu_find_opts("tpmdev"), |
213 | d1a0cf73 | Stefan Berger | tpm_init_tpmdev, NULL, 1) != 0) { |
214 | d1a0cf73 | Stefan Berger | return -1; |
215 | d1a0cf73 | Stefan Berger | } |
216 | d1a0cf73 | Stefan Berger | |
217 | d1a0cf73 | Stefan Berger | atexit(tpm_cleanup); |
218 | d1a0cf73 | Stefan Berger | |
219 | d1a0cf73 | Stefan Berger | return 0; |
220 | d1a0cf73 | Stefan Berger | } |
221 | d1a0cf73 | Stefan Berger | |
222 | d1a0cf73 | Stefan Berger | /*
|
223 | d1a0cf73 | Stefan Berger | * Parse the TPM configuration options.
|
224 | d1a0cf73 | Stefan Berger | * To display all available TPM backends the user may use '-tpmdev help'
|
225 | d1a0cf73 | Stefan Berger | */
|
226 | d1a0cf73 | Stefan Berger | int tpm_config_parse(QemuOptsList *opts_list, const char *optarg) |
227 | d1a0cf73 | Stefan Berger | { |
228 | d1a0cf73 | Stefan Berger | QemuOpts *opts; |
229 | d1a0cf73 | Stefan Berger | |
230 | d1a0cf73 | Stefan Berger | if (!strcmp(optarg, "help")) { |
231 | d1a0cf73 | Stefan Berger | tpm_display_backend_drivers(); |
232 | d1a0cf73 | Stefan Berger | return -1; |
233 | d1a0cf73 | Stefan Berger | } |
234 | d1a0cf73 | Stefan Berger | opts = qemu_opts_parse(opts_list, optarg, 1);
|
235 | d1a0cf73 | Stefan Berger | if (!opts) {
|
236 | d1a0cf73 | Stefan Berger | return -1; |
237 | d1a0cf73 | Stefan Berger | } |
238 | d1a0cf73 | Stefan Berger | return 0; |
239 | d1a0cf73 | Stefan Berger | } |
240 | d1a0cf73 | Stefan Berger | |
241 | d1a0cf73 | Stefan Berger | #endif /* CONFIG_TPM */ |
242 | d1a0cf73 | Stefan Berger | |
243 | d1a0cf73 | Stefan Berger | static const TPMDriverOps *tpm_driver_find_by_type(enum TpmType type) |
244 | d1a0cf73 | Stefan Berger | { |
245 | d1a0cf73 | Stefan Berger | int i;
|
246 | d1a0cf73 | Stefan Berger | |
247 | d1a0cf73 | Stefan Berger | for (i = 0; i < TPM_MAX_DRIVERS && be_drivers[i] != NULL; i++) { |
248 | d1a0cf73 | Stefan Berger | if (be_drivers[i]->type == type) {
|
249 | d1a0cf73 | Stefan Berger | return be_drivers[i];
|
250 | d1a0cf73 | Stefan Berger | } |
251 | d1a0cf73 | Stefan Berger | } |
252 | d1a0cf73 | Stefan Berger | return NULL; |
253 | d1a0cf73 | Stefan Berger | } |
254 | d1a0cf73 | Stefan Berger | |
255 | d1a0cf73 | Stefan Berger | static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
|
256 | d1a0cf73 | Stefan Berger | { |
257 | d1a0cf73 | Stefan Berger | TPMInfo *res = g_new0(TPMInfo, 1);
|
258 | d1a0cf73 | Stefan Berger | TPMPassthroughOptions *tpo; |
259 | d1a0cf73 | Stefan Berger | |
260 | d1a0cf73 | Stefan Berger | res->id = g_strdup(drv->id); |
261 | d1a0cf73 | Stefan Berger | res->model = drv->fe_model; |
262 | 88ca7bcf | Corey Bryant | res->options = g_new0(TpmTypeOptions, 1);
|
263 | d1a0cf73 | Stefan Berger | |
264 | 88ca7bcf | Corey Bryant | switch (drv->ops->type) {
|
265 | d1a0cf73 | Stefan Berger | case TPM_TYPE_PASSTHROUGH:
|
266 | 88ca7bcf | Corey Bryant | res->options->kind = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH; |
267 | d1a0cf73 | Stefan Berger | tpo = g_new0(TPMPassthroughOptions, 1);
|
268 | 88ca7bcf | Corey Bryant | res->options->passthrough = tpo; |
269 | d1a0cf73 | Stefan Berger | if (drv->path) {
|
270 | d1a0cf73 | Stefan Berger | tpo->path = g_strdup(drv->path); |
271 | d1a0cf73 | Stefan Berger | tpo->has_path = true;
|
272 | d1a0cf73 | Stefan Berger | } |
273 | d1a0cf73 | Stefan Berger | if (drv->cancel_path) {
|
274 | d1a0cf73 | Stefan Berger | tpo->cancel_path = g_strdup(drv->cancel_path); |
275 | d1a0cf73 | Stefan Berger | tpo->has_cancel_path = true;
|
276 | d1a0cf73 | Stefan Berger | } |
277 | d1a0cf73 | Stefan Berger | break;
|
278 | d1a0cf73 | Stefan Berger | case TPM_TYPE_MAX:
|
279 | d1a0cf73 | Stefan Berger | break;
|
280 | d1a0cf73 | Stefan Berger | } |
281 | d1a0cf73 | Stefan Berger | |
282 | d1a0cf73 | Stefan Berger | return res;
|
283 | d1a0cf73 | Stefan Berger | } |
284 | d1a0cf73 | Stefan Berger | |
285 | d1a0cf73 | Stefan Berger | /*
|
286 | d1a0cf73 | Stefan Berger | * Walk the list of active TPM backends and collect information about them
|
287 | d1a0cf73 | Stefan Berger | * following the schema description in qapi-schema.json.
|
288 | d1a0cf73 | Stefan Berger | */
|
289 | d1a0cf73 | Stefan Berger | TPMInfoList *qmp_query_tpm(Error **errp) |
290 | d1a0cf73 | Stefan Berger | { |
291 | d1a0cf73 | Stefan Berger | TPMBackend *drv; |
292 | d1a0cf73 | Stefan Berger | TPMInfoList *info, *head = NULL, *cur_item = NULL; |
293 | d1a0cf73 | Stefan Berger | |
294 | d1a0cf73 | Stefan Berger | QLIST_FOREACH(drv, &tpm_backends, list) { |
295 | d1a0cf73 | Stefan Berger | if (!tpm_model_is_registered(drv->fe_model)) {
|
296 | d1a0cf73 | Stefan Berger | continue;
|
297 | d1a0cf73 | Stefan Berger | } |
298 | d1a0cf73 | Stefan Berger | info = g_new0(TPMInfoList, 1);
|
299 | d1a0cf73 | Stefan Berger | info->value = qmp_query_tpm_inst(drv); |
300 | d1a0cf73 | Stefan Berger | |
301 | d1a0cf73 | Stefan Berger | if (!cur_item) {
|
302 | d1a0cf73 | Stefan Berger | head = cur_item = info; |
303 | d1a0cf73 | Stefan Berger | } else {
|
304 | d1a0cf73 | Stefan Berger | cur_item->next = info; |
305 | d1a0cf73 | Stefan Berger | cur_item = info; |
306 | d1a0cf73 | Stefan Berger | } |
307 | d1a0cf73 | Stefan Berger | } |
308 | d1a0cf73 | Stefan Berger | |
309 | d1a0cf73 | Stefan Berger | return head;
|
310 | d1a0cf73 | Stefan Berger | } |
311 | d1a0cf73 | Stefan Berger | |
312 | d1a0cf73 | Stefan Berger | TpmTypeList *qmp_query_tpm_types(Error **errp) |
313 | d1a0cf73 | Stefan Berger | { |
314 | d1a0cf73 | Stefan Berger | unsigned int i = 0; |
315 | d1a0cf73 | Stefan Berger | TpmTypeList *head = NULL, *prev = NULL, *cur_item; |
316 | d1a0cf73 | Stefan Berger | |
317 | d1a0cf73 | Stefan Berger | for (i = 0; i < TPM_TYPE_MAX; i++) { |
318 | d1a0cf73 | Stefan Berger | if (!tpm_driver_find_by_type(i)) {
|
319 | d1a0cf73 | Stefan Berger | continue;
|
320 | d1a0cf73 | Stefan Berger | } |
321 | d1a0cf73 | Stefan Berger | cur_item = g_new0(TpmTypeList, 1);
|
322 | d1a0cf73 | Stefan Berger | cur_item->value = i; |
323 | d1a0cf73 | Stefan Berger | |
324 | d1a0cf73 | Stefan Berger | if (prev) {
|
325 | d1a0cf73 | Stefan Berger | prev->next = cur_item; |
326 | d1a0cf73 | Stefan Berger | } |
327 | d1a0cf73 | Stefan Berger | if (!head) {
|
328 | d1a0cf73 | Stefan Berger | head = cur_item; |
329 | d1a0cf73 | Stefan Berger | } |
330 | d1a0cf73 | Stefan Berger | prev = cur_item; |
331 | d1a0cf73 | Stefan Berger | } |
332 | d1a0cf73 | Stefan Berger | |
333 | d1a0cf73 | Stefan Berger | return head;
|
334 | d1a0cf73 | Stefan Berger | } |
335 | d1a0cf73 | Stefan Berger | |
336 | d1a0cf73 | Stefan Berger | TpmModelList *qmp_query_tpm_models(Error **errp) |
337 | d1a0cf73 | Stefan Berger | { |
338 | d1a0cf73 | Stefan Berger | unsigned int i = 0; |
339 | d1a0cf73 | Stefan Berger | TpmModelList *head = NULL, *prev = NULL, *cur_item; |
340 | d1a0cf73 | Stefan Berger | |
341 | d1a0cf73 | Stefan Berger | for (i = 0; i < TPM_MODEL_MAX; i++) { |
342 | d1a0cf73 | Stefan Berger | if (!tpm_model_is_registered(i)) {
|
343 | d1a0cf73 | Stefan Berger | continue;
|
344 | d1a0cf73 | Stefan Berger | } |
345 | d1a0cf73 | Stefan Berger | cur_item = g_new0(TpmModelList, 1);
|
346 | d1a0cf73 | Stefan Berger | cur_item->value = i; |
347 | d1a0cf73 | Stefan Berger | |
348 | d1a0cf73 | Stefan Berger | if (prev) {
|
349 | d1a0cf73 | Stefan Berger | prev->next = cur_item; |
350 | d1a0cf73 | Stefan Berger | } |
351 | d1a0cf73 | Stefan Berger | if (!head) {
|
352 | d1a0cf73 | Stefan Berger | head = cur_item; |
353 | d1a0cf73 | Stefan Berger | } |
354 | d1a0cf73 | Stefan Berger | prev = cur_item; |
355 | d1a0cf73 | Stefan Berger | } |
356 | d1a0cf73 | Stefan Berger | |
357 | d1a0cf73 | Stefan Berger | return head;
|
358 | d1a0cf73 | Stefan Berger | } |