Statistics
| Branch: | Revision:

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
}