qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

Merge remote-tracking branch 'remotes/stefanberger/tags/pull-tpm-2017-12-15-1' into staging

Merge tpm 2017/12/15 v1

# gpg: Signature made Fri 15 Dec 2017 04:44:15 GMT
# gpg: using RSA key 0x75AD65802A0B4211
# gpg: Good signature from "Stefan Berger <stefanb@linux.vnet.ibm.com>"
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: B818 B9CA DF90 89C2 D5CE C66B 75AD 6580 2A0B 4211

* remotes/stefanberger/tags/pull-tpm-2017-12-15-1: (32 commits)
tpm: tpm_passthrough: Fail startup if FE buffer size < BE buffer size
tpm: tpm_emulator: get and set buffer size of device
tpm: tpm_passthrough: Read the buffer size from the host device
tpm: pull tpm_util_request() out of tpm_util_test()
tpm: Move getting TPM buffer size to backends
tpm: remove tpm_register_model()
tpm-tis: use DEFINE_PROP_TPMBE
qdev: add DEFINE_PROP_TPMBE
tpm-tis: check that at most one TPM device exists
tpm-tis: remove redundant 'tpm_tis:' in error messages
tpm-emulator: add a FIXME comment about blocking cancel
acpi: change TPM TIS data conditions
tpm: add tpm_cmd_get_size() to tpm_util
tpm: add TPM interface to lookup TPM version
tpm: lookup the the TPM interface instead of TIS device
tpm: rename qemu_find_tpm() -> qemu_find_tpm_be()
tpm-tis: simplify header inclusion
tpm-passthrough: workaround a possible race
tpm-passthrough: simplify create()
tpm-passthrough: make it safer to destroy after creation
...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

+553 -266
+35 -57
backends/tpm.c
··· 17 17 #include "qapi/error.h" 18 18 #include "qapi/qmp/qerror.h" 19 19 #include "sysemu/tpm.h" 20 - #include "hw/tpm/tpm_int.h" 21 20 #include "qemu/thread.h" 21 + #include "qemu/main-loop.h" 22 + 23 + static void tpm_backend_request_completed_bh(void *opaque) 24 + { 25 + TPMBackend *s = TPM_BACKEND(opaque); 26 + TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif); 27 + 28 + tic->request_completed(s->tpmif); 29 + } 22 30 23 31 static void tpm_backend_worker_thread(gpointer data, gpointer user_data) 24 32 { 25 33 TPMBackend *s = TPM_BACKEND(user_data); 26 - TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 34 + TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 27 35 28 - assert(k->handle_request != NULL); 29 36 k->handle_request(s, (TPMBackendCmd *)data); 37 + 38 + qemu_bh_schedule(s->bh); 30 39 } 31 40 32 41 static void tpm_backend_thread_end(TPMBackend *s) ··· 44 53 return k->type; 45 54 } 46 55 47 - int tpm_backend_init(TPMBackend *s, TPMState *state) 56 + int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp) 48 57 { 49 - s->tpm_state = state; 58 + if (s->tpmif) { 59 + error_setg(errp, "TPM backend '%s' is already initialized", s->id); 60 + return -1; 61 + } 62 + 63 + s->tpmif = tpmif; 64 + object_ref(OBJECT(tpmif)); 65 + 50 66 s->had_startup_error = false; 51 67 52 68 return 0; 53 69 } 54 70 55 - int tpm_backend_startup_tpm(TPMBackend *s) 71 + int tpm_backend_startup_tpm(TPMBackend *s, size_t buffersize) 56 72 { 57 73 int res = 0; 58 74 TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); ··· 63 79 s->thread_pool = g_thread_pool_new(tpm_backend_worker_thread, s, 1, TRUE, 64 80 NULL); 65 81 66 - res = k->startup_tpm ? k->startup_tpm(s) : 0; 82 + res = k->startup_tpm ? k->startup_tpm(s, buffersize) : 0; 67 83 68 84 s->had_startup_error = (res != 0); 69 85 ··· 97 113 { 98 114 TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 99 115 100 - assert(k->cancel_cmd); 101 - 102 116 k->cancel_cmd(s); 103 117 } 104 118 ··· 122 136 { 123 137 TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 124 138 125 - assert(k->get_tpm_version); 126 - 127 139 return k->get_tpm_version(s); 128 140 } 129 141 130 - TPMInfo *tpm_backend_query_tpm(TPMBackend *s) 142 + size_t tpm_backend_get_buffer_size(TPMBackend *s) 131 143 { 132 - TPMInfo *info = g_new0(TPMInfo, 1); 133 144 TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 134 145 135 - info->id = g_strdup(s->id); 136 - info->model = s->fe_model; 137 - if (k->get_tpm_options) { 138 - info->options = k->get_tpm_options(s); 139 - } 140 - 141 - return info; 142 - } 143 - 144 - static bool tpm_backend_prop_get_opened(Object *obj, Error **errp) 145 - { 146 - TPMBackend *s = TPM_BACKEND(obj); 147 - 148 - return s->opened; 146 + return k->get_buffer_size(s); 149 147 } 150 148 151 - void tpm_backend_open(TPMBackend *s, Error **errp) 149 + TPMInfo *tpm_backend_query_tpm(TPMBackend *s) 152 150 { 153 - object_property_set_bool(OBJECT(s), true, "opened", errp); 154 - } 155 - 156 - static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp) 157 - { 158 - TPMBackend *s = TPM_BACKEND(obj); 151 + TPMInfo *info = g_new0(TPMInfo, 1); 159 152 TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s); 160 - Error *local_err = NULL; 161 - 162 - if (value == s->opened) { 163 - return; 164 - } 165 - 166 - if (!value && s->opened) { 167 - error_setg(errp, QERR_PERMISSION_DENIED); 168 - return; 169 - } 153 + TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif); 170 154 171 - if (k->opened) { 172 - k->opened(s, &local_err); 173 - if (local_err) { 174 - error_propagate(errp, local_err); 175 - return; 176 - } 177 - } 155 + info->id = g_strdup(s->id); 156 + info->model = tic->model; 157 + info->options = k->get_tpm_options(s); 178 158 179 - s->opened = true; 159 + return info; 180 160 } 181 161 182 162 static void tpm_backend_instance_init(Object *obj) 183 163 { 184 164 TPMBackend *s = TPM_BACKEND(obj); 185 165 186 - object_property_add_bool(obj, "opened", 187 - tpm_backend_prop_get_opened, 188 - tpm_backend_prop_set_opened, 189 - NULL); 190 - s->fe_model = -1; 166 + s->bh = qemu_bh_new(tpm_backend_request_completed_bh, s); 191 167 } 192 168 193 169 static void tpm_backend_instance_finalize(Object *obj) 194 170 { 195 171 TPMBackend *s = TPM_BACKEND(obj); 196 172 173 + object_unref(OBJECT(s->tpmif)); 197 174 g_free(s->id); 198 175 tpm_backend_thread_end(s); 176 + qemu_bh_delete(s->bh); 199 177 } 200 178 201 179 static const TypeInfo tpm_backend_info = {
+64
hw/core/qdev-properties-system.c
··· 21 21 #include "net/hub.h" 22 22 #include "qapi/visitor.h" 23 23 #include "chardev/char-fe.h" 24 + #include "sysemu/tpm_backend.h" 24 25 #include "sysemu/iothread.h" 25 26 26 27 static void get_pointer(Object *obj, Visitor *v, Property *prop, ··· 234 235 .get = get_chr, 235 236 .set = set_chr, 236 237 .release = release_chr, 238 + }; 239 + 240 + /* --- character device --- */ 241 + 242 + static void get_tpm(Object *obj, Visitor *v, const char *name, void *opaque, 243 + Error **errp) 244 + { 245 + DeviceState *dev = DEVICE(obj); 246 + TPMBackend **be = qdev_get_prop_ptr(dev, opaque); 247 + char *p; 248 + 249 + p = g_strdup(*be ? (*be)->id : ""); 250 + visit_type_str(v, name, &p, errp); 251 + g_free(p); 252 + } 253 + 254 + static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque, 255 + Error **errp) 256 + { 257 + DeviceState *dev = DEVICE(obj); 258 + Error *local_err = NULL; 259 + Property *prop = opaque; 260 + TPMBackend *s, **be = qdev_get_prop_ptr(dev, prop); 261 + char *str; 262 + 263 + if (dev->realized) { 264 + qdev_prop_set_after_realize(dev, name, errp); 265 + return; 266 + } 267 + 268 + visit_type_str(v, name, &str, &local_err); 269 + if (local_err) { 270 + error_propagate(errp, local_err); 271 + return; 272 + } 273 + 274 + s = qemu_find_tpm_be(str); 275 + if (s == NULL) { 276 + error_setg(errp, "Property '%s.%s' can't find value '%s'", 277 + object_get_typename(obj), prop->name, str); 278 + } else if (tpm_backend_init(s, TPM_IF(obj), errp) == 0) { 279 + *be = s; /* weak reference, avoid cyclic ref */ 280 + } 281 + g_free(str); 282 + } 283 + 284 + static void release_tpm(Object *obj, const char *name, void *opaque) 285 + { 286 + DeviceState *dev = DEVICE(obj); 287 + Property *prop = opaque; 288 + TPMBackend **be = qdev_get_prop_ptr(dev, prop); 289 + 290 + if (*be) { 291 + tpm_backend_reset(*be); 292 + } 293 + } 294 + 295 + const PropertyInfo qdev_prop_tpm = { 296 + .name = "str", 297 + .description = "ID of a tpm to use as a backend", 298 + .get = get_tpm, 299 + .set = set_tpm, 300 + .release = release_tpm, 237 301 }; 238 302 239 303 /* --- netdev device --- */
+9 -5
hw/i386/acpi-build.c
··· 208 208 } 209 209 210 210 info->has_hpet = hpet_find(); 211 - info->tpm_version = tpm_get_version(); 211 + info->tpm_version = tpm_get_version(tpm_find()); 212 212 info->pvpanic_port = pvpanic_port(); 213 213 info->applesmc_io_base = applesmc_port(); 214 214 } ··· 2038 2038 } 2039 2039 } 2040 2040 2041 - if (misc->tpm_version != TPM_VERSION_UNSPEC) { 2041 + if (TPM_IS_TIS(tpm_find())) { 2042 2042 aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE, 2043 2043 TPM_TIS_ADDR_SIZE, AML_READ_WRITE)); 2044 2044 } ··· 2204 2204 /* Scan all PCI buses. Generate tables to support hotplug. */ 2205 2205 build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); 2206 2206 2207 - if (misc->tpm_version != TPM_VERSION_UNSPEC) { 2207 + if (TPM_IS_TIS(tpm_find())) { 2208 2208 dev = aml_device("ISA.TPM"); 2209 2209 aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31"))); 2210 2210 aml_append(dev, aml_name_decl("_STA", aml_int(0xF))); ··· 2281 2281 tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr); 2282 2282 2283 2283 tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT); 2284 - tpm2_ptr->control_area_address = cpu_to_le64(0); 2285 - tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO); 2284 + if (TPM_IS_TIS(tpm_find())) { 2285 + tpm2_ptr->control_area_address = cpu_to_le64(0); 2286 + tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO); 2287 + } else { 2288 + g_warn_if_reached(); 2289 + } 2286 2290 2287 2291 build_header(linker, table_data, 2288 2292 (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL);
+84 -14
hw/tpm/tpm_emulator.c
··· 186 186 static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd) 187 187 { 188 188 TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 189 - TPMIfClass *tic = TPM_IF_GET_CLASS(tb->tpm_state); 190 189 Error *err = NULL; 191 190 192 191 DPRINTF("processing TPM command"); ··· 201 200 goto error; 202 201 } 203 202 204 - tic->request_completed(TPM_IF(tb->tpm_state)); 205 203 return; 206 204 207 205 error: ··· 234 232 switch (tpm_emu->tpm_version) { 235 233 case TPM_VERSION_1_2: 236 234 caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED | 237 - PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD; 235 + PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD | PTM_CAP_STOP | 236 + PTM_CAP_SET_BUFFERSIZE; 238 237 tpm = "1.2"; 239 238 break; 240 239 case TPM_VERSION_2_0: 241 240 caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED | 242 241 PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED | 243 - PTM_CAP_SET_DATAFD; 242 + PTM_CAP_SET_DATAFD | PTM_CAP_STOP | PTM_CAP_SET_BUFFERSIZE; 244 243 tpm = "2"; 245 244 break; 246 245 case TPM_VERSION_UNSPEC: ··· 257 256 return 0; 258 257 } 259 258 260 - static int tpm_emulator_startup_tpm(TPMBackend *tb) 259 + static int tpm_emulator_stop_tpm(TPMBackend *tb) 260 + { 261 + TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 262 + ptm_res res; 263 + 264 + if (tpm_emulator_ctrlcmd(tpm_emu, CMD_STOP, &res, 0, sizeof(res)) < 0) { 265 + error_report("tpm-emulator: Could not stop TPM: %s", 266 + strerror(errno)); 267 + return -1; 268 + } 269 + 270 + res = be32_to_cpu(res); 271 + if (res) { 272 + error_report("tpm-emulator: TPM result for CMD_STOP: 0x%x", res); 273 + return -1; 274 + } 275 + 276 + return 0; 277 + } 278 + 279 + static int tpm_emulator_set_buffer_size(TPMBackend *tb, 280 + size_t wanted_size, 281 + size_t *actual_size) 282 + { 283 + TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 284 + ptm_setbuffersize psbs; 285 + 286 + if (tpm_emulator_stop_tpm(tb) < 0) { 287 + return -1; 288 + } 289 + 290 + psbs.u.req.buffersize = cpu_to_be32(wanted_size); 291 + 292 + if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_BUFFERSIZE, &psbs, 293 + sizeof(psbs.u.req), sizeof(psbs.u.resp)) < 0) { 294 + error_report("tpm-emulator: Could not set buffer size: %s", 295 + strerror(errno)); 296 + return -1; 297 + } 298 + 299 + psbs.u.resp.tpm_result = be32_to_cpu(psbs.u.resp.tpm_result); 300 + if (psbs.u.resp.tpm_result != 0) { 301 + error_report("tpm-emulator: TPM result for set buffer size : 0x%x", 302 + psbs.u.resp.tpm_result); 303 + return -1; 304 + } 305 + 306 + if (actual_size) { 307 + *actual_size = be32_to_cpu(psbs.u.resp.buffersize); 308 + } 309 + 310 + DPRINTF("buffer size: %u, min: %u, max: %u\n", 311 + be32_to_cpu(psbs.u.resp.buffersize), 312 + be32_to_cpu(psbs.u.resp.minsize), 313 + be32_to_cpu(psbs.u.resp.maxsize)); 314 + 315 + return 0; 316 + } 317 + 318 + static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize) 261 319 { 262 320 TPMEmulator *tpm_emu = TPM_EMULATOR(tb); 263 321 ptm_init init; 264 322 ptm_res res; 323 + 324 + if (buffersize != 0 && 325 + tpm_emulator_set_buffer_size(tb, buffersize, NULL) < 0) { 326 + goto err_exit; 327 + } 265 328 266 329 DPRINTF("%s", __func__); 267 330 if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init), ··· 340 403 return; 341 404 } 342 405 406 + /* FIXME: make the function non-blocking, or it may block a VCPU */ 343 407 if (tpm_emulator_ctrlcmd(tpm_emu, CMD_CANCEL_TPM_CMD, &res, 0, 344 408 sizeof(res)) < 0) { 345 409 error_report("tpm-emulator: Could not cancel command: %s", ··· 357 421 return tpm_emu->tpm_version; 358 422 } 359 423 424 + static size_t tpm_emulator_get_buffer_size(TPMBackend *tb) 425 + { 426 + size_t actual_size; 427 + 428 + if (tpm_emulator_set_buffer_size(tb, 0, &actual_size) < 0) { 429 + return 4096; 430 + } 431 + 432 + return actual_size; 433 + } 434 + 360 435 static int tpm_emulator_block_migration(TPMEmulator *tpm_emu) 361 436 { 362 437 Error *err = NULL; ··· 465 540 return -1; 466 541 } 467 542 468 - static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id) 543 + static TPMBackend *tpm_emulator_create(QemuOpts *opts) 469 544 { 470 545 TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR)); 471 546 472 - tb->id = g_strdup(id); 473 - 474 547 if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) { 475 - goto err_exit; 548 + object_unref(OBJECT(tb)); 549 + return NULL; 476 550 } 477 551 478 552 return tb; 479 - 480 - err_exit: 481 - object_unref(OBJECT(tb)); 482 - 483 - return NULL; 484 553 } 485 554 486 555 static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb) ··· 563 632 tbc->get_tpm_established_flag = tpm_emulator_get_tpm_established_flag; 564 633 tbc->reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag; 565 634 tbc->get_tpm_version = tpm_emulator_get_tpm_version; 635 + tbc->get_buffer_size = tpm_emulator_get_buffer_size; 566 636 tbc->get_tpm_options = tpm_emulator_get_tpm_options; 567 637 568 638 tbc->handle_request = tpm_emulator_handle_request;
+10 -21
hw/tpm/tpm_int.h
··· 13 13 #define TPM_TPM_INT_H 14 14 15 15 #include "qemu/osdep.h" 16 - #include "qom/object.h" 17 16 18 - #define TYPE_TPM_IF "tpm-if" 19 - #define TPM_IF_CLASS(klass) \ 20 - OBJECT_CLASS_CHECK(TPMIfClass, (klass), TYPE_TPM_IF) 21 - #define TPM_IF_GET_CLASS(obj) \ 22 - OBJECT_GET_CLASS(TPMIfClass, (obj), TYPE_TPM_IF) 23 - #define TPM_IF(obj) \ 24 - INTERFACE_CHECK(TPMIf, (obj), TYPE_TPM_IF) 25 - 26 - typedef struct TPMIf { 27 - Object parent_obj; 28 - } TPMIf; 29 - 30 - typedef struct TPMIfClass { 31 - InterfaceClass parent_class; 32 - 33 - /* run in thread pool by backend */ 34 - void (*request_completed)(TPMIf *obj); 35 - } TPMIfClass; 36 - 37 - #define TPM_STANDARD_CMDLINE_OPTS \ 17 + #define TPM_STANDARD_CMDLINE_OPTS \ 38 18 { \ 39 19 .name = "type", \ 40 20 .type = QEMU_OPT_STRING, \ ··· 65 45 66 46 #define TPM_ORD_ContinueSelfTest 0x53 67 47 #define TPM_ORD_GetTicks 0xf1 48 + #define TPM_ORD_GetCapability 0x65 68 49 50 + #define TPM_CAP_PROPERTY 0x05 51 + 52 + #define TPM_CAP_PROP_INPUT_BUFFER 0x124 69 53 70 54 /* TPM2 defines */ 71 55 #define TPM2_ST_NO_SESSIONS 0x8001 72 56 73 57 #define TPM2_CC_ReadClock 0x00000181 58 + #define TPM2_CC_GetCapability 0x0000017a 59 + 60 + #define TPM2_CAP_TPM_PROPERTIES 0x6 61 + 62 + #define TPM2_PT_MAX_COMMAND_SIZE 0x11e 74 63 75 64 #endif /* TPM_TPM_INT_H */
+27 -1
hw/tpm/tpm_ioctl.h
··· 169 169 #define PTM_CONFIG_FLAG_FILE_KEY 0x1 170 170 #define PTM_CONFIG_FLAG_MIGRATION_KEY 0x2 171 171 172 + /* 173 + * PTM_SET_BUFFERSIZE: Set the buffer size to be used by the TPM. 174 + * A 0 on input queries for the current buffer size. Any other 175 + * number will try to set the buffer size. The returned number is 176 + * the buffer size that will be used, which can be larger than the 177 + * requested one, if it was below the minimum, or smaller than the 178 + * requested one, if it was above the maximum. 179 + */ 180 + struct ptm_setbuffersize { 181 + union { 182 + struct { 183 + uint32_t buffersize; /* 0 to query for current buffer size */ 184 + } req; /* request */ 185 + struct { 186 + ptm_res tpm_result; 187 + uint32_t buffersize; /* buffer size in use */ 188 + uint32_t minsize; /* min. supported buffer size */ 189 + uint32_t maxsize; /* max. supported buffer size */ 190 + } resp; /* response */ 191 + } u; 192 + }; 193 + 172 194 173 195 typedef uint64_t ptm_cap; 174 196 typedef struct ptm_est ptm_est; ··· 179 201 typedef struct ptm_getstate ptm_getstate; 180 202 typedef struct ptm_setstate ptm_setstate; 181 203 typedef struct ptm_getconfig ptm_getconfig; 204 + typedef struct ptm_setbuffersize ptm_setbuffersize; 182 205 183 206 /* capability flags returned by PTM_GET_CAPABILITY */ 184 207 #define PTM_CAP_INIT (1) ··· 194 217 #define PTM_CAP_STOP (1 << 10) 195 218 #define PTM_CAP_GET_CONFIG (1 << 11) 196 219 #define PTM_CAP_SET_DATAFD (1 << 12) 220 + #define PTM_CAP_SET_BUFFERSIZE (1 << 13) 197 221 198 222 enum { 199 223 PTM_GET_CAPABILITY = _IOR('P', 0, ptm_cap), ··· 212 236 PTM_STOP = _IOR('P', 13, ptm_res), 213 237 PTM_GET_CONFIG = _IOR('P', 14, ptm_getconfig), 214 238 PTM_SET_DATAFD = _IOR('P', 15, ptm_res), 239 + PTM_SET_BUFFERSIZE = _IOWR('P', 16, ptm_setbuffersize), 215 240 }; 216 241 217 242 /* ··· 240 265 CMD_SET_STATEBLOB, 241 266 CMD_STOP, 242 267 CMD_GET_CONFIG, 243 - CMD_SET_DATAFD 268 + CMD_SET_DATAFD, 269 + CMD_SET_BUFFERSIZE, 244 270 }; 245 271 246 272 #endif /* _TPM_IOCTL_H */
+50 -40
hw/tpm/tpm_passthrough.c
··· 57 57 int cancel_fd; 58 58 59 59 TPMVersion tpm_version; 60 + size_t tpm_buffersize; 60 61 }; 61 62 62 63 typedef struct TPMPassthruState TPMPassthruState; ··· 89 90 bool is_selftest; 90 91 const struct tpm_resp_hdr *hdr; 91 92 93 + /* FIXME: protect shared variables or use other sync mechanism */ 92 94 tpm_pt->tpm_op_canceled = false; 93 95 tpm_pt->tpm_executing = true; 94 96 *selftest_done = false; ··· 139 141 static void tpm_passthrough_handle_request(TPMBackend *tb, TPMBackendCmd *cmd) 140 142 { 141 143 TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 142 - TPMIfClass *tic = TPM_IF_GET_CLASS(tb->tpm_state); 143 144 144 145 DPRINTF("tpm_passthrough: processing command %p\n", cmd); 145 146 146 147 tpm_passthrough_unix_tx_bufs(tpm_pt, cmd->in, cmd->in_len, 147 148 cmd->out, cmd->out_len, &cmd->selftest_done); 148 - 149 - tic->request_completed(TPM_IF(tb->tpm_state)); 150 149 } 151 150 152 151 static void tpm_passthrough_reset(TPMBackend *tb) ··· 181 180 */ 182 181 if (tpm_pt->tpm_executing) { 183 182 if (tpm_pt->cancel_fd >= 0) { 183 + tpm_pt->tpm_op_canceled = true; 184 184 n = write(tpm_pt->cancel_fd, "-", 1); 185 185 if (n != 1) { 186 186 error_report("Canceling TPM command failed: %s", 187 187 strerror(errno)); 188 - } else { 189 - tpm_pt->tpm_op_canceled = true; 190 188 } 191 189 } else { 192 190 error_report("Cannot cancel TPM command due to missing " ··· 202 200 return tpm_pt->tpm_version; 203 201 } 204 202 203 + static size_t tpm_passthrough_get_buffer_size(TPMBackend *tb) 204 + { 205 + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 206 + int ret; 207 + 208 + ret = tpm_util_get_buffer_size(tpm_pt->tpm_fd, tpm_pt->tpm_version, 209 + &tpm_pt->tpm_buffersize); 210 + if (ret < 0) { 211 + tpm_pt->tpm_buffersize = 4096; 212 + } 213 + return tpm_pt->tpm_buffersize; 214 + } 215 + 205 216 /* 206 217 * Unless path or file descriptor set has been provided by user, 207 218 * determine the sysfs cancel file following kernel documentation ··· 229 240 if (snprintf(path, sizeof(path), "/sys/class/misc/%s/device/cancel", 230 241 dev) < sizeof(path)) { 231 242 fd = qemu_open(path, O_WRONLY); 232 - if (fd >= 0) { 233 - tpm_pt->options->cancel_path = g_strdup(path); 234 - } else { 243 + if (fd < 0) { 235 244 error_report("tpm_passthrough: Could not open TPM cancel " 236 245 "path %s : %s", path, strerror(errno)); 237 246 } ··· 244 253 return fd; 245 254 } 246 255 247 - static int tpm_passthrough_handle_device_opts(QemuOpts *opts, TPMBackend *tb) 256 + static int 257 + tpm_passthrough_handle_device_opts(TPMPassthruState *tpm_pt, QemuOpts *opts) 248 258 { 249 - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 250 259 const char *value; 251 260 252 261 value = qemu_opt_get(opts, "cancel-path"); ··· 266 275 if (tpm_pt->tpm_fd < 0) { 267 276 error_report("Cannot access TPM device using '%s': %s", 268 277 tpm_pt->tpm_dev, strerror(errno)); 269 - goto err_free_parameters; 278 + return -1; 270 279 } 271 280 272 281 if (tpm_util_test_tpmdev(tpm_pt->tpm_fd, &tpm_pt->tpm_version)) { 273 282 error_report("'%s' is not a TPM device.", 274 283 tpm_pt->tpm_dev); 275 - goto err_close_tpmdev; 284 + return -1; 276 285 } 277 286 278 - return 0; 279 - 280 - err_close_tpmdev: 281 - qemu_close(tpm_pt->tpm_fd); 282 - tpm_pt->tpm_fd = -1; 283 - 284 - err_free_parameters: 285 - qapi_free_TPMPassthroughOptions(tpm_pt->options); 286 - tpm_pt->options = NULL; 287 - tpm_pt->tpm_dev = NULL; 287 + tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt); 288 + if (tpm_pt->cancel_fd < 0) { 289 + return -1; 290 + } 288 291 289 - return 1; 292 + return 0; 290 293 } 291 294 292 - static TPMBackend *tpm_passthrough_create(QemuOpts *opts, const char *id) 295 + static TPMBackend *tpm_passthrough_create(QemuOpts *opts) 293 296 { 294 297 Object *obj = object_new(TYPE_TPM_PASSTHROUGH); 295 - TPMBackend *tb = TPM_BACKEND(obj); 296 - TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 297 298 298 - tb->id = g_strdup(id); 299 - 300 - if (tpm_passthrough_handle_device_opts(opts, tb)) { 301 - goto err_exit; 299 + if (tpm_passthrough_handle_device_opts(TPM_PASSTHROUGH(obj), opts)) { 300 + object_unref(obj); 301 + return NULL; 302 302 } 303 303 304 - tpm_pt->cancel_fd = tpm_passthrough_open_sysfs_cancel(tpm_pt); 305 - if (tpm_pt->cancel_fd < 0) { 306 - goto err_exit; 307 - } 304 + return TPM_BACKEND(obj); 305 + } 308 306 309 - return tb; 307 + static int tpm_passthrough_startup_tpm(TPMBackend *tb, size_t buffersize) 308 + { 309 + TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb); 310 310 311 - err_exit: 312 - object_unref(obj); 311 + if (buffersize && buffersize < tpm_pt->tpm_buffersize) { 312 + error_report("Requested buffer size of %zu is smaller than host TPM's " 313 + "fixed buffer size of %zu", 314 + buffersize, tpm_pt->tpm_buffersize); 315 + return -1; 316 + } 313 317 314 - return NULL; 318 + return 0; 315 319 } 316 320 317 321 static TpmTypeOptions *tpm_passthrough_get_tpm_options(TPMBackend *tb) ··· 355 359 356 360 tpm_passthrough_cancel_cmd(TPM_BACKEND(obj)); 357 361 358 - qemu_close(tpm_pt->tpm_fd); 359 - qemu_close(tpm_pt->cancel_fd); 362 + if (tpm_pt->tpm_fd >= 0) { 363 + qemu_close(tpm_pt->tpm_fd); 364 + } 365 + if (tpm_pt->cancel_fd >= 0) { 366 + qemu_close(tpm_pt->cancel_fd); 367 + } 360 368 qapi_free_TPMPassthroughOptions(tpm_pt->options); 361 369 } 362 370 ··· 368 376 tbc->opts = tpm_passthrough_cmdline_opts; 369 377 tbc->desc = "Passthrough TPM backend driver"; 370 378 tbc->create = tpm_passthrough_create; 379 + tbc->startup_tpm = tpm_passthrough_startup_tpm; 371 380 tbc->reset = tpm_passthrough_reset; 372 381 tbc->cancel_cmd = tpm_passthrough_cancel_cmd; 373 382 tbc->get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag; 374 383 tbc->reset_tpm_established_flag = 375 384 tpm_passthrough_reset_tpm_established_flag; 376 385 tbc->get_tpm_version = tpm_passthrough_get_tpm_version; 386 + tbc->get_buffer_size = tpm_passthrough_get_buffer_size; 377 387 tbc->get_tpm_options = tpm_passthrough_get_tpm_options; 378 388 tbc->handle_request = tpm_passthrough_handle_request; 379 389 }
+41 -60
hw/tpm/tpm_tis.c
··· 24 24 25 25 #include "qemu/osdep.h" 26 26 #include "hw/isa/isa.h" 27 + #include "qapi/error.h" 28 + 29 + #include "hw/acpi/tpm.h" 30 + #include "hw/pci/pci_ids.h" 27 31 #include "sysemu/tpm_backend.h" 28 32 #include "tpm_int.h" 29 - #include "sysemu/block-backend.h" 30 - #include "exec/address-spaces.h" 31 - #include "hw/hw.h" 32 - #include "hw/i386/pc.h" 33 - #include "hw/pci/pci_ids.h" 34 - #include "qapi/error.h" 35 - #include "qemu-common.h" 36 - #include "qemu/main-loop.h" 37 - #include "hw/acpi/tpm.h" 33 + #include "tpm_util.h" 38 34 39 35 #define TPM_TIS_NUM_LOCALITIES 5 /* per spec */ 40 36 #define TPM_TIS_LOCALITY_SHIFT 12 ··· 72 68 TPMSizedBuffer r_buffer; 73 69 } TPMLocality; 74 70 75 - struct TPMState { 71 + typedef struct TPMState { 76 72 ISADevice busdev; 77 73 MemoryRegion mmio; 78 74 79 - QEMUBH *bh; 80 75 uint32_t offset; 81 76 uint8_t buf[TPM_TIS_BUFFER_MAX]; 82 77 ··· 89 84 qemu_irq irq; 90 85 uint32_t irq_num; 91 86 92 - uint8_t locty_number; 93 87 TPMBackendCmd cmd; 94 88 95 - char *backend; 96 89 TPMBackend *be_driver; 97 90 TPMVersion be_tpm_version; 98 - }; 91 + 92 + size_t be_buffer_size; 93 + } TPMState; 99 94 100 95 #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS) 101 96 ··· 222 217 223 218 static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb) 224 219 { 225 - return be32_to_cpu(*(uint32_t *)&sb->buffer[2]); 220 + return tpm_cmd_get_size(sb->buffer); 226 221 } 227 222 228 223 static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string) ··· 411 406 tpm_tis_abort(s, locty); 412 407 } 413 408 414 - static void tpm_tis_receive_bh(void *opaque) 409 + /* 410 + * Callback from the TPM to indicate that the response was received. 411 + */ 412 + static void tpm_tis_request_completed(TPMIf *ti) 415 413 { 416 - TPMState *s = opaque; 414 + TPMState *s = TPM(ti); 417 415 uint8_t locty = s->cmd.locty; 416 + uint8_t l; 417 + 418 + if (s->cmd.selftest_done) { 419 + for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { 420 + s->loc[locty].sts |= TPM_TIS_STS_SELFTEST_DONE; 421 + } 422 + } 418 423 419 424 tpm_tis_sts_set(&s->loc[locty], 420 425 TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); ··· 432 437 TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID); 433 438 } 434 439 435 - static void tpm_tis_request_completed(TPMIf *ti) 436 - { 437 - TPMState *s = TPM(ti); 438 - 439 - bool is_selftest_done = s->cmd.selftest_done; 440 - uint8_t locty = s->cmd.locty; 441 - uint8_t l; 442 - 443 - if (is_selftest_done) { 444 - for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { 445 - s->loc[locty].sts |= TPM_TIS_STS_SELFTEST_DONE; 446 - } 447 - } 448 - 449 - qemu_bh_schedule(s->bh); 450 - } 451 - 452 440 /* 453 441 * Read a byte of response data 454 442 */ ··· 986 974 }, 987 975 }; 988 976 989 - static int tpm_tis_do_startup_tpm(TPMState *s) 977 + static int tpm_tis_do_startup_tpm(TPMState *s, uint32_t buffersize) 990 978 { 991 - return tpm_backend_startup_tpm(s->be_driver); 979 + return tpm_backend_startup_tpm(s->be_driver, buffersize); 992 980 } 993 981 994 - static void tpm_tis_realloc_buffer(TPMSizedBuffer *sb) 982 + static void tpm_tis_realloc_buffer(TPMSizedBuffer *sb, 983 + size_t wanted_size) 995 984 { 996 - size_t wanted_size = 4096; /* Linux tpm.c buffer size */ 997 - 998 985 if (sb->size != wanted_size) { 999 986 sb->buffer = g_realloc(sb->buffer, wanted_size); 1000 987 sb->size = wanted_size; ··· 1004 991 /* 1005 992 * Get the TPMVersion of the backend device being used 1006 993 */ 1007 - TPMVersion tpm_tis_get_tpm_version(Object *obj) 994 + static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti) 1008 995 { 1009 - TPMState *s = TPM(obj); 996 + TPMState *s = TPM(ti); 1010 997 1011 998 if (tpm_backend_had_startup_error(s->be_driver)) { 1012 999 return TPM_VERSION_UNSPEC; ··· 1025 1012 int c; 1026 1013 1027 1014 s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); 1015 + s->be_buffer_size = tpm_backend_get_buffer_size(s->be_driver); 1028 1016 1029 1017 tpm_backend_reset(s->be_driver); 1030 1018 ··· 1051 1039 s->loc[c].state = TPM_TIS_STATE_IDLE; 1052 1040 1053 1041 s->loc[c].w_offset = 0; 1054 - tpm_tis_realloc_buffer(&s->loc[c].w_buffer); 1042 + tpm_tis_realloc_buffer(&s->loc[c].w_buffer, s->be_buffer_size); 1055 1043 s->loc[c].r_offset = 0; 1056 - tpm_tis_realloc_buffer(&s->loc[c].r_buffer); 1044 + tpm_tis_realloc_buffer(&s->loc[c].r_buffer, s->be_buffer_size); 1057 1045 } 1058 1046 1059 - tpm_tis_do_startup_tpm(s); 1047 + tpm_tis_do_startup_tpm(s, 0); 1060 1048 } 1061 1049 1062 1050 static const VMStateDescription vmstate_tpm_tis = { ··· 1066 1054 1067 1055 static Property tpm_tis_properties[] = { 1068 1056 DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ), 1069 - DEFINE_PROP_STRING("tpmdev", TPMState, backend), 1057 + DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver), 1070 1058 DEFINE_PROP_END_OF_LIST(), 1071 1059 }; 1072 1060 ··· 1074 1062 { 1075 1063 TPMState *s = TPM(dev); 1076 1064 1077 - s->be_driver = qemu_find_tpm(s->backend); 1078 - if (!s->be_driver) { 1079 - error_setg(errp, "tpm_tis: backend driver with id %s could not be " 1080 - "found", s->backend); 1065 + if (!tpm_find()) { 1066 + error_setg(errp, "at most one TPM device is permitted"); 1081 1067 return; 1082 1068 } 1083 1069 1084 - s->be_driver->fe_model = TPM_MODEL_TPM_TIS; 1085 - 1086 - if (tpm_backend_init(s->be_driver, s)) { 1087 - error_setg(errp, "tpm_tis: backend driver with id %s could not be " 1088 - "initialized", s->backend); 1070 + if (!s->be_driver) { 1071 + error_setg(errp, "'tpmdev' property is required"); 1089 1072 return; 1090 1073 } 1091 - 1092 1074 if (s->irq_num > 15) { 1093 - error_setg(errp, "tpm_tis: IRQ %d for TPM TIS is outside valid range " 1094 - "of 0 to 15", s->irq_num); 1075 + error_setg(errp, "IRQ %d is outside valid range of 0 to 15", 1076 + s->irq_num); 1095 1077 return; 1096 1078 } 1097 1079 1098 - s->bh = qemu_bh_new(tpm_tis_receive_bh, s); 1099 - 1100 1080 isa_init_irq(&s->busdev, &s->irq, s->irq_num); 1101 1081 1102 1082 memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), ··· 1121 1101 dc->props = tpm_tis_properties; 1122 1102 dc->reset = tpm_tis_reset; 1123 1103 dc->vmsd = &vmstate_tpm_tis; 1104 + tc->model = TPM_MODEL_TPM_TIS; 1105 + tc->get_version = tpm_tis_get_tpm_version; 1124 1106 tc->request_completed = tpm_tis_request_completed; 1125 1107 } 1126 1108 ··· 1139 1121 static void tpm_tis_register(void) 1140 1122 { 1141 1123 type_register_static(&tpm_tis_info); 1142 - tpm_register_model(TPM_MODEL_TPM_TIS); 1143 1124 } 1144 1125 1145 1126 type_init(tpm_tis_register)
+146 -9
hw/tpm/tpm_util.c
··· 20 20 */ 21 21 22 22 #include "qemu/osdep.h" 23 + #include "qemu/error-report.h" 23 24 #include "tpm_util.h" 24 25 #include "tpm_int.h" 25 26 #include "exec/memory.h" 27 + 28 + #define DEBUG_TPM 0 29 + 30 + #define DPRINTF(fmt, ...) do { \ 31 + if (DEBUG_TPM) { \ 32 + fprintf(stderr, "tpm-util:"fmt"\n", ## __VA_ARGS__); \ 33 + } \ 34 + } while (0) 26 35 27 36 /* 28 37 * Write an error message in the given output buffer. ··· 50 59 } 51 60 52 61 /* 53 - * A basic test of a TPM device. We expect a well formatted response header 54 - * (error response is fine) within one second. 62 + * Send request to a TPM device. We expect a response within one second. 55 63 */ 56 - static int tpm_util_test(int fd, 57 - unsigned char *request, 58 - size_t requestlen, 59 - uint16_t *return_tag) 64 + static int tpm_util_request(int fd, 65 + unsigned char *request, 66 + size_t requestlen, 67 + unsigned char *response, 68 + size_t responselen) 60 69 { 61 70 struct tpm_resp_hdr *resp; 62 71 fd_set readfds; ··· 65 74 .tv_sec = 1, 66 75 .tv_usec = 0, 67 76 }; 68 - unsigned char buf[1024]; 69 77 70 78 n = write(fd, request, requestlen); 71 79 if (n < 0) { ··· 84 92 return -errno; 85 93 } 86 94 87 - n = read(fd, &buf, sizeof(buf)); 95 + n = read(fd, response, responselen); 88 96 if (n < sizeof(struct tpm_resp_hdr)) { 89 97 return -EFAULT; 90 98 } 91 99 92 - resp = (struct tpm_resp_hdr *)buf; 100 + resp = (struct tpm_resp_hdr *)response; 93 101 /* check the header */ 94 102 if (be32_to_cpu(resp->len) != n) { 95 103 return -EMSGSIZE; 96 104 } 97 105 106 + return 0; 107 + } 108 + 109 + /* 110 + * A basic test of a TPM device. We expect a well formatted response header 111 + * (error response is fine). 112 + */ 113 + static int tpm_util_test(int fd, 114 + unsigned char *request, 115 + size_t requestlen, 116 + uint16_t *return_tag) 117 + { 118 + struct tpm_resp_hdr *resp; 119 + unsigned char buf[1024]; 120 + ssize_t ret; 121 + 122 + ret = tpm_util_request(fd, request, requestlen, 123 + buf, sizeof(buf)); 124 + if (ret < 0) { 125 + return ret; 126 + } 127 + 128 + resp = (struct tpm_resp_hdr *)buf; 98 129 *return_tag = be16_to_cpu(resp->tag); 99 130 100 131 return 0; ··· 151 182 152 183 return 1; 153 184 } 185 + 186 + int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version, 187 + size_t *buffersize) 188 + { 189 + unsigned char buf[1024]; 190 + int ret; 191 + 192 + switch (tpm_version) { 193 + case TPM_VERSION_1_2: { 194 + const struct tpm_req_get_buffer_size { 195 + struct tpm_req_hdr hdr; 196 + uint32_t capability; 197 + uint32_t len; 198 + uint32_t subcap; 199 + } QEMU_PACKED tpm_get_buffer_size = { 200 + .hdr = { 201 + .tag = cpu_to_be16(TPM_TAG_RQU_COMMAND), 202 + .len = cpu_to_be32(sizeof(tpm_get_buffer_size)), 203 + .ordinal = cpu_to_be32(TPM_ORD_GetCapability), 204 + }, 205 + .capability = cpu_to_be32(TPM_CAP_PROPERTY), 206 + .len = cpu_to_be32(sizeof(uint32_t)), 207 + .subcap = cpu_to_be32(TPM_CAP_PROP_INPUT_BUFFER), 208 + }; 209 + struct tpm_resp_get_buffer_size { 210 + struct tpm_resp_hdr hdr; 211 + uint32_t len; 212 + uint32_t buffersize; 213 + } QEMU_PACKED *tpm_resp = (struct tpm_resp_get_buffer_size *)buf; 214 + 215 + ret = tpm_util_request(tpm_fd, (unsigned char *)&tpm_get_buffer_size, 216 + sizeof(tpm_get_buffer_size), buf, sizeof(buf)); 217 + if (ret < 0) { 218 + return ret; 219 + } 220 + 221 + if (be32_to_cpu(tpm_resp->hdr.len) != sizeof(*tpm_resp) || 222 + be32_to_cpu(tpm_resp->len) != sizeof(uint32_t)) { 223 + DPRINTF("tpm_resp->hdr.len = %u, expected = %zu\n", 224 + be32_to_cpu(tpm_resp->hdr.len), sizeof(*tpm_resp)); 225 + DPRINTF("tpm_resp->len = %u, expected = %zu\n", 226 + be32_to_cpu(tpm_resp->len), sizeof(uint32_t)); 227 + error_report("tpm_util: Got unexpected response to " 228 + "TPM_GetCapability; errcode: 0x%x", 229 + be32_to_cpu(tpm_resp->hdr.errcode)); 230 + return -EFAULT; 231 + } 232 + *buffersize = be32_to_cpu(tpm_resp->buffersize); 233 + break; 234 + } 235 + case TPM_VERSION_2_0: { 236 + const struct tpm2_req_get_buffer_size { 237 + struct tpm_req_hdr hdr; 238 + uint32_t capability; 239 + uint32_t property; 240 + uint32_t count; 241 + } QEMU_PACKED tpm2_get_buffer_size = { 242 + .hdr = { 243 + .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS), 244 + .len = cpu_to_be32(sizeof(tpm2_get_buffer_size)), 245 + .ordinal = cpu_to_be32(TPM2_CC_GetCapability), 246 + }, 247 + .capability = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES), 248 + .property = cpu_to_be32(TPM2_PT_MAX_COMMAND_SIZE), 249 + .count = cpu_to_be32(2), /* also get TPM2_PT_MAX_RESPONSE_SIZE */ 250 + }; 251 + struct tpm2_resp_get_buffer_size { 252 + struct tpm_resp_hdr hdr; 253 + uint8_t more; 254 + uint32_t capability; 255 + uint32_t count; 256 + uint32_t property1; 257 + uint32_t value1; 258 + uint32_t property2; 259 + uint32_t value2; 260 + } QEMU_PACKED *tpm2_resp = (struct tpm2_resp_get_buffer_size *)buf; 261 + 262 + ret = tpm_util_request(tpm_fd, (unsigned char *)&tpm2_get_buffer_size, 263 + sizeof(tpm2_get_buffer_size), buf, sizeof(buf)); 264 + if (ret < 0) { 265 + return ret; 266 + } 267 + 268 + if (be32_to_cpu(tpm2_resp->hdr.len) != sizeof(*tpm2_resp) || 269 + be32_to_cpu(tpm2_resp->count) != 2) { 270 + DPRINTF("tpm2_resp->hdr.len = %u, expected = %zu\n", 271 + be32_to_cpu(tpm2_resp->hdr.len), sizeof(*tpm2_resp)); 272 + DPRINTF("tpm2_resp->len = %u, expected = %u\n", 273 + be32_to_cpu(tpm2_resp->count), 2); 274 + error_report("tpm_util: Got unexpected response to " 275 + "TPM2_GetCapability; errcode: 0x%x", 276 + be32_to_cpu(tpm2_resp->hdr.errcode)); 277 + return -EFAULT; 278 + } 279 + *buffersize = MAX(be32_to_cpu(tpm2_resp->value1), 280 + be32_to_cpu(tpm2_resp->value2)); 281 + break; 282 + } 283 + case TPM_VERSION_UNSPEC: 284 + return -EFAULT; 285 + } 286 + 287 + DPRINTF("buffersize of device: %zu\n", *buffersize); 288 + 289 + return 0; 290 + }
+10 -1
hw/tpm/tpm_util.h
··· 22 22 #ifndef TPM_TPM_UTIL_H 23 23 #define TPM_TPM_UTIL_H 24 24 25 - #include "sysemu/tpm_backend.h" 25 + #include "sysemu/tpm.h" 26 + #include "qemu/bswap.h" 26 27 27 28 void tpm_util_write_fatal_error_response(uint8_t *out, uint32_t out_len); 28 29 29 30 bool tpm_util_is_selftest(const uint8_t *in, uint32_t in_len); 30 31 31 32 int tpm_util_test_tpmdev(int tpm_fd, TPMVersion *tpm_version); 33 + 34 + static inline uint32_t tpm_cmd_get_size(const void *b) 35 + { 36 + return be32_to_cpu(*(const uint32_t *)(b + 2)); 37 + } 38 + 39 + int tpm_util_get_buffer_size(int tpm_fd, TPMVersion tpm_version, 40 + size_t *buffersize); 32 41 33 42 #endif /* TPM_TPM_UTIL_H */
+3
include/hw/qdev-properties.h
··· 17 17 extern const PropertyInfo qdev_prop_size; 18 18 extern const PropertyInfo qdev_prop_string; 19 19 extern const PropertyInfo qdev_prop_chr; 20 + extern const PropertyInfo qdev_prop_tpm; 20 21 extern const PropertyInfo qdev_prop_ptr; 21 22 extern const PropertyInfo qdev_prop_macaddr; 22 23 extern const PropertyInfo qdev_prop_on_off_auto; ··· 186 187 187 188 #define DEFINE_PROP_CHR(_n, _s, _f) \ 188 189 DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharBackend) 190 + #define DEFINE_PROP_TPMBE(_n, _s, _f) \ 191 + DEFINE_PROP(_n, _s, _f, qdev_prop_tpm, TPMBackend *) 189 192 #define DEFINE_PROP_STRING(_n, _s, _f) \ 190 193 DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*) 191 194 #define DEFINE_PROP_NETDEV(_n, _s, _f) \
+36 -12
include/sysemu/tpm.h
··· 12 12 #ifndef QEMU_TPM_H 13 13 #define QEMU_TPM_H 14 14 15 - #include "qemu/option.h" 16 15 #include "qom/object.h" 17 - 18 - typedef struct TPMState TPMState; 16 + #include "qapi-types.h" 19 17 20 18 int tpm_config_parse(QemuOptsList *opts_list, const char *optarg); 21 19 int tpm_init(void); 22 20 void tpm_cleanup(void); 23 21 24 - typedef enum TPMVersion { 22 + typedef enum TPMVersion { 25 23 TPM_VERSION_UNSPEC = 0, 26 24 TPM_VERSION_1_2 = 1, 27 25 TPM_VERSION_2_0 = 2, 28 26 } TPMVersion; 29 27 30 - TPMVersion tpm_tis_get_tpm_version(Object *obj); 28 + #define TYPE_TPM_IF "tpm-if" 29 + #define TPM_IF_CLASS(klass) \ 30 + OBJECT_CLASS_CHECK(TPMIfClass, (klass), TYPE_TPM_IF) 31 + #define TPM_IF_GET_CLASS(obj) \ 32 + OBJECT_GET_CLASS(TPMIfClass, (obj), TYPE_TPM_IF) 33 + #define TPM_IF(obj) \ 34 + INTERFACE_CHECK(TPMIf, (obj), TYPE_TPM_IF) 35 + 36 + typedef struct TPMIf { 37 + Object parent_obj; 38 + } TPMIf; 39 + 40 + typedef struct TPMIfClass { 41 + InterfaceClass parent_class; 42 + 43 + enum TpmModel model; 44 + void (*request_completed)(TPMIf *obj); 45 + enum TPMVersion (*get_version)(TPMIf *obj); 46 + } TPMIfClass; 31 47 32 48 #define TYPE_TPM_TIS "tpm-tis" 33 49 34 - static inline TPMVersion tpm_get_version(void) 50 + #define TPM_IS_TIS(chr) \ 51 + object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS) 52 + 53 + /* returns NULL unless there is exactly one TPM device */ 54 + static inline TPMIf *tpm_find(void) 35 55 { 36 - #ifdef CONFIG_TPM 37 - Object *obj = object_resolve_path_type("", TYPE_TPM_TIS, NULL); 56 + Object *obj = object_resolve_path_type("", TYPE_TPM_IF, NULL); 38 57 39 - if (obj) { 40 - return tpm_tis_get_tpm_version(obj); 58 + return TPM_IF(obj); 59 + } 60 + 61 + static inline TPMVersion tpm_get_version(TPMIf *ti) 62 + { 63 + if (!ti) { 64 + return TPM_VERSION_UNSPEC; 41 65 } 42 - #endif 43 - return TPM_VERSION_UNSPEC; 66 + 67 + return TPM_IF_GET_CLASS(ti)->get_version(ti); 44 68 } 45 69 46 70 #endif /* QEMU_TPM_H */
+27 -23
include/sysemu/tpm_backend.h
··· 43 43 Object parent; 44 44 45 45 /*< protected >*/ 46 + TPMIf *tpmif; 46 47 bool opened; 47 - TPMState *tpm_state; 48 48 GThreadPool *thread_pool; 49 49 bool had_startup_error; 50 + QEMUBH *bh; 50 51 51 52 /* <public> */ 52 53 char *id; 53 - enum TpmModel fe_model; 54 54 55 55 QLIST_ENTRY(TPMBackend) list; 56 56 }; ··· 63 63 /* get a descriptive text of the backend to display to the user */ 64 64 const char *desc; 65 65 66 - TPMBackend *(*create)(QemuOpts *opts, const char *id); 66 + TPMBackend *(*create)(QemuOpts *opts); 67 67 68 - /* start up the TPM on the backend */ 69 - int (*startup_tpm)(TPMBackend *t); 68 + /* start up the TPM on the backend - optional */ 69 + int (*startup_tpm)(TPMBackend *t, size_t buffersize); 70 70 71 + /* optional */ 71 72 void (*reset)(TPMBackend *t); 72 73 73 74 void (*cancel_cmd)(TPMBackend *t); 74 75 76 + /* optional */ 75 77 bool (*get_tpm_established_flag)(TPMBackend *t); 76 78 79 + /* optional */ 77 80 int (*reset_tpm_established_flag)(TPMBackend *t, uint8_t locty); 78 81 79 82 TPMVersion (*get_tpm_version)(TPMBackend *t); 80 83 81 - TpmTypeOptions *(*get_tpm_options)(TPMBackend *t); 84 + size_t (*get_buffer_size)(TPMBackend *t); 82 85 83 - void (*opened)(TPMBackend *s, Error **errp); 86 + TpmTypeOptions *(*get_tpm_options)(TPMBackend *t); 84 87 85 88 void (*handle_request)(TPMBackend *s, TPMBackendCmd *cmd); 86 89 }; ··· 96 99 /** 97 100 * tpm_backend_init: 98 101 * @s: the backend to initialized 99 - * @state: TPMState 102 + * @tpmif: TPM interface 100 103 * @datacb: callback for sending data to frontend 104 + * @errp: a pointer to return the #Error object if an error occurs. 101 105 * 102 106 * Initialize the backend with the given variables. 103 107 * 104 108 * Returns 0 on success. 105 109 */ 106 - int tpm_backend_init(TPMBackend *s, TPMState *state); 110 + int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp); 107 111 108 112 /** 109 113 * tpm_backend_startup_tpm: 110 114 * @s: the backend whose TPM support is to be started 115 + * @buffersize: the buffer size the TPM is supposed to use, 116 + * 0 to leave it as-is 111 117 * 112 118 * Returns 0 on success. 113 119 */ 114 - int tpm_backend_startup_tpm(TPMBackend *s); 120 + int tpm_backend_startup_tpm(TPMBackend *s, size_t buffersize); 115 121 116 122 /** 117 123 * tpm_backend_had_startup_error: ··· 171 177 int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty); 172 178 173 179 /** 174 - * tpm_backend_open: 175 - * @s: the backend to open 176 - * @errp: a pointer to return the #Error object if an error occurs. 177 - * 178 - * This function will open the backend if it is not already open. Calling this 179 - * function on an already opened backend will not result in an error. 180 - */ 181 - void tpm_backend_open(TPMBackend *s, Error **errp); 182 - 183 - /** 184 180 * tpm_backend_get_tpm_version: 185 181 * @s: the backend to call into 186 182 * ··· 191 187 TPMVersion tpm_backend_get_tpm_version(TPMBackend *s); 192 188 193 189 /** 190 + * tpm_backend_get_buffer_size: 191 + * @s: the backend to call into 192 + * 193 + * Get the TPM's buffer size. 194 + * 195 + * Returns buffer size. 196 + */ 197 + size_t tpm_backend_get_buffer_size(TPMBackend *s); 198 + 199 + /** 194 200 * tpm_backend_query_tpm: 195 201 * @s: the backend 196 202 * ··· 200 206 */ 201 207 TPMInfo *tpm_backend_query_tpm(TPMBackend *s); 202 208 203 - TPMBackend *qemu_find_tpm(const char *id); 204 - 205 - void tpm_register_model(enum TpmModel model); 209 + TPMBackend *qemu_find_tpm_be(const char *id); 206 210 207 211 #endif
+11 -23
tpm.c
··· 23 23 static QLIST_HEAD(, TPMBackend) tpm_backends = 24 24 QLIST_HEAD_INITIALIZER(tpm_backends); 25 25 26 - static bool tpm_models[TPM_MODEL__MAX]; 27 - 28 - void tpm_register_model(enum TpmModel model) 29 - { 30 - tpm_models[model] = true; 31 - } 32 - 33 26 static const TPMBackendClass * 34 27 tpm_be_find_by_type(enum TpmType type) 35 28 { ··· 69 62 /* 70 63 * Find the TPM with the given Id 71 64 */ 72 - TPMBackend *qemu_find_tpm(const char *id) 65 + TPMBackend *qemu_find_tpm_be(const char *id) 73 66 { 74 67 TPMBackend *drv; 75 68 ··· 127 120 return 1; 128 121 } 129 122 130 - drv = be->create(opts, id); 123 + drv = be->create(opts); 131 124 if (!drv) { 132 125 return 1; 133 126 } 134 127 135 - tpm_backend_open(drv, &local_err); 136 - if (local_err) { 137 - error_report_err(local_err); 138 - return 1; 139 - } 140 - 128 + drv->id = g_strdup(id); 141 129 QLIST_INSERT_HEAD(&tpm_backends, drv, list); 142 130 143 131 return 0; ··· 200 188 TPMInfoList *info, *head = NULL, *cur_item = NULL; 201 189 202 190 QLIST_FOREACH(drv, &tpm_backends, list) { 203 - if (!tpm_models[drv->fe_model]) { 191 + if (!drv->tpmif) { 204 192 continue; 205 193 } 194 + 206 195 info = g_new0(TPMInfoList, 1); 207 196 info->value = tpm_backend_query_tpm(drv); 208 197 ··· 240 229 241 230 return head; 242 231 } 243 - 244 232 TpmModelList *qmp_query_tpm_models(Error **errp) 245 233 { 246 - unsigned int i = 0; 247 234 TpmModelList *head = NULL, *prev = NULL, *cur_item; 235 + GSList *e, *l = object_class_get_list(TYPE_TPM_IF, false); 248 236 249 - for (i = 0; i < TPM_MODEL__MAX; i++) { 250 - if (!tpm_models[i]) { 251 - continue; 252 - } 237 + for (e = l; e; e = e->next) { 238 + TPMIfClass *c = TPM_IF_CLASS(e->data); 239 + 253 240 cur_item = g_new0(TpmModelList, 1); 254 - cur_item->value = i; 241 + cur_item->value = c->model; 255 242 256 243 if (prev) { 257 244 prev->next = cur_item; ··· 261 248 } 262 249 prev = cur_item; 263 250 } 251 + g_slist_free(l); 264 252 265 253 return head; 266 254 }