Statistics
| Branch: | Revision:

root / tpm.c @ bdee56f5

History | View | Annotate | Download (7.3 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 8f0605cc Stefan Berger
#include "backends/tpm.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 d1a0cf73 Stefan Berger
    -1,
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 d1a0cf73 Stefan Berger
        if (tpm_models[i] == -1) {
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 d1a0cf73 Stefan Berger
    drv = be->create(opts, id);
163 d1a0cf73 Stefan Berger
    if (!drv) {
164 d1a0cf73 Stefan Berger
        return 1;
165 d1a0cf73 Stefan Berger
    }
166 d1a0cf73 Stefan Berger
167 8f0605cc Stefan Berger
    tpm_backend_open(drv, &local_err);
168 8f0605cc Stefan Berger
    if (local_err) {
169 8f0605cc Stefan Berger
        qerror_report_err(local_err);
170 8f0605cc Stefan Berger
        error_free(local_err);
171 8f0605cc Stefan Berger
        return 1;
172 8f0605cc Stefan Berger
    }
173 8f0605cc Stefan Berger
174 d1a0cf73 Stefan Berger
    QLIST_INSERT_HEAD(&tpm_backends, drv, list);
175 d1a0cf73 Stefan Berger
176 d1a0cf73 Stefan Berger
    return 0;
177 d1a0cf73 Stefan Berger
}
178 d1a0cf73 Stefan Berger
179 d1a0cf73 Stefan Berger
static int tpm_init_tpmdev(QemuOpts *opts, void *dummy)
180 d1a0cf73 Stefan Berger
{
181 d1a0cf73 Stefan Berger
    return configure_tpm(opts);
182 d1a0cf73 Stefan Berger
}
183 d1a0cf73 Stefan Berger
184 d1a0cf73 Stefan Berger
/*
185 d1a0cf73 Stefan Berger
 * Walk the list of TPM backend drivers that are in use and call their
186 d1a0cf73 Stefan Berger
 * destroy function to have them cleaned up.
187 d1a0cf73 Stefan Berger
 */
188 d1a0cf73 Stefan Berger
void tpm_cleanup(void)
189 d1a0cf73 Stefan Berger
{
190 d1a0cf73 Stefan Berger
    TPMBackend *drv, *next;
191 d1a0cf73 Stefan Berger
192 d1a0cf73 Stefan Berger
    QLIST_FOREACH_SAFE(drv, &tpm_backends, list, next) {
193 d1a0cf73 Stefan Berger
        QLIST_REMOVE(drv, list);
194 8f0605cc Stefan Berger
        tpm_backend_destroy(drv);
195 d1a0cf73 Stefan Berger
    }
196 d1a0cf73 Stefan Berger
}
197 d1a0cf73 Stefan Berger
198 d1a0cf73 Stefan Berger
/*
199 d1a0cf73 Stefan Berger
 * Initialize the TPM. Process the tpmdev command line options describing the
200 d1a0cf73 Stefan Berger
 * TPM backend.
201 d1a0cf73 Stefan Berger
 */
202 d1a0cf73 Stefan Berger
int tpm_init(void)
203 d1a0cf73 Stefan Berger
{
204 d1a0cf73 Stefan Berger
    if (qemu_opts_foreach(qemu_find_opts("tpmdev"),
205 d1a0cf73 Stefan Berger
                          tpm_init_tpmdev, NULL, 1) != 0) {
206 d1a0cf73 Stefan Berger
        return -1;
207 d1a0cf73 Stefan Berger
    }
208 d1a0cf73 Stefan Berger
209 d1a0cf73 Stefan Berger
    atexit(tpm_cleanup);
210 d1a0cf73 Stefan Berger
211 d1a0cf73 Stefan Berger
    return 0;
212 d1a0cf73 Stefan Berger
}
213 d1a0cf73 Stefan Berger
214 d1a0cf73 Stefan Berger
/*
215 d1a0cf73 Stefan Berger
 * Parse the TPM configuration options.
216 d1a0cf73 Stefan Berger
 * To display all available TPM backends the user may use '-tpmdev help'
217 d1a0cf73 Stefan Berger
 */
218 d1a0cf73 Stefan Berger
int tpm_config_parse(QemuOptsList *opts_list, const char *optarg)
219 d1a0cf73 Stefan Berger
{
220 d1a0cf73 Stefan Berger
    QemuOpts *opts;
221 d1a0cf73 Stefan Berger
222 d1a0cf73 Stefan Berger
    if (!strcmp(optarg, "help")) {
223 d1a0cf73 Stefan Berger
        tpm_display_backend_drivers();
224 d1a0cf73 Stefan Berger
        return -1;
225 d1a0cf73 Stefan Berger
    }
226 d1a0cf73 Stefan Berger
    opts = qemu_opts_parse(opts_list, optarg, 1);
227 d1a0cf73 Stefan Berger
    if (!opts) {
228 d1a0cf73 Stefan Berger
        return -1;
229 d1a0cf73 Stefan Berger
    }
230 d1a0cf73 Stefan Berger
    return 0;
231 d1a0cf73 Stefan Berger
}
232 d1a0cf73 Stefan Berger
233 d1a0cf73 Stefan Berger
#endif /* CONFIG_TPM */
234 d1a0cf73 Stefan Berger
235 d1a0cf73 Stefan Berger
static const TPMDriverOps *tpm_driver_find_by_type(enum TpmType type)
236 d1a0cf73 Stefan Berger
{
237 d1a0cf73 Stefan Berger
    int i;
238 d1a0cf73 Stefan Berger
239 d1a0cf73 Stefan Berger
    for (i = 0; i < TPM_MAX_DRIVERS && be_drivers[i] != NULL; i++) {
240 d1a0cf73 Stefan Berger
        if (be_drivers[i]->type == type) {
241 d1a0cf73 Stefan Berger
            return be_drivers[i];
242 d1a0cf73 Stefan Berger
        }
243 d1a0cf73 Stefan Berger
    }
244 d1a0cf73 Stefan Berger
    return NULL;
245 d1a0cf73 Stefan Berger
}
246 d1a0cf73 Stefan Berger
247 d1a0cf73 Stefan Berger
static TPMInfo *qmp_query_tpm_inst(TPMBackend *drv)
248 d1a0cf73 Stefan Berger
{
249 d1a0cf73 Stefan Berger
    TPMInfo *res = g_new0(TPMInfo, 1);
250 d1a0cf73 Stefan Berger
    TPMPassthroughOptions *tpo;
251 d1a0cf73 Stefan Berger
252 d1a0cf73 Stefan Berger
    res->id = g_strdup(drv->id);
253 d1a0cf73 Stefan Berger
    res->model = drv->fe_model;
254 88ca7bcf Corey Bryant
    res->options = g_new0(TpmTypeOptions, 1);
255 d1a0cf73 Stefan Berger
256 88ca7bcf Corey Bryant
    switch (drv->ops->type) {
257 d1a0cf73 Stefan Berger
    case TPM_TYPE_PASSTHROUGH:
258 88ca7bcf Corey Bryant
        res->options->kind = TPM_TYPE_OPTIONS_KIND_PASSTHROUGH;
259 d1a0cf73 Stefan Berger
        tpo = g_new0(TPMPassthroughOptions, 1);
260 88ca7bcf Corey Bryant
        res->options->passthrough = tpo;
261 d1a0cf73 Stefan Berger
        if (drv->path) {
262 d1a0cf73 Stefan Berger
            tpo->path = g_strdup(drv->path);
263 d1a0cf73 Stefan Berger
            tpo->has_path = true;
264 d1a0cf73 Stefan Berger
        }
265 d1a0cf73 Stefan Berger
        if (drv->cancel_path) {
266 d1a0cf73 Stefan Berger
            tpo->cancel_path = g_strdup(drv->cancel_path);
267 d1a0cf73 Stefan Berger
            tpo->has_cancel_path = true;
268 d1a0cf73 Stefan Berger
        }
269 d1a0cf73 Stefan Berger
        break;
270 d1a0cf73 Stefan Berger
    case TPM_TYPE_MAX:
271 d1a0cf73 Stefan Berger
        break;
272 d1a0cf73 Stefan Berger
    }
273 d1a0cf73 Stefan Berger
274 d1a0cf73 Stefan Berger
    return res;
275 d1a0cf73 Stefan Berger
}
276 d1a0cf73 Stefan Berger
277 d1a0cf73 Stefan Berger
/*
278 d1a0cf73 Stefan Berger
 * Walk the list of active TPM backends and collect information about them
279 d1a0cf73 Stefan Berger
 * following the schema description in qapi-schema.json.
280 d1a0cf73 Stefan Berger
 */
281 d1a0cf73 Stefan Berger
TPMInfoList *qmp_query_tpm(Error **errp)
282 d1a0cf73 Stefan Berger
{
283 d1a0cf73 Stefan Berger
    TPMBackend *drv;
284 d1a0cf73 Stefan Berger
    TPMInfoList *info, *head = NULL, *cur_item = NULL;
285 d1a0cf73 Stefan Berger
286 d1a0cf73 Stefan Berger
    QLIST_FOREACH(drv, &tpm_backends, list) {
287 d1a0cf73 Stefan Berger
        if (!tpm_model_is_registered(drv->fe_model)) {
288 d1a0cf73 Stefan Berger
            continue;
289 d1a0cf73 Stefan Berger
        }
290 d1a0cf73 Stefan Berger
        info = g_new0(TPMInfoList, 1);
291 d1a0cf73 Stefan Berger
        info->value = qmp_query_tpm_inst(drv);
292 d1a0cf73 Stefan Berger
293 d1a0cf73 Stefan Berger
        if (!cur_item) {
294 d1a0cf73 Stefan Berger
            head = cur_item = info;
295 d1a0cf73 Stefan Berger
        } else {
296 d1a0cf73 Stefan Berger
            cur_item->next = info;
297 d1a0cf73 Stefan Berger
            cur_item = info;
298 d1a0cf73 Stefan Berger
        }
299 d1a0cf73 Stefan Berger
    }
300 d1a0cf73 Stefan Berger
301 d1a0cf73 Stefan Berger
    return head;
302 d1a0cf73 Stefan Berger
}
303 d1a0cf73 Stefan Berger
304 d1a0cf73 Stefan Berger
TpmTypeList *qmp_query_tpm_types(Error **errp)
305 d1a0cf73 Stefan Berger
{
306 d1a0cf73 Stefan Berger
    unsigned int i = 0;
307 d1a0cf73 Stefan Berger
    TpmTypeList *head = NULL, *prev = NULL, *cur_item;
308 d1a0cf73 Stefan Berger
309 d1a0cf73 Stefan Berger
    for (i = 0; i < TPM_TYPE_MAX; i++) {
310 d1a0cf73 Stefan Berger
        if (!tpm_driver_find_by_type(i)) {
311 d1a0cf73 Stefan Berger
            continue;
312 d1a0cf73 Stefan Berger
        }
313 d1a0cf73 Stefan Berger
        cur_item = g_new0(TpmTypeList, 1);
314 d1a0cf73 Stefan Berger
        cur_item->value = i;
315 d1a0cf73 Stefan Berger
316 d1a0cf73 Stefan Berger
        if (prev) {
317 d1a0cf73 Stefan Berger
            prev->next = cur_item;
318 d1a0cf73 Stefan Berger
        }
319 d1a0cf73 Stefan Berger
        if (!head) {
320 d1a0cf73 Stefan Berger
            head = cur_item;
321 d1a0cf73 Stefan Berger
        }
322 d1a0cf73 Stefan Berger
        prev = cur_item;
323 d1a0cf73 Stefan Berger
    }
324 d1a0cf73 Stefan Berger
325 d1a0cf73 Stefan Berger
    return head;
326 d1a0cf73 Stefan Berger
}
327 d1a0cf73 Stefan Berger
328 d1a0cf73 Stefan Berger
TpmModelList *qmp_query_tpm_models(Error **errp)
329 d1a0cf73 Stefan Berger
{
330 d1a0cf73 Stefan Berger
    unsigned int i = 0;
331 d1a0cf73 Stefan Berger
    TpmModelList *head = NULL, *prev = NULL, *cur_item;
332 d1a0cf73 Stefan Berger
333 d1a0cf73 Stefan Berger
    for (i = 0; i < TPM_MODEL_MAX; i++) {
334 d1a0cf73 Stefan Berger
        if (!tpm_model_is_registered(i)) {
335 d1a0cf73 Stefan Berger
            continue;
336 d1a0cf73 Stefan Berger
        }
337 d1a0cf73 Stefan Berger
        cur_item = g_new0(TpmModelList, 1);
338 d1a0cf73 Stefan Berger
        cur_item->value = i;
339 d1a0cf73 Stefan Berger
340 d1a0cf73 Stefan Berger
        if (prev) {
341 d1a0cf73 Stefan Berger
            prev->next = cur_item;
342 d1a0cf73 Stefan Berger
        }
343 d1a0cf73 Stefan Berger
        if (!head) {
344 d1a0cf73 Stefan Berger
            head = cur_item;
345 d1a0cf73 Stefan Berger
        }
346 d1a0cf73 Stefan Berger
        prev = cur_item;
347 d1a0cf73 Stefan Berger
    }
348 d1a0cf73 Stefan Berger
349 d1a0cf73 Stefan Berger
    return head;
350 d1a0cf73 Stefan Berger
}