qemu

Форк
0
/
tpm_tis_i2c.c 
571 строка · 17.3 Кб
1
/*
2
 * tpm_tis_i2c.c - QEMU's TPM TIS I2C Device
3
 *
4
 * Copyright (c) 2023 IBM Corporation
5
 *
6
 * Authors:
7
 *   Ninad Palsule <ninad@linux.ibm.com>
8
 *
9
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10
 * See the COPYING file in the top-level directory.
11
 *
12
 * TPM I2C implementation follows TCG TPM I2c Interface specification,
13
 * Family 2.0, Level 00, Revision 1.00
14
 *
15
 * TPM TIS for TPM 2 implementation following TCG PC Client Platform
16
 * TPM Profile (PTP) Specification, Family 2.0, Revision 00.43
17
 *
18
 */
19

20
#include "qemu/osdep.h"
21
#include "hw/i2c/i2c.h"
22
#include "hw/sysbus.h"
23
#include "hw/acpi/tpm.h"
24
#include "migration/vmstate.h"
25
#include "tpm_prop.h"
26
#include "qemu/log.h"
27
#include "trace.h"
28
#include "tpm_tis.h"
29

30
/* Operations */
31
#define OP_SEND   1
32
#define OP_RECV   2
33

34
/* Is locality valid */
35
#define TPM_TIS_I2C_IS_VALID_LOCTY(x)   TPM_TIS_IS_VALID_LOCTY(x)
36

37
typedef struct TPMStateI2C {
38
    /*< private >*/
39
    I2CSlave    parent_obj;
40

41
    uint8_t     offset;       /* offset into data[] */
42
    uint8_t     operation;    /* OP_SEND & OP_RECV */
43
    uint8_t     data[5];      /* Data */
44

45
    /* i2c registers */
46
    uint8_t     loc_sel;      /* Current locality */
47
    uint8_t     csum_enable;  /* Is checksum enabled */
48

49
    /* Derived from the above */
50
    const char *reg_name;     /* Register name */
51
    uint32_t    tis_addr;     /* Converted tis address including locty */
52

53
    /*< public >*/
54
    TPMState    state; /* not a QOM object */
55

56
} TPMStateI2C;
57

58
DECLARE_INSTANCE_CHECKER(TPMStateI2C, TPM_TIS_I2C,
59
                         TYPE_TPM_TIS_I2C)
60

61
/* Prototype */
62
static inline void tpm_tis_i2c_to_tis_reg(TPMStateI2C *i2cst, uint8_t i2c_reg);
63

64
/* Register map */
65
typedef struct regMap {
66
    uint8_t   i2c_reg;    /* I2C register */
67
    uint16_t  tis_reg;    /* TIS register */
68
    const char *reg_name; /* Register name */
69
} I2CRegMap;
70

71
/*
72
 * The register values in the common code is different than the latest
73
 * register numbers as per the spec hence add the conversion map
74
 */
75
static const I2CRegMap tpm_tis_reg_map[] = {
76
    /*
77
     * These registers are sent to TIS layer. The register with UNKNOWN
78
     * mapping are not sent to TIS layer and handled in I2c layer.
79
     * NOTE: Adding frequently used registers at the start
80
     */
81
    { TPM_I2C_REG_DATA_FIFO,        TPM_TIS_REG_DATA_FIFO,       "FIFO",      },
82
    { TPM_I2C_REG_STS,              TPM_TIS_REG_STS,             "STS",       },
83
    { TPM_I2C_REG_DATA_CSUM_GET,    TPM_I2C_REG_UNKNOWN,         "CSUM_GET",  },
84
    { TPM_I2C_REG_LOC_SEL,          TPM_I2C_REG_UNKNOWN,         "LOC_SEL",   },
85
    { TPM_I2C_REG_ACCESS,           TPM_TIS_REG_ACCESS,          "ACCESS",    },
86
    { TPM_I2C_REG_INT_ENABLE,       TPM_TIS_REG_INT_ENABLE,     "INTR_ENABLE",},
87
    { TPM_I2C_REG_INT_CAPABILITY,   TPM_I2C_REG_UNKNOWN,         "INTR_CAP",  },
88
    { TPM_I2C_REG_INTF_CAPABILITY,  TPM_TIS_REG_INTF_CAPABILITY, "INTF_CAP",  },
89
    { TPM_I2C_REG_DID_VID,          TPM_TIS_REG_DID_VID,         "DID_VID",   },
90
    { TPM_I2C_REG_RID,              TPM_TIS_REG_RID,             "RID",       },
91
    { TPM_I2C_REG_I2C_DEV_ADDRESS,  TPM_I2C_REG_UNKNOWN,        "DEV_ADDRESS",},
92
    { TPM_I2C_REG_DATA_CSUM_ENABLE, TPM_I2C_REG_UNKNOWN,        "CSUM_ENABLE",},
93
};
94

95
static int tpm_tis_i2c_pre_save(void *opaque)
96
{
97
    TPMStateI2C *i2cst = opaque;
98

99
    return tpm_tis_pre_save(&i2cst->state);
100
}
101

102
static int tpm_tis_i2c_post_load(void *opaque, int version_id)
103
{
104
    TPMStateI2C *i2cst = opaque;
105

106
    if (i2cst->offset >= 1) {
107
        tpm_tis_i2c_to_tis_reg(i2cst, i2cst->data[0]);
108
    }
109

110
    return 0;
111
}
112

113
static const VMStateDescription vmstate_tpm_tis_i2c = {
114
    .name = "tpm-tis-i2c",
115
    .version_id = 0,
116
    .pre_save  = tpm_tis_i2c_pre_save,
117
    .post_load  = tpm_tis_i2c_post_load,
118
    .fields = (const VMStateField[]) {
119
        VMSTATE_BUFFER(state.buffer, TPMStateI2C),
120
        VMSTATE_UINT16(state.rw_offset, TPMStateI2C),
121
        VMSTATE_UINT8(state.active_locty, TPMStateI2C),
122
        VMSTATE_UINT8(state.aborting_locty, TPMStateI2C),
123
        VMSTATE_UINT8(state.next_locty, TPMStateI2C),
124

125
        VMSTATE_STRUCT_ARRAY(state.loc, TPMStateI2C, TPM_TIS_NUM_LOCALITIES, 0,
126
                             vmstate_locty, TPMLocality),
127

128
        /* i2c specifics */
129
        VMSTATE_UINT8(offset, TPMStateI2C),
130
        VMSTATE_UINT8(operation, TPMStateI2C),
131
        VMSTATE_BUFFER(data, TPMStateI2C),
132
        VMSTATE_UINT8(loc_sel, TPMStateI2C),
133
        VMSTATE_UINT8(csum_enable, TPMStateI2C),
134

135
        VMSTATE_END_OF_LIST()
136
    }
137
};
138

139
/*
140
 * Set data value. The i2cst->offset is not updated as called in
141
 * the read path.
142
 */
143
static void tpm_tis_i2c_set_data(TPMStateI2C *i2cst, uint32_t data)
144
{
145
    i2cst->data[1] = data;
146
    i2cst->data[2] = data >> 8;
147
    i2cst->data[3] = data >> 16;
148
    i2cst->data[4] = data >> 24;
149
}
150
/*
151
 * Generate interface capability based on what is returned by TIS and what is
152
 * expected by I2C. Save the capability in the data array overwriting the TIS
153
 * capability.
154
 */
155
static uint32_t tpm_tis_i2c_interface_capability(TPMStateI2C *i2cst,
156
                                                 uint32_t tis_cap)
157
{
158
    uint32_t i2c_cap;
159

160
    /* Now generate i2c capability */
161
    i2c_cap = (TPM_I2C_CAP_INTERFACE_TYPE |
162
               TPM_I2C_CAP_INTERFACE_VER  |
163
               TPM_I2C_CAP_TPM2_FAMILY    |
164
               TPM_I2C_CAP_LOCALITY_CAP   |
165
               TPM_I2C_CAP_BUS_SPEED      |
166
               TPM_I2C_CAP_DEV_ADDR_CHANGE);
167

168
    /* Now check the TIS and set some capabilities */
169

170
    /* Static burst count set */
171
    if (tis_cap & TPM_TIS_CAP_BURST_COUNT_STATIC) {
172
        i2c_cap |= TPM_I2C_CAP_BURST_COUNT_STATIC;
173
    }
174

175
    return i2c_cap;
176
}
177

178
/* Convert I2C register to TIS address and returns the name of the register */
179
static inline void tpm_tis_i2c_to_tis_reg(TPMStateI2C *i2cst, uint8_t i2c_reg)
180
{
181
    const I2CRegMap *reg_map;
182
    int i;
183

184
    i2cst->tis_addr = 0xffffffff;
185

186
    /* Special case for the STS register. */
187
    if (i2c_reg >= TPM_I2C_REG_STS && i2c_reg <= TPM_I2C_REG_STS + 3) {
188
        i2c_reg = TPM_I2C_REG_STS;
189
    }
190

191
    for (i = 0; i < ARRAY_SIZE(tpm_tis_reg_map); i++) {
192
        reg_map = &tpm_tis_reg_map[i];
193
        if (reg_map->i2c_reg == i2c_reg) {
194
            i2cst->reg_name = reg_map->reg_name;
195
            i2cst->tis_addr = reg_map->tis_reg;
196

197
            /* Include the locality in the address. */
198
            assert(TPM_TIS_I2C_IS_VALID_LOCTY(i2cst->loc_sel));
199
            i2cst->tis_addr += (i2cst->loc_sel << TPM_TIS_LOCALITY_SHIFT);
200
            break;
201
        }
202
    }
203
}
204

205
/* Clear some fields from the structure. */
206
static inline void tpm_tis_i2c_clear_data(TPMStateI2C *i2cst)
207
{
208
    /* Clear operation and offset */
209
    i2cst->operation = 0;
210
    i2cst->offset = 0;
211
    i2cst->tis_addr = 0xffffffff;
212
    i2cst->reg_name = NULL;
213
    memset(i2cst->data, 0, sizeof(i2cst->data));
214

215
    return;
216
}
217

218
/* Send data to TPM */
219
static inline void tpm_tis_i2c_tpm_send(TPMStateI2C *i2cst)
220
{
221
    uint32_t data;
222
    size_t offset = 0;
223
    uint32_t sz = 4;
224

225
    if ((i2cst->operation == OP_SEND) && (i2cst->offset > 1)) {
226

227
        switch (i2cst->data[0]) {
228
        case TPM_I2C_REG_DATA_CSUM_ENABLE:
229
            /*
230
             * Checksum is not handled by TIS code hence we will consume the
231
             * register here.
232
             */
233
            i2cst->csum_enable = i2cst->data[1] & TPM_DATA_CSUM_ENABLED;
234
            break;
235
        case TPM_I2C_REG_DATA_FIFO:
236
            /* Handled in the main i2c_send function */
237
            break;
238
        case TPM_I2C_REG_LOC_SEL:
239
            /*
240
             * This register is not handled by TIS so save the locality
241
             * locally
242
             */
243
            if (TPM_TIS_I2C_IS_VALID_LOCTY(i2cst->data[1])) {
244
                i2cst->loc_sel = i2cst->data[1];
245
            }
246
            break;
247
        default:
248
            /* We handle non-FIFO here */
249

250
            /* Index 0 is a register. Convert byte stream to uint32_t */
251
            data = i2cst->data[1];
252
            data |= i2cst->data[2] << 8;
253
            data |= i2cst->data[3] << 16;
254
            data |= i2cst->data[4] << 24;
255

256
            /* Add register specific masking */
257
            switch (i2cst->data[0]) {
258
            case TPM_I2C_REG_INT_ENABLE:
259
                data &= TPM_I2C_INT_ENABLE_MASK;
260
                break;
261
            case TPM_I2C_REG_STS ... TPM_I2C_REG_STS + 3:
262
                /*
263
                 * STS register has 4 bytes data.
264
                 * As per the specs following writes must be allowed.
265
                 *  - From base address 1 to 4 bytes are allowed.
266
                 *  - Single byte write to first or last byte must
267
                 *    be allowed.
268
                 */
269
                offset = i2cst->data[0] - TPM_I2C_REG_STS;
270
                if (offset > 0) {
271
                    sz = 1;
272
                }
273
                data &= (TPM_I2C_STS_WRITE_MASK >> (offset * 8));
274
                break;
275
            }
276

277
            tpm_tis_write_data(&i2cst->state, i2cst->tis_addr + offset, data,
278
                               sz);
279
            break;
280
        }
281

282
        tpm_tis_i2c_clear_data(i2cst);
283
    }
284

285
    return;
286
}
287

288
/* Callback from TPM to indicate that response is copied */
289
static void tpm_tis_i2c_request_completed(TPMIf *ti, int ret)
290
{
291
    TPMStateI2C *i2cst = TPM_TIS_I2C(ti);
292
    TPMState *s = &i2cst->state;
293

294
    /* Inform the common code. */
295
    tpm_tis_request_completed(s, ret);
296
}
297

298
static enum TPMVersion tpm_tis_i2c_get_tpm_version(TPMIf *ti)
299
{
300
    TPMStateI2C *i2cst = TPM_TIS_I2C(ti);
301
    TPMState *s = &i2cst->state;
302

303
    return tpm_tis_get_tpm_version(s);
304
}
305

306
static int tpm_tis_i2c_event(I2CSlave *i2c, enum i2c_event event)
307
{
308
    TPMStateI2C *i2cst = TPM_TIS_I2C(i2c);
309
    int ret = 0;
310

311
    switch (event) {
312
    case I2C_START_RECV:
313
        trace_tpm_tis_i2c_event("START_RECV");
314
        break;
315
    case I2C_START_SEND:
316
        trace_tpm_tis_i2c_event("START_SEND");
317
        tpm_tis_i2c_clear_data(i2cst);
318
        break;
319
    case I2C_FINISH:
320
        trace_tpm_tis_i2c_event("FINISH");
321
        if (i2cst->operation == OP_SEND) {
322
            tpm_tis_i2c_tpm_send(i2cst);
323
        } else {
324
            tpm_tis_i2c_clear_data(i2cst);
325
        }
326
        break;
327
    default:
328
        break;
329
    }
330

331
    return ret;
332
}
333

334
/*
335
 * If data is for FIFO then it is received from tpm_tis_common buffer
336
 * otherwise it will be handled using single call to common code and
337
 * cached in the local buffer.
338
 */
339
static uint8_t tpm_tis_i2c_recv(I2CSlave *i2c)
340
{
341
    int          ret = 0;
342
    uint32_t     data_read;
343
    TPMStateI2C *i2cst = TPM_TIS_I2C(i2c);
344
    TPMState    *s = &i2cst->state;
345
    uint16_t     i2c_reg = i2cst->data[0];
346
    size_t       offset;
347

348
    if (i2cst->operation == OP_RECV) {
349

350
        /* Do not cache FIFO data. */
351
        if (i2cst->data[0] == TPM_I2C_REG_DATA_FIFO) {
352
            data_read = tpm_tis_read_data(s, i2cst->tis_addr, 1);
353
            ret = (data_read & 0xff);
354
        } else if (i2cst->offset < sizeof(i2cst->data)) {
355
            ret = i2cst->data[i2cst->offset++];
356
        }
357

358
    } else if ((i2cst->operation == OP_SEND) && (i2cst->offset < 2)) {
359
        /* First receive call after send */
360

361
        i2cst->operation = OP_RECV;
362

363
        switch (i2c_reg) {
364
        case TPM_I2C_REG_LOC_SEL:
365
            /* Location selection register is managed by i2c */
366
            tpm_tis_i2c_set_data(i2cst, i2cst->loc_sel);
367
            break;
368
        case TPM_I2C_REG_DATA_FIFO:
369
            /* FIFO data is directly read from TPM TIS */
370
            data_read = tpm_tis_read_data(s, i2cst->tis_addr, 1);
371
            tpm_tis_i2c_set_data(i2cst, (data_read & 0xff));
372
            break;
373
        case TPM_I2C_REG_DATA_CSUM_ENABLE:
374
            tpm_tis_i2c_set_data(i2cst, i2cst->csum_enable);
375
            break;
376
        case TPM_I2C_REG_INT_CAPABILITY:
377
            /*
378
             * Interrupt is not supported in the linux kernel hence we cannot
379
             * test this model with interrupts.
380
             */
381
            tpm_tis_i2c_set_data(i2cst, TPM_I2C_INT_ENABLE_MASK);
382
            break;
383
        case TPM_I2C_REG_DATA_CSUM_GET:
384
            /*
385
             * Checksum registers are not supported by common code hence
386
             * call a common code to get the checksum.
387
             */
388
            data_read = tpm_tis_get_checksum(s);
389

390
            /* Save the byte stream in data field */
391
            tpm_tis_i2c_set_data(i2cst, data_read);
392
            break;
393
        default:
394
            data_read = tpm_tis_read_data(s, i2cst->tis_addr, 4);
395

396
            switch (i2c_reg) {
397
            case TPM_I2C_REG_INTF_CAPABILITY:
398
                /* Prepare the capabilities as per I2C interface */
399
                data_read = tpm_tis_i2c_interface_capability(i2cst,
400
                                                             data_read);
401
                break;
402
            case TPM_I2C_REG_STS ... TPM_I2C_REG_STS + 3:
403
                offset = i2c_reg - TPM_I2C_REG_STS;
404
                /*
405
                 * As per specs, STS bit 31:26 are reserved and must
406
                 * be set to 0
407
                 */
408
                data_read &= TPM_I2C_STS_READ_MASK;
409
                /*
410
                 * STS register has 4 bytes data.
411
                 * As per the specs following reads must be allowed.
412
                 *  - From base address 1 to 4 bytes are allowed.
413
                 *  - Last byte must be allowed to read as a single byte
414
                 *  - Second and third byte must be allowed to read as two
415
                 *    two bytes.
416
                 */
417
                data_read >>= (offset * 8);
418
                break;
419
            }
420

421
            /* Save byte stream in data[] */
422
            tpm_tis_i2c_set_data(i2cst, data_read);
423
            break;
424
        }
425

426
        /* Return first byte with this call */
427
        i2cst->offset = 1; /* keep the register value intact for debug */
428
        ret = i2cst->data[i2cst->offset++];
429
    } else {
430
        i2cst->operation = OP_RECV;
431
    }
432

433
    trace_tpm_tis_i2c_recv(ret);
434

435
    return ret;
436
}
437

438
/*
439
 * Send function only remembers data in the buffer and then calls
440
 * TPM TIS common code during FINISH event.
441
 */
442
static int tpm_tis_i2c_send(I2CSlave *i2c, uint8_t data)
443
{
444
    TPMStateI2C *i2cst = TPM_TIS_I2C(i2c);
445

446
    /* Reject non-supported registers. */
447
    if (i2cst->offset == 0) {
448
        /* Convert I2C register to TIS register */
449
        tpm_tis_i2c_to_tis_reg(i2cst, data);
450
        if (i2cst->tis_addr == 0xffffffff) {
451
            return 0xffffffff;
452
        }
453

454
        trace_tpm_tis_i2c_send_reg(i2cst->reg_name, data);
455

456
        /* We do not support device address change */
457
        if (data == TPM_I2C_REG_I2C_DEV_ADDRESS) {
458
            qemu_log_mask(LOG_UNIMP, "%s: Device address change "
459
                          "is not supported.\n", __func__);
460
            return 0xffffffff;
461
        }
462
    } else {
463
        trace_tpm_tis_i2c_send(data);
464
    }
465

466
    if (i2cst->offset < sizeof(i2cst->data)) {
467
        i2cst->operation = OP_SEND;
468

469
        /*
470
         * In two cases, we save values in the local buffer.
471
         * 1) The first value is always a register.
472
         * 2) In case of non-FIFO multibyte registers, TIS expects full
473
         *    register value hence I2C layer cache the register value and send
474
         *    to TIS during FINISH event.
475
         */
476
        if ((i2cst->offset == 0) ||
477
            (i2cst->data[0] != TPM_I2C_REG_DATA_FIFO)) {
478
            i2cst->data[i2cst->offset++] = data;
479
        } else {
480
            /*
481
             * The TIS can process FIFO data one byte at a time hence the FIFO
482
             * data is sent to TIS directly.
483
             */
484
            tpm_tis_write_data(&i2cst->state, i2cst->tis_addr, data, 1);
485
        }
486

487
        return 0;
488
    }
489

490
    /* Return non-zero to indicate NAK */
491
    return 1;
492
}
493

494
static Property tpm_tis_i2c_properties[] = {
495
    DEFINE_PROP_TPMBE("tpmdev", TPMStateI2C, state.be_driver),
496
    DEFINE_PROP_END_OF_LIST(),
497
};
498

499
static void tpm_tis_i2c_realizefn(DeviceState *dev, Error **errp)
500
{
501
    TPMStateI2C *i2cst = TPM_TIS_I2C(dev);
502
    TPMState *s = &i2cst->state;
503

504
    if (!tpm_find()) {
505
        error_setg(errp, "at most one TPM device is permitted");
506
        return;
507
    }
508

509
    /*
510
     * Get the backend pointer. It is not initialized properly during
511
     * device_class_set_props
512
     */
513
    s->be_driver = qemu_find_tpm_be("tpm0");
514

515
    if (!s->be_driver) {
516
        error_setg(errp, "'tpmdev' property is required");
517
        return;
518
    }
519
}
520

521
static void tpm_tis_i2c_reset(DeviceState *dev)
522
{
523
    TPMStateI2C *i2cst = TPM_TIS_I2C(dev);
524
    TPMState *s = &i2cst->state;
525

526
    tpm_tis_i2c_clear_data(i2cst);
527

528
    i2cst->csum_enable = 0;
529
    i2cst->loc_sel = 0x00;
530

531
    return tpm_tis_reset(s);
532
}
533

534
static void tpm_tis_i2c_class_init(ObjectClass *klass, void *data)
535
{
536
    DeviceClass *dc = DEVICE_CLASS(klass);
537
    I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
538
    TPMIfClass *tc = TPM_IF_CLASS(klass);
539

540
    dc->realize = tpm_tis_i2c_realizefn;
541
    dc->reset = tpm_tis_i2c_reset;
542
    dc->vmsd = &vmstate_tpm_tis_i2c;
543
    device_class_set_props(dc, tpm_tis_i2c_properties);
544
    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
545

546
    k->event = tpm_tis_i2c_event;
547
    k->recv = tpm_tis_i2c_recv;
548
    k->send = tpm_tis_i2c_send;
549

550
    tc->model = TPM_MODEL_TPM_TIS;
551
    tc->request_completed = tpm_tis_i2c_request_completed;
552
    tc->get_version = tpm_tis_i2c_get_tpm_version;
553
}
554

555
static const TypeInfo tpm_tis_i2c_info = {
556
    .name          = TYPE_TPM_TIS_I2C,
557
    .parent        = TYPE_I2C_SLAVE,
558
    .instance_size = sizeof(TPMStateI2C),
559
    .class_init    = tpm_tis_i2c_class_init,
560
        .interfaces = (InterfaceInfo[]) {
561
        { TYPE_TPM_IF },
562
        { }
563
    }
564
};
565

566
static void tpm_tis_i2c_register_types(void)
567
{
568
    type_register_static(&tpm_tis_i2c_info);
569
}
570

571
type_init(tpm_tis_i2c_register_types)
572

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.