Commit 411ad781 authored by Peter Maydell's avatar Peter Maydell
Browse files

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: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 38d1b31e 683c4b77
Loading
Loading
Loading
Loading
+35 −57
Original line number Diff line number Diff line
@@ -17,16 +17,25 @@
#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
#include "sysemu/tpm.h"
#include "hw/tpm/tpm_int.h"
#include "qemu/thread.h"
#include "qemu/main-loop.h"

static void tpm_backend_request_completed_bh(void *opaque)
{
    TPMBackend *s = TPM_BACKEND(opaque);
    TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif);

    tic->request_completed(s->tpmif);
}

static void tpm_backend_worker_thread(gpointer data, gpointer user_data)
{
    TPMBackend *s = TPM_BACKEND(user_data);
    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);

    assert(k->handle_request != NULL);
    k->handle_request(s, (TPMBackendCmd *)data);

    qemu_bh_schedule(s->bh);
}

static void tpm_backend_thread_end(TPMBackend *s)
@@ -44,15 +53,22 @@ enum TpmType tpm_backend_get_type(TPMBackend *s)
    return k->type;
}

int tpm_backend_init(TPMBackend *s, TPMState *state)
int tpm_backend_init(TPMBackend *s, TPMIf *tpmif, Error **errp)
{
    s->tpm_state = state;
    if (s->tpmif) {
        error_setg(errp, "TPM backend '%s' is already initialized", s->id);
        return -1;
    }

    s->tpmif = tpmif;
    object_ref(OBJECT(tpmif));

    s->had_startup_error = false;

    return 0;
}

int tpm_backend_startup_tpm(TPMBackend *s)
int tpm_backend_startup_tpm(TPMBackend *s, size_t buffersize)
{
    int res = 0;
    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
@@ -63,7 +79,7 @@ int tpm_backend_startup_tpm(TPMBackend *s)
    s->thread_pool = g_thread_pool_new(tpm_backend_worker_thread, s, 1, TRUE,
                                       NULL);

    res = k->startup_tpm ? k->startup_tpm(s) : 0;
    res = k->startup_tpm ? k->startup_tpm(s, buffersize) : 0;

    s->had_startup_error = (res != 0);

@@ -97,8 +113,6 @@ void tpm_backend_cancel_cmd(TPMBackend *s)
{
    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);

    assert(k->cancel_cmd);

    k->cancel_cmd(s);
}

@@ -122,80 +136,44 @@ TPMVersion tpm_backend_get_tpm_version(TPMBackend *s)
{
    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);

    assert(k->get_tpm_version);

    return k->get_tpm_version(s);
}

TPMInfo *tpm_backend_query_tpm(TPMBackend *s)
size_t tpm_backend_get_buffer_size(TPMBackend *s)
{
    TPMInfo *info = g_new0(TPMInfo, 1);
    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);

    info->id = g_strdup(s->id);
    info->model = s->fe_model;
    if (k->get_tpm_options) {
        info->options = k->get_tpm_options(s);
    }

    return info;
}

static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
{
    TPMBackend *s = TPM_BACKEND(obj);

    return s->opened;
}

void tpm_backend_open(TPMBackend *s, Error **errp)
{
    object_property_set_bool(OBJECT(s), true, "opened", errp);
    return k->get_buffer_size(s);
}

static void tpm_backend_prop_set_opened(Object *obj, bool value, Error **errp)
TPMInfo *tpm_backend_query_tpm(TPMBackend *s)
{
    TPMBackend *s = TPM_BACKEND(obj);
    TPMInfo *info = g_new0(TPMInfo, 1);
    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
    Error *local_err = NULL;
    TPMIfClass *tic = TPM_IF_GET_CLASS(s->tpmif);

    if (value == s->opened) {
        return;
    }

    if (!value && s->opened) {
        error_setg(errp, QERR_PERMISSION_DENIED);
        return;
    }

    if (k->opened) {
        k->opened(s, &local_err);
        if (local_err) {
            error_propagate(errp, local_err);
            return;
        }
    }
    info->id = g_strdup(s->id);
    info->model = tic->model;
    info->options = k->get_tpm_options(s);

    s->opened = true;
    return info;
}

static void tpm_backend_instance_init(Object *obj)
{
    TPMBackend *s = TPM_BACKEND(obj);

    object_property_add_bool(obj, "opened",
                             tpm_backend_prop_get_opened,
                             tpm_backend_prop_set_opened,
                             NULL);
    s->fe_model = -1;
    s->bh = qemu_bh_new(tpm_backend_request_completed_bh, s);
}

static void tpm_backend_instance_finalize(Object *obj)
{
    TPMBackend *s = TPM_BACKEND(obj);

    object_unref(OBJECT(s->tpmif));
    g_free(s->id);
    tpm_backend_thread_end(s);
    qemu_bh_delete(s->bh);
}

static const TypeInfo tpm_backend_info = {
+64 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "net/hub.h"
#include "qapi/visitor.h"
#include "chardev/char-fe.h"
#include "sysemu/tpm_backend.h"
#include "sysemu/iothread.h"

static void get_pointer(Object *obj, Visitor *v, Property *prop,
@@ -236,6 +237,69 @@ const PropertyInfo qdev_prop_chr = {
    .release = release_chr,
};

/* --- character device --- */

static void get_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
                    Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    TPMBackend **be = qdev_get_prop_ptr(dev, opaque);
    char *p;

    p = g_strdup(*be ? (*be)->id : "");
    visit_type_str(v, name, &p, errp);
    g_free(p);
}

static void set_tpm(Object *obj, Visitor *v, const char *name, void *opaque,
                    Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Error *local_err = NULL;
    Property *prop = opaque;
    TPMBackend *s, **be = qdev_get_prop_ptr(dev, prop);
    char *str;

    if (dev->realized) {
        qdev_prop_set_after_realize(dev, name, errp);
        return;
    }

    visit_type_str(v, name, &str, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }

    s = qemu_find_tpm_be(str);
    if (s == NULL) {
        error_setg(errp, "Property '%s.%s' can't find value '%s'",
                   object_get_typename(obj), prop->name, str);
    } else if (tpm_backend_init(s, TPM_IF(obj), errp) == 0) {
        *be = s; /* weak reference, avoid cyclic ref */
    }
    g_free(str);
}

static void release_tpm(Object *obj, const char *name, void *opaque)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
    TPMBackend **be = qdev_get_prop_ptr(dev, prop);

    if (*be) {
        tpm_backend_reset(*be);
    }
}

const PropertyInfo qdev_prop_tpm = {
    .name  = "str",
    .description = "ID of a tpm to use as a backend",
    .get   = get_tpm,
    .set   = set_tpm,
    .release = release_tpm,
};

/* --- netdev device --- */
static void get_netdev(Object *obj, Visitor *v, const char *name,
                       void *opaque, Error **errp)
+9 −5
Original line number Diff line number Diff line
@@ -208,7 +208,7 @@ static void acpi_get_misc_info(AcpiMiscInfo *info)
    }

    info->has_hpet = hpet_find();
    info->tpm_version = tpm_get_version();
    info->tpm_version = tpm_get_version(tpm_find());
    info->pvpanic_port = pvpanic_port();
    info->applesmc_io_base = applesmc_port();
}
@@ -2038,7 +2038,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
        }
    }

    if (misc->tpm_version != TPM_VERSION_UNSPEC) {
    if (TPM_IS_TIS(tpm_find())) {
        aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE,
                   TPM_TIS_ADDR_SIZE, AML_READ_WRITE));
    }
@@ -2204,7 +2204,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
            /* Scan all PCI buses. Generate tables to support hotplug. */
            build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en);

            if (misc->tpm_version != TPM_VERSION_UNSPEC) {
            if (TPM_IS_TIS(tpm_find())) {
                dev = aml_device("ISA.TPM");
                aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0C31")));
                aml_append(dev, aml_name_decl("_STA", aml_int(0xF)));
@@ -2281,8 +2281,12 @@ build_tpm2(GArray *table_data, BIOSLinker *linker)
    tpm2_ptr = acpi_data_push(table_data, sizeof *tpm2_ptr);

    tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT);
    if (TPM_IS_TIS(tpm_find())) {
        tpm2_ptr->control_area_address = cpu_to_le64(0);
        tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO);
    } else {
        g_warn_if_reached();
    }

    build_header(linker, table_data,
                 (void *)tpm2_ptr, "TPM2", sizeof(*tpm2_ptr), 4, NULL, NULL);
+84 −14
Original line number Diff line number Diff line
@@ -186,7 +186,6 @@ static int tpm_emulator_set_locality(TPMEmulator *tpm_emu, uint8_t locty_number,
static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd)
{
    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
    TPMIfClass *tic = TPM_IF_GET_CLASS(tb->tpm_state);
    Error *err = NULL;

    DPRINTF("processing TPM command");
@@ -201,7 +200,6 @@ static void tpm_emulator_handle_request(TPMBackend *tb, TPMBackendCmd *cmd)
        goto error;
    }

    tic->request_completed(TPM_IF(tb->tpm_state));
    return;

error:
@@ -234,13 +232,14 @@ static int tpm_emulator_check_caps(TPMEmulator *tpm_emu)
    switch (tpm_emu->tpm_version) {
    case TPM_VERSION_1_2:
        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
               PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD;
               PTM_CAP_SET_LOCALITY | PTM_CAP_SET_DATAFD | PTM_CAP_STOP |
               PTM_CAP_SET_BUFFERSIZE;
        tpm = "1.2";
        break;
    case TPM_VERSION_2_0:
        caps = PTM_CAP_INIT | PTM_CAP_SHUTDOWN | PTM_CAP_GET_TPMESTABLISHED |
               PTM_CAP_SET_LOCALITY | PTM_CAP_RESET_TPMESTABLISHED |
               PTM_CAP_SET_DATAFD;
               PTM_CAP_SET_DATAFD | PTM_CAP_STOP | PTM_CAP_SET_BUFFERSIZE;
        tpm = "2";
        break;
    case TPM_VERSION_UNSPEC:
@@ -257,12 +256,76 @@ static int tpm_emulator_check_caps(TPMEmulator *tpm_emu)
    return 0;
}

static int tpm_emulator_startup_tpm(TPMBackend *tb)
static int tpm_emulator_stop_tpm(TPMBackend *tb)
{
    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
    ptm_res res;

    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_STOP, &res, 0, sizeof(res)) < 0) {
        error_report("tpm-emulator: Could not stop TPM: %s",
                     strerror(errno));
        return -1;
    }

    res = be32_to_cpu(res);
    if (res) {
        error_report("tpm-emulator: TPM result for CMD_STOP: 0x%x", res);
        return -1;
    }

    return 0;
}

static int tpm_emulator_set_buffer_size(TPMBackend *tb,
                                        size_t wanted_size,
                                        size_t *actual_size)
{
    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
    ptm_setbuffersize psbs;

    if (tpm_emulator_stop_tpm(tb) < 0) {
        return -1;
    }

    psbs.u.req.buffersize = cpu_to_be32(wanted_size);

    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_SET_BUFFERSIZE, &psbs,
                             sizeof(psbs.u.req), sizeof(psbs.u.resp)) < 0) {
        error_report("tpm-emulator: Could not set buffer size: %s",
                     strerror(errno));
        return -1;
    }

    psbs.u.resp.tpm_result = be32_to_cpu(psbs.u.resp.tpm_result);
    if (psbs.u.resp.tpm_result != 0) {
        error_report("tpm-emulator: TPM result for set buffer size : 0x%x",
                     psbs.u.resp.tpm_result);
        return -1;
    }

    if (actual_size) {
        *actual_size = be32_to_cpu(psbs.u.resp.buffersize);
    }

    DPRINTF("buffer size: %u, min: %u, max: %u\n",
            be32_to_cpu(psbs.u.resp.buffersize),
            be32_to_cpu(psbs.u.resp.minsize),
            be32_to_cpu(psbs.u.resp.maxsize));

    return 0;
}

static int tpm_emulator_startup_tpm(TPMBackend *tb, size_t buffersize)
{
    TPMEmulator *tpm_emu = TPM_EMULATOR(tb);
    ptm_init init;
    ptm_res res;

    if (buffersize != 0 &&
        tpm_emulator_set_buffer_size(tb, buffersize, NULL) < 0) {
        goto err_exit;
    }

    DPRINTF("%s", __func__);
    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_INIT, &init, sizeof(init),
                             sizeof(init)) < 0) {
@@ -340,6 +403,7 @@ static void tpm_emulator_cancel_cmd(TPMBackend *tb)
        return;
    }

    /* FIXME: make the function non-blocking, or it may block a VCPU */
    if (tpm_emulator_ctrlcmd(tpm_emu, CMD_CANCEL_TPM_CMD, &res, 0,
                             sizeof(res)) < 0) {
        error_report("tpm-emulator: Could not cancel command: %s",
@@ -357,6 +421,17 @@ static TPMVersion tpm_emulator_get_tpm_version(TPMBackend *tb)
    return tpm_emu->tpm_version;
}

static size_t tpm_emulator_get_buffer_size(TPMBackend *tb)
{
    size_t actual_size;

    if (tpm_emulator_set_buffer_size(tb, 0, &actual_size) < 0) {
        return 4096;
    }

    return actual_size;
}

static int tpm_emulator_block_migration(TPMEmulator *tpm_emu)
{
    Error *err = NULL;
@@ -465,22 +540,16 @@ err:
    return -1;
}

static TPMBackend *tpm_emulator_create(QemuOpts *opts, const char *id)
static TPMBackend *tpm_emulator_create(QemuOpts *opts)
{
    TPMBackend *tb = TPM_BACKEND(object_new(TYPE_TPM_EMULATOR));

    tb->id = g_strdup(id);

    if (tpm_emulator_handle_device_opts(TPM_EMULATOR(tb), opts)) {
        goto err_exit;
        object_unref(OBJECT(tb));
        return NULL;
    }

    return tb;

err_exit:
    object_unref(OBJECT(tb));

    return NULL;
}

static TpmTypeOptions *tpm_emulator_get_tpm_options(TPMBackend *tb)
@@ -563,6 +632,7 @@ static void tpm_emulator_class_init(ObjectClass *klass, void *data)
    tbc->get_tpm_established_flag = tpm_emulator_get_tpm_established_flag;
    tbc->reset_tpm_established_flag = tpm_emulator_reset_tpm_established_flag;
    tbc->get_tpm_version = tpm_emulator_get_tpm_version;
    tbc->get_buffer_size = tpm_emulator_get_buffer_size;
    tbc->get_tpm_options = tpm_emulator_get_tpm_options;

    tbc->handle_request = tpm_emulator_handle_request;
+10 −21
Original line number Diff line number Diff line
@@ -13,26 +13,6 @@
#define TPM_TPM_INT_H

#include "qemu/osdep.h"
#include "qom/object.h"

#define TYPE_TPM_IF "tpm-if"
#define TPM_IF_CLASS(klass) \
    OBJECT_CLASS_CHECK(TPMIfClass, (klass), TYPE_TPM_IF)
#define TPM_IF_GET_CLASS(obj) \
    OBJECT_GET_CLASS(TPMIfClass, (obj), TYPE_TPM_IF)
#define TPM_IF(obj) \
    INTERFACE_CHECK(TPMIf, (obj), TYPE_TPM_IF)

typedef struct TPMIf {
    Object parent_obj;
} TPMIf;

typedef struct TPMIfClass {
    InterfaceClass parent_class;

    /* run in thread pool by backend */
    void (*request_completed)(TPMIf *obj);
} TPMIfClass;

#define TPM_STANDARD_CMDLINE_OPTS \
    { \
@@ -65,11 +45,20 @@ struct tpm_resp_hdr {

#define TPM_ORD_ContinueSelfTest  0x53
#define TPM_ORD_GetTicks          0xf1
#define TPM_ORD_GetCapability     0x65

#define TPM_CAP_PROPERTY          0x05

#define TPM_CAP_PROP_INPUT_BUFFER 0x124

/* TPM2 defines */
#define TPM2_ST_NO_SESSIONS       0x8001

#define TPM2_CC_ReadClock         0x00000181
#define TPM2_CC_GetCapability     0x0000017a

#define TPM2_CAP_TPM_PROPERTIES   0x6

#define TPM2_PT_MAX_COMMAND_SIZE  0x11e

#endif /* TPM_TPM_INT_H */
Loading