cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

tpm_spapr.c (12415B)


      1/*
      2 * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
      3 *
      4 * PAPR Virtual TPM
      5 *
      6 * Copyright (c) 2015, 2017, 2019 IBM Corporation.
      7 *
      8 * Authors:
      9 *    Stefan Berger <stefanb@linux.vnet.ibm.com>
     10 *
     11 * This code is licensed under the GPL version 2 or later. See the
     12 * COPYING file in the top-level directory.
     13 *
     14 */
     15
     16#include "qemu/osdep.h"
     17#include "qemu/error-report.h"
     18#include "qapi/error.h"
     19#include "hw/qdev-properties.h"
     20#include "migration/vmstate.h"
     21
     22#include "sysemu/tpm_backend.h"
     23#include "sysemu/tpm_util.h"
     24#include "tpm_prop.h"
     25
     26#include "hw/ppc/spapr.h"
     27#include "hw/ppc/spapr_vio.h"
     28#include "trace.h"
     29#include "qom/object.h"
     30
     31#define DEBUG_SPAPR 0
     32
     33typedef struct SpaprTpmState SpaprTpmState;
     34DECLARE_INSTANCE_CHECKER(SpaprTpmState, VIO_SPAPR_VTPM,
     35                         TYPE_TPM_SPAPR)
     36
     37typedef struct TpmCrq {
     38    uint8_t valid;  /* 0x80: cmd; 0xc0: init crq */
     39                    /* 0x81-0x83: CRQ message response */
     40    uint8_t msg;    /* see below */
     41    uint16_t len;   /* len of TPM request; len of TPM response */
     42    uint32_t data;  /* rtce_dma_handle when sending TPM request */
     43    uint64_t reserved;
     44} TpmCrq;
     45
     46#define SPAPR_VTPM_VALID_INIT_CRQ_COMMAND  0xC0
     47#define SPAPR_VTPM_VALID_COMMAND           0x80
     48#define SPAPR_VTPM_MSG_RESULT              0x80
     49
     50/* msg types for valid = SPAPR_VTPM_VALID_INIT_CRQ */
     51#define SPAPR_VTPM_INIT_CRQ_RESULT           0x1
     52#define SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT  0x2
     53
     54/* msg types for valid = SPAPR_VTPM_VALID_CMD */
     55#define SPAPR_VTPM_GET_VERSION               0x1
     56#define SPAPR_VTPM_TPM_COMMAND               0x2
     57#define SPAPR_VTPM_GET_RTCE_BUFFER_SIZE      0x3
     58#define SPAPR_VTPM_PREPARE_TO_SUSPEND        0x4
     59
     60/* response error messages */
     61#define SPAPR_VTPM_VTPM_ERROR                0xff
     62
     63/* error codes */
     64#define SPAPR_VTPM_ERR_COPY_IN_FAILED        0x3
     65#define SPAPR_VTPM_ERR_COPY_OUT_FAILED       0x4
     66
     67#define TPM_SPAPR_BUFFER_MAX                 4096
     68
     69struct SpaprTpmState {
     70    SpaprVioDevice vdev;
     71
     72    TpmCrq crq; /* track single TPM command */
     73
     74    uint8_t state;
     75#define SPAPR_VTPM_STATE_NONE         0
     76#define SPAPR_VTPM_STATE_EXECUTION    1
     77#define SPAPR_VTPM_STATE_COMPLETION   2
     78
     79    unsigned char *buffer;
     80
     81    uint32_t numbytes; /* number of bytes to deliver on resume */
     82
     83    TPMBackendCmd cmd;
     84
     85    TPMBackend *be_driver;
     86    TPMVersion be_tpm_version;
     87
     88    size_t be_buffer_size;
     89};
     90
     91/*
     92 * Send a request to the TPM.
     93 */
     94static void tpm_spapr_tpm_send(SpaprTpmState *s)
     95{
     96    tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM");
     97
     98    s->state = SPAPR_VTPM_STATE_EXECUTION;
     99    s->cmd = (TPMBackendCmd) {
    100        .locty = 0,
    101        .in = s->buffer,
    102        .in_len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size),
    103        .out = s->buffer,
    104        .out_len = s->be_buffer_size,
    105    };
    106
    107    tpm_backend_deliver_request(s->be_driver, &s->cmd);
    108}
    109
    110static int tpm_spapr_process_cmd(SpaprTpmState *s, uint64_t dataptr)
    111{
    112    long rc;
    113
    114    /* a max. of be_buffer_size bytes can be transported */
    115    rc = spapr_vio_dma_read(&s->vdev, dataptr,
    116                            s->buffer, s->be_buffer_size);
    117    if (rc) {
    118        error_report("tpm_spapr_got_payload: DMA read failure");
    119    }
    120    /* let vTPM handle any malformed request */
    121    tpm_spapr_tpm_send(s);
    122
    123    return rc;
    124}
    125
    126static inline int spapr_tpm_send_crq(struct SpaprVioDevice *dev, TpmCrq *crq)
    127{
    128    return spapr_vio_send_crq(dev, (uint8_t *)crq);
    129}
    130
    131static int tpm_spapr_do_crq(struct SpaprVioDevice *dev, uint8_t *crq_data)
    132{
    133    SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
    134    TpmCrq local_crq;
    135    TpmCrq *crq = &s->crq; /* requests only */
    136    int rc;
    137    uint8_t valid = crq_data[0];
    138    uint8_t msg = crq_data[1];
    139
    140    trace_tpm_spapr_do_crq(valid, msg);
    141
    142    switch (valid) {
    143    case SPAPR_VTPM_VALID_INIT_CRQ_COMMAND: /* Init command/response */
    144
    145        /* Respond to initialization request */
    146        switch (msg) {
    147        case SPAPR_VTPM_INIT_CRQ_RESULT:
    148            trace_tpm_spapr_do_crq_crq_result();
    149            memset(&local_crq, 0, sizeof(local_crq));
    150            local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND;
    151            local_crq.msg = SPAPR_VTPM_INIT_CRQ_RESULT;
    152            spapr_tpm_send_crq(dev, &local_crq);
    153            break;
    154
    155        case SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT:
    156            trace_tpm_spapr_do_crq_crq_complete_result();
    157            memset(&local_crq, 0, sizeof(local_crq));
    158            local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND;
    159            local_crq.msg = SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT;
    160            spapr_tpm_send_crq(dev, &local_crq);
    161            break;
    162        }
    163
    164        break;
    165    case SPAPR_VTPM_VALID_COMMAND: /* Payloads */
    166        switch (msg) {
    167        case SPAPR_VTPM_TPM_COMMAND:
    168            trace_tpm_spapr_do_crq_tpm_command();
    169            if (s->state == SPAPR_VTPM_STATE_EXECUTION) {
    170                return H_BUSY;
    171            }
    172            memcpy(crq, crq_data, sizeof(*crq));
    173
    174            rc = tpm_spapr_process_cmd(s, be32_to_cpu(crq->data));
    175
    176            if (rc == H_SUCCESS) {
    177                crq->valid = be16_to_cpu(0);
    178            } else {
    179                local_crq.valid = SPAPR_VTPM_MSG_RESULT;
    180                local_crq.msg = SPAPR_VTPM_VTPM_ERROR;
    181                local_crq.len = cpu_to_be16(0);
    182                local_crq.data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_IN_FAILED);
    183                spapr_tpm_send_crq(dev, &local_crq);
    184            }
    185            break;
    186
    187        case SPAPR_VTPM_GET_RTCE_BUFFER_SIZE:
    188            trace_tpm_spapr_do_crq_tpm_get_rtce_buffer_size(s->be_buffer_size);
    189            local_crq.valid = SPAPR_VTPM_VALID_COMMAND;
    190            local_crq.msg = SPAPR_VTPM_GET_RTCE_BUFFER_SIZE |
    191                            SPAPR_VTPM_MSG_RESULT;
    192            local_crq.len = cpu_to_be16(s->be_buffer_size);
    193            spapr_tpm_send_crq(dev, &local_crq);
    194            break;
    195
    196        case SPAPR_VTPM_GET_VERSION:
    197            local_crq.valid = SPAPR_VTPM_VALID_COMMAND;
    198            local_crq.msg = SPAPR_VTPM_GET_VERSION | SPAPR_VTPM_MSG_RESULT;
    199            local_crq.len = cpu_to_be16(0);
    200            switch (s->be_tpm_version) {
    201            case TPM_VERSION_1_2:
    202                local_crq.data = cpu_to_be32(1);
    203                break;
    204            case TPM_VERSION_2_0:
    205                local_crq.data = cpu_to_be32(2);
    206                break;
    207            default:
    208                g_assert_not_reached();
    209                break;
    210            }
    211            trace_tpm_spapr_do_crq_get_version(be32_to_cpu(local_crq.data));
    212            spapr_tpm_send_crq(dev, &local_crq);
    213            break;
    214
    215        case SPAPR_VTPM_PREPARE_TO_SUSPEND:
    216            trace_tpm_spapr_do_crq_prepare_to_suspend();
    217            local_crq.valid = SPAPR_VTPM_VALID_COMMAND;
    218            local_crq.msg = SPAPR_VTPM_PREPARE_TO_SUSPEND |
    219                            SPAPR_VTPM_MSG_RESULT;
    220            spapr_tpm_send_crq(dev, &local_crq);
    221            break;
    222
    223        default:
    224            trace_tpm_spapr_do_crq_unknown_msg_type(crq->msg);
    225        }
    226        break;
    227    default:
    228        trace_tpm_spapr_do_crq_unknown_crq(valid, msg);
    229    };
    230
    231    return H_SUCCESS;
    232}
    233
    234static void tpm_spapr_request_completed(TPMIf *ti, int ret)
    235{
    236    SpaprTpmState *s = VIO_SPAPR_VTPM(ti);
    237    TpmCrq *crq = &s->crq;
    238    uint32_t len;
    239    int rc;
    240
    241    s->state = SPAPR_VTPM_STATE_COMPLETION;
    242
    243    /* a max. of be_buffer_size bytes can be transported */
    244    len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size);
    245
    246    if (runstate_check(RUN_STATE_FINISH_MIGRATE)) {
    247        trace_tpm_spapr_caught_response(len);
    248        /* defer delivery of response until .post_load */
    249        s->numbytes = len;
    250        return;
    251    }
    252
    253    rc = spapr_vio_dma_write(&s->vdev, be32_to_cpu(crq->data),
    254                             s->buffer, len);
    255
    256    tpm_util_show_buffer(s->buffer, len, "From TPM");
    257
    258    crq->valid = SPAPR_VTPM_MSG_RESULT;
    259    if (rc == H_SUCCESS) {
    260        crq->msg = SPAPR_VTPM_TPM_COMMAND | SPAPR_VTPM_MSG_RESULT;
    261        crq->len = cpu_to_be16(len);
    262    } else {
    263        error_report("%s: DMA write failure", __func__);
    264        crq->msg = SPAPR_VTPM_VTPM_ERROR;
    265        crq->len = cpu_to_be16(0);
    266        crq->data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_OUT_FAILED);
    267    }
    268
    269    rc = spapr_tpm_send_crq(&s->vdev, crq);
    270    if (rc) {
    271        error_report("%s: Error sending response", __func__);
    272    }
    273}
    274
    275static int tpm_spapr_do_startup_tpm(SpaprTpmState *s, size_t buffersize)
    276{
    277    return tpm_backend_startup_tpm(s->be_driver, buffersize);
    278}
    279
    280static const char *tpm_spapr_get_dt_compatible(SpaprVioDevice *dev)
    281{
    282    SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
    283
    284    switch (s->be_tpm_version) {
    285    case TPM_VERSION_1_2:
    286        return "IBM,vtpm";
    287    case TPM_VERSION_2_0:
    288        return "IBM,vtpm20";
    289    default:
    290        g_assert_not_reached();
    291    }
    292}
    293
    294static void tpm_spapr_reset(SpaprVioDevice *dev)
    295{
    296    SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
    297
    298    s->state = SPAPR_VTPM_STATE_NONE;
    299    s->numbytes = 0;
    300
    301    s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
    302
    303    s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),
    304                            TPM_SPAPR_BUFFER_MAX);
    305
    306    tpm_backend_reset(s->be_driver);
    307
    308    if (tpm_spapr_do_startup_tpm(s, s->be_buffer_size) < 0) {
    309        exit(1);
    310    }
    311}
    312
    313static enum TPMVersion tpm_spapr_get_version(TPMIf *ti)
    314{
    315    SpaprTpmState *s = VIO_SPAPR_VTPM(ti);
    316
    317    if (tpm_backend_had_startup_error(s->be_driver)) {
    318        return TPM_VERSION_UNSPEC;
    319    }
    320
    321    return tpm_backend_get_tpm_version(s->be_driver);
    322}
    323
    324/* persistent state handling */
    325
    326static int tpm_spapr_pre_save(void *opaque)
    327{
    328    SpaprTpmState *s = opaque;
    329
    330    tpm_backend_finish_sync(s->be_driver);
    331    /*
    332     * we cannot deliver the results to the VM since DMA would touch VM memory
    333     */
    334
    335    return 0;
    336}
    337
    338static int tpm_spapr_post_load(void *opaque, int version_id)
    339{
    340    SpaprTpmState *s = opaque;
    341
    342    if (s->numbytes) {
    343        trace_tpm_spapr_post_load();
    344        /* deliver the results to the VM via DMA */
    345        tpm_spapr_request_completed(TPM_IF(s), 0);
    346        s->numbytes = 0;
    347    }
    348
    349    return 0;
    350}
    351
    352static const VMStateDescription vmstate_spapr_vtpm = {
    353    .name = "tpm-spapr",
    354    .pre_save = tpm_spapr_pre_save,
    355    .post_load = tpm_spapr_post_load,
    356    .fields = (VMStateField[]) {
    357        VMSTATE_SPAPR_VIO(vdev, SpaprTpmState),
    358
    359        VMSTATE_UINT8(state, SpaprTpmState),
    360        VMSTATE_UINT32(numbytes, SpaprTpmState),
    361        VMSTATE_VBUFFER_UINT32(buffer, SpaprTpmState, 0, NULL, numbytes),
    362        /* remember DMA address */
    363        VMSTATE_UINT32(crq.data, SpaprTpmState),
    364        VMSTATE_END_OF_LIST(),
    365    }
    366};
    367
    368static Property tpm_spapr_properties[] = {
    369    DEFINE_SPAPR_PROPERTIES(SpaprTpmState, vdev),
    370    DEFINE_PROP_TPMBE("tpmdev", SpaprTpmState, be_driver),
    371    DEFINE_PROP_END_OF_LIST(),
    372};
    373
    374static void tpm_spapr_realizefn(SpaprVioDevice *dev, Error **errp)
    375{
    376    SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
    377
    378    if (!tpm_find()) {
    379        error_setg(errp, "at most one TPM device is permitted");
    380        return;
    381    }
    382
    383    dev->crq.SendFunc = tpm_spapr_do_crq;
    384
    385    if (!s->be_driver) {
    386        error_setg(errp, "'tpmdev' property is required");
    387        return;
    388    }
    389    s->buffer = g_malloc(TPM_SPAPR_BUFFER_MAX);
    390}
    391
    392static void tpm_spapr_class_init(ObjectClass *klass, void *data)
    393{
    394    DeviceClass *dc = DEVICE_CLASS(klass);
    395    SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
    396    TPMIfClass *tc = TPM_IF_CLASS(klass);
    397
    398    k->realize = tpm_spapr_realizefn;
    399    k->reset = tpm_spapr_reset;
    400    k->dt_name = "vtpm";
    401    k->dt_type = "IBM,vtpm";
    402    k->get_dt_compatible = tpm_spapr_get_dt_compatible;
    403    k->signal_mask = 0x00000001;
    404    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    405    device_class_set_props(dc, tpm_spapr_properties);
    406    k->rtce_window_size = 0x10000000;
    407    dc->vmsd = &vmstate_spapr_vtpm;
    408
    409    tc->model = TPM_MODEL_TPM_SPAPR;
    410    tc->get_version = tpm_spapr_get_version;
    411    tc->request_completed = tpm_spapr_request_completed;
    412}
    413
    414static const TypeInfo tpm_spapr_info = {
    415    .name          = TYPE_TPM_SPAPR,
    416    .parent        = TYPE_VIO_SPAPR_DEVICE,
    417    .instance_size = sizeof(SpaprTpmState),
    418    .class_init    = tpm_spapr_class_init,
    419    .interfaces = (InterfaceInfo[]) {
    420        { TYPE_TPM_IF },
    421        { }
    422    }
    423};
    424
    425static void tpm_spapr_register_types(void)
    426{
    427    type_register_static(&tpm_spapr_info);
    428}
    429
    430type_init(tpm_spapr_register_types)