qemu

Форк
0
/
tpm_tis_common.c 
891 строка · 26.6 Кб
1
/*
2
 * tpm_tis_common.c - QEMU's TPM TIS interface emulator
3
 * device agnostic functions
4
 *
5
 * Copyright (C) 2006,2010-2013 IBM Corporation
6
 *
7
 * Authors:
8
 *  Stefan Berger <stefanb@us.ibm.com>
9
 *  David Safford <safford@us.ibm.com>
10
 *
11
 * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at>
12
 *
13
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
14
 * See the COPYING file in the top-level directory.
15
 *
16
 * Implementation of the TIS interface according to specs found at
17
 * http://www.trustedcomputinggroup.org. This implementation currently
18
 * supports version 1.3, 21 March 2013
19
 * In the developers menu choose the PC Client section then find the TIS
20
 * specification.
21
 *
22
 * TPM TIS for TPM 2 implementation following TCG PC Client Platform
23
 * TPM Profile (PTP) Specification, Family 2.0, Revision 00.43
24
 */
25
#include "qemu/osdep.h"
26
#include "hw/irq.h"
27
#include "hw/isa/isa.h"
28
#include "qapi/error.h"
29
#include "qemu/bswap.h"
30
#include "qemu/crc-ccitt.h"
31
#include "qemu/module.h"
32

33
#include "hw/acpi/tpm.h"
34
#include "hw/pci/pci_ids.h"
35
#include "hw/qdev-properties.h"
36
#include "migration/vmstate.h"
37
#include "sysemu/tpm_backend.h"
38
#include "sysemu/tpm_util.h"
39
#include "tpm_ppi.h"
40
#include "trace.h"
41

42
#include "tpm_tis.h"
43

44
#define DEBUG_TIS 0
45

46
/* local prototypes */
47

48
static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
49
                                  unsigned size);
50

51
/* utility functions */
52

53
static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
54
{
55
    uint8_t locty;
56

57
    locty = (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
58
    assert(TPM_TIS_IS_VALID_LOCTY(locty));
59

60
    return locty;
61
}
62

63

64
/*
65
 * Set the given flags in the STS register by clearing the register but
66
 * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting
67
 * the new flags.
68
 *
69
 * The SELFTEST_DONE flag is acquired from the backend that determines it by
70
 * peeking into TPM commands.
71
 *
72
 * A VM suspend/resume will preserve the flag by storing it into the VM
73
 * device state, but the backend will not remember it when QEMU is started
74
 * again. Therefore, we cache the flag here. Once set, it will not be unset
75
 * except by a reset.
76
 */
77
static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags)
78
{
79
    l->sts &= TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK;
80
    l->sts |= flags;
81
}
82

83
/*
84
 * Send a request to the TPM.
85
 */
86
static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
87
{
88
    tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM");
89

90
    /*
91
     * rw_offset serves as length indicator for length of data;
92
     * it's reset when the response comes back
93
     */
94
    s->loc[locty].state = TPM_TIS_STATE_EXECUTION;
95

96
    s->cmd = (TPMBackendCmd) {
97
        .locty = locty,
98
        .in = s->buffer,
99
        .in_len = s->rw_offset,
100
        .out = s->buffer,
101
        .out_len = s->be_buffer_size,
102
    };
103

104
    tpm_backend_deliver_request(s->be_driver, &s->cmd);
105
}
106

107
/* raise an interrupt if allowed */
108
static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask)
109
{
110
    if (!TPM_TIS_IS_VALID_LOCTY(locty)) {
111
        return;
112
    }
113

114
    if ((s->loc[locty].inte & TPM_TIS_INT_ENABLED) &&
115
        (s->loc[locty].inte & irqmask)) {
116
        trace_tpm_tis_raise_irq(irqmask);
117
        qemu_irq_raise(s->irq);
118
        s->loc[locty].ints |= irqmask;
119
    }
120
}
121

122
static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty)
123
{
124
    uint8_t l;
125

126
    for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
127
        if (l == locty) {
128
            continue;
129
        }
130
        if ((s->loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) {
131
            return 1;
132
        }
133
    }
134

135
    return 0;
136
}
137

138
static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
139
{
140
    bool change = (s->active_locty != new_active_locty);
141
    bool is_seize;
142
    uint8_t mask;
143

144
    if (change && TPM_TIS_IS_VALID_LOCTY(s->active_locty)) {
145
        is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) &&
146
                   s->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE;
147

148
        if (is_seize) {
149
            mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY);
150
        } else {
151
            mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY|
152
                     TPM_TIS_ACCESS_REQUEST_USE);
153
        }
154
        /* reset flags on the old active locality */
155
        s->loc[s->active_locty].access &= mask;
156

157
        if (is_seize) {
158
            s->loc[s->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED;
159
        }
160
    }
161

162
    s->active_locty = new_active_locty;
163

164
    trace_tpm_tis_new_active_locality(s->active_locty);
165

166
    if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) {
167
        /* set flags on the new active locality */
168
        s->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY;
169
        s->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE |
170
                                               TPM_TIS_ACCESS_SEIZE);
171
    }
172

173
    if (change) {
174
        tpm_tis_raise_irq(s, s->active_locty, TPM_TIS_INT_LOCALITY_CHANGED);
175
    }
176
}
177

178
/* abort -- this function switches the locality */
179
static void tpm_tis_abort(TPMState *s)
180
{
181
    s->rw_offset = 0;
182

183
    trace_tpm_tis_abort(s->next_locty);
184

185
    /*
186
     * Need to react differently depending on who's aborting now and
187
     * which locality will become active afterwards.
188
     */
189
    if (s->aborting_locty == s->next_locty) {
190
        s->loc[s->aborting_locty].state = TPM_TIS_STATE_READY;
191
        tpm_tis_sts_set(&s->loc[s->aborting_locty],
192
                        TPM_TIS_STS_COMMAND_READY);
193
        tpm_tis_raise_irq(s, s->aborting_locty, TPM_TIS_INT_COMMAND_READY);
194
    }
195

196
    /* locality after abort is another one than the current one */
197
    tpm_tis_new_active_locality(s, s->next_locty);
198

199
    s->next_locty = TPM_TIS_NO_LOCALITY;
200
    /* nobody's aborting a command anymore */
201
    s->aborting_locty = TPM_TIS_NO_LOCALITY;
202
}
203

204
/* prepare aborting current command */
205
static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
206
{
207
    uint8_t busy_locty;
208

209
    assert(TPM_TIS_IS_VALID_LOCTY(newlocty));
210

211
    s->aborting_locty = locty; /* may also be TPM_TIS_NO_LOCALITY */
212
    s->next_locty = newlocty;  /* locality after successful abort */
213

214
    /*
215
     * only abort a command using an interrupt if currently executing
216
     * a command AND if there's a valid connection to the vTPM.
217
     */
218
    for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) {
219
        if (s->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) {
220
            /*
221
             * request the backend to cancel. Some backends may not
222
             * support it
223
             */
224
            tpm_backend_cancel_cmd(s->be_driver);
225
            return;
226
        }
227
    }
228

229
    tpm_tis_abort(s);
230
}
231

232
/*
233
 * Callback from the TPM to indicate that the response was received.
234
 */
235
void tpm_tis_request_completed(TPMState *s, int ret)
236
{
237
    uint8_t locty = s->cmd.locty;
238
    uint8_t l;
239

240
    assert(TPM_TIS_IS_VALID_LOCTY(locty));
241

242
    if (s->cmd.selftest_done) {
243
        for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
244
            s->loc[l].sts |= TPM_TIS_STS_SELFTEST_DONE;
245
        }
246
    }
247

248
    /* FIXME: report error if ret != 0 */
249
    tpm_tis_sts_set(&s->loc[locty],
250
                    TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
251
    s->loc[locty].state = TPM_TIS_STATE_COMPLETION;
252
    s->rw_offset = 0;
253

254
    tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM");
255

256
    if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) {
257
        tpm_tis_abort(s);
258
    }
259

260
    tpm_tis_raise_irq(s, locty,
261
                      TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
262
}
263

264
/*
265
 * Read a byte of response data
266
 */
267
static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
268
{
269
    uint32_t ret = TPM_TIS_NO_DATA_BYTE;
270
    uint16_t len;
271

272
    if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
273
        len = MIN(tpm_cmd_get_size(&s->buffer),
274
                  s->be_buffer_size);
275

276
        ret = s->buffer[s->rw_offset++];
277
        if (s->rw_offset >= len) {
278
            /* got last byte */
279
            tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID);
280
            tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
281
        }
282
        trace_tpm_tis_data_read(ret, s->rw_offset - 1);
283
    }
284

285
    return ret;
286
}
287

288
#ifdef DEBUG_TIS
289
static void tpm_tis_dump_state(TPMState *s, hwaddr addr)
290
{
291
    static const unsigned regs[] = {
292
        TPM_TIS_REG_ACCESS,
293
        TPM_TIS_REG_INT_ENABLE,
294
        TPM_TIS_REG_INT_VECTOR,
295
        TPM_TIS_REG_INT_STATUS,
296
        TPM_TIS_REG_INTF_CAPABILITY,
297
        TPM_TIS_REG_STS,
298
        TPM_TIS_REG_DID_VID,
299
        TPM_TIS_REG_RID,
300
        0xfff};
301
    int idx;
302
    uint8_t locty = tpm_tis_locality_from_addr(addr);
303
    hwaddr base = addr & ~0xfff;
304

305
    printf("tpm_tis: active locality      : %d\n"
306
           "tpm_tis: state of locality %d : %d\n"
307
           "tpm_tis: register dump:\n",
308
           s->active_locty,
309
           locty, s->loc[locty].state);
310

311
    for (idx = 0; regs[idx] != 0xfff; idx++) {
312
        printf("tpm_tis: 0x%04x : 0x%08x\n", regs[idx],
313
               (int)tpm_tis_mmio_read(s, base + regs[idx], 4));
314
    }
315

316
    printf("tpm_tis: r/w offset    : %d\n"
317
           "tpm_tis: result buffer : ",
318
           s->rw_offset);
319
    for (idx = 0;
320
         idx < MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size);
321
         idx++) {
322
        printf("%c%02x%s",
323
               s->rw_offset == idx ? '>' : ' ',
324
               s->buffer[idx],
325
               ((idx & 0xf) == 0xf) ? "\ntpm_tis:                 " : "");
326
    }
327
    printf("\n");
328
}
329
#endif
330

331
/*
332
 * Read a register of the TIS interface
333
 * See specs pages 33-63 for description of the registers
334
 */
335
static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
336
                                  unsigned size)
337
{
338
    TPMState *s = opaque;
339
    uint16_t offset = addr & 0xffc;
340
    uint8_t shift = (addr & 0x3) * 8;
341
    uint32_t val = 0xffffffff;
342
    uint8_t locty = tpm_tis_locality_from_addr(addr);
343
    uint32_t avail;
344
    uint8_t v;
345

346
    if (tpm_backend_had_startup_error(s->be_driver)) {
347
        return 0;
348
    }
349

350
    switch (offset) {
351
    case TPM_TIS_REG_ACCESS:
352
        /* never show the SEIZE flag even though we use it internally */
353
        val = s->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE;
354
        /* the pending flag is always calculated */
355
        if (tpm_tis_check_request_use_except(s, locty)) {
356
            val |= TPM_TIS_ACCESS_PENDING_REQUEST;
357
        }
358
        val |= !tpm_backend_get_tpm_established_flag(s->be_driver);
359
        break;
360
    case TPM_TIS_REG_INT_ENABLE:
361
        val = s->loc[locty].inte;
362
        break;
363
    case TPM_TIS_REG_INT_VECTOR:
364
        val = s->irq_num;
365
        break;
366
    case TPM_TIS_REG_INT_STATUS:
367
        val = s->loc[locty].ints;
368
        break;
369
    case TPM_TIS_REG_INTF_CAPABILITY:
370
        switch (s->be_tpm_version) {
371
        case TPM_VERSION_UNSPEC:
372
            val = 0;
373
            break;
374
        case TPM_VERSION_1_2:
375
            val = TPM_TIS_CAPABILITIES_SUPPORTED1_3;
376
            break;
377
        case TPM_VERSION_2_0:
378
            val = TPM_TIS_CAPABILITIES_SUPPORTED2_0;
379
            break;
380
        }
381
        break;
382
    case TPM_TIS_REG_STS:
383
        if (s->active_locty == locty) {
384
            if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
385
                val = TPM_TIS_BURST_COUNT(
386
                       MIN(tpm_cmd_get_size(&s->buffer),
387
                           s->be_buffer_size)
388
                       - s->rw_offset) | s->loc[locty].sts;
389
            } else {
390
                avail = s->be_buffer_size - s->rw_offset;
391
                /*
392
                 * byte-sized reads should not return 0x00 for 0x100
393
                 * available bytes.
394
                 */
395
                if (size == 1 && avail > 0xff) {
396
                    avail = 0xff;
397
                }
398
                val = TPM_TIS_BURST_COUNT(avail) | s->loc[locty].sts;
399
            }
400
        }
401
        break;
402
    case TPM_TIS_REG_DATA_FIFO:
403
    case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
404
        if (s->active_locty == locty) {
405
            if (size > 4 - (addr & 0x3)) {
406
                /* prevent access beyond FIFO */
407
                size = 4 - (addr & 0x3);
408
            }
409
            val = 0;
410
            shift = 0;
411
            while (size > 0) {
412
                switch (s->loc[locty].state) {
413
                case TPM_TIS_STATE_COMPLETION:
414
                    v = tpm_tis_data_read(s, locty);
415
                    break;
416
                default:
417
                    v = TPM_TIS_NO_DATA_BYTE;
418
                    break;
419
                }
420
                val |= (v << shift);
421
                shift += 8;
422
                size--;
423
            }
424
            shift = 0; /* no more adjustments */
425
        }
426
        break;
427
    case TPM_TIS_REG_INTERFACE_ID:
428
        val = s->loc[locty].iface_id;
429
        break;
430
    case TPM_TIS_REG_DID_VID:
431
        val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
432
        break;
433
    case TPM_TIS_REG_RID:
434
        val = TPM_TIS_TPM_RID;
435
        break;
436
#ifdef DEBUG_TIS
437
    case TPM_TIS_REG_DEBUG:
438
        tpm_tis_dump_state(s, addr);
439
        break;
440
#endif
441
    }
442

443
    if (shift) {
444
        val >>= shift;
445
    }
446

447
    trace_tpm_tis_mmio_read(size, addr, val);
448

449
    return val;
450
}
451

452
/*
453
 * A wrapper read function so that it can be directly called without
454
 * mmio.
455
 */
456
uint32_t tpm_tis_read_data(TPMState *s, hwaddr addr, unsigned size)
457
{
458
    return tpm_tis_mmio_read(s, addr, size);
459
}
460

461
/*
462
 * Calculate current data buffer checksum
463
 */
464
uint16_t tpm_tis_get_checksum(TPMState *s)
465
{
466
    return bswap16(crc_ccitt(0, s->buffer, s->rw_offset));
467
}
468

469
/*
470
 * Write a value to a register of the TIS interface
471
 * See specs pages 33-63 for description of the registers
472
 */
473
static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
474
                               uint64_t val, unsigned size)
475
{
476
    TPMState *s = opaque;
477
    uint16_t off = addr & 0xffc;
478
    uint8_t shift = (addr & 0x3) * 8;
479
    uint8_t locty = tpm_tis_locality_from_addr(addr);
480
    uint8_t active_locty, l;
481
    int c, set_new_locty = 1;
482
    uint16_t len;
483
    uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0);
484

485
    trace_tpm_tis_mmio_write(size, addr, val);
486

487
    if (locty == 4) {
488
        trace_tpm_tis_mmio_write_locty4();
489
        return;
490
    }
491

492
    if (tpm_backend_had_startup_error(s->be_driver)) {
493
        return;
494
    }
495

496
    val &= mask;
497

498
    if (shift) {
499
        val <<= shift;
500
        mask <<= shift;
501
    }
502

503
    mask ^= 0xffffffff;
504

505
    switch (off) {
506
    case TPM_TIS_REG_ACCESS:
507

508
        if ((val & TPM_TIS_ACCESS_SEIZE)) {
509
            val &= ~(TPM_TIS_ACCESS_REQUEST_USE |
510
                     TPM_TIS_ACCESS_ACTIVE_LOCALITY);
511
        }
512

513
        active_locty = s->active_locty;
514

515
        if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {
516
            /* give up locality if currently owned */
517
            if (s->active_locty == locty) {
518
                trace_tpm_tis_mmio_write_release_locty(locty);
519

520
                uint8_t newlocty = TPM_TIS_NO_LOCALITY;
521
                /* anybody wants the locality ? */
522
                for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {
523
                    if ((s->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {
524
                        trace_tpm_tis_mmio_write_locty_req_use(c);
525
                        newlocty = c;
526
                        break;
527
                    }
528
                }
529
                trace_tpm_tis_mmio_write_next_locty(newlocty);
530

531
                if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {
532
                    set_new_locty = 0;
533
                    tpm_tis_prep_abort(s, locty, newlocty);
534
                } else {
535
                    active_locty = TPM_TIS_NO_LOCALITY;
536
                }
537
            } else {
538
                /* not currently the owner; clear a pending request */
539
                s->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;
540
            }
541
        }
542

543
        if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {
544
            s->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;
545
        }
546

547
        if ((val & TPM_TIS_ACCESS_SEIZE)) {
548
            /*
549
             * allow seize if a locality is active and the requesting
550
             * locality is higher than the one that's active
551
             * OR
552
             * allow seize for requesting locality if no locality is
553
             * active
554
             */
555
            while ((TPM_TIS_IS_VALID_LOCTY(s->active_locty) &&
556
                    locty > s->active_locty) ||
557
                    !TPM_TIS_IS_VALID_LOCTY(s->active_locty)) {
558
                bool higher_seize = false;
559

560
                /* already a pending SEIZE ? */
561
                if ((s->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {
562
                    break;
563
                }
564

565
                /* check for ongoing seize by a higher locality */
566
                for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {
567
                    if ((s->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {
568
                        higher_seize = true;
569
                        break;
570
                    }
571
                }
572

573
                if (higher_seize) {
574
                    break;
575
                }
576

577
                /* cancel any seize by a lower locality */
578
                for (l = 0; l < locty; l++) {
579
                    s->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;
580
                }
581

582
                s->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;
583

584
                trace_tpm_tis_mmio_write_locty_seized(locty, s->active_locty);
585
                trace_tpm_tis_mmio_write_init_abort();
586

587
                set_new_locty = 0;
588
                tpm_tis_prep_abort(s, s->active_locty, locty);
589
                break;
590
            }
591
        }
592

593
        if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {
594
            if (s->active_locty != locty) {
595
                if (TPM_TIS_IS_VALID_LOCTY(s->active_locty)) {
596
                    s->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;
597
                } else {
598
                    /* no locality active -> make this one active now */
599
                    active_locty = locty;
600
                }
601
            }
602
        }
603

604
        if (set_new_locty) {
605
            tpm_tis_new_active_locality(s, active_locty);
606
        }
607

608
        break;
609
    case TPM_TIS_REG_INT_ENABLE:
610
        s->loc[locty].inte &= mask;
611
        s->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED |
612
                                        TPM_TIS_INT_POLARITY_MASK |
613
                                        TPM_TIS_INTERRUPTS_SUPPORTED));
614
        break;
615
    case TPM_TIS_REG_INT_VECTOR:
616
        /* hard wired -- ignore */
617
        break;
618
    case TPM_TIS_REG_INT_STATUS:
619
        /* clearing of interrupt flags */
620
        if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&
621
            (s->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {
622
            s->loc[locty].ints &= ~val;
623
            if (s->loc[locty].ints == 0) {
624
                qemu_irq_lower(s->irq);
625
                trace_tpm_tis_mmio_write_lowering_irq();
626
            }
627
        }
628
        s->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);
629
        break;
630
    case TPM_TIS_REG_STS:
631
        if (s->active_locty != locty) {
632
            break;
633
        }
634

635
        if (s->be_tpm_version == TPM_VERSION_2_0) {
636
            /* some flags that are only supported for TPM 2 */
637
            if (val & TPM_TIS_STS_COMMAND_CANCEL) {
638
                if (s->loc[locty].state == TPM_TIS_STATE_EXECUTION) {
639
                    /*
640
                     * request the backend to cancel. Some backends may not
641
                     * support it
642
                     */
643
                    tpm_backend_cancel_cmd(s->be_driver);
644
                }
645
            }
646

647
            if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) {
648
                if (locty == 3 || locty == 4) {
649
                    tpm_backend_reset_tpm_established_flag(s->be_driver, locty);
650
                }
651
            }
652
        }
653

654
        val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
655
                TPM_TIS_STS_RESPONSE_RETRY);
656

657
        if (val == TPM_TIS_STS_COMMAND_READY) {
658
            switch (s->loc[locty].state) {
659

660
            case TPM_TIS_STATE_READY:
661
                s->rw_offset = 0;
662
            break;
663

664
            case TPM_TIS_STATE_IDLE:
665
                tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_COMMAND_READY);
666
                s->loc[locty].state = TPM_TIS_STATE_READY;
667
                tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
668
            break;
669

670
            case TPM_TIS_STATE_EXECUTION:
671
            case TPM_TIS_STATE_RECEPTION:
672
                /* abort currently running command */
673
                trace_tpm_tis_mmio_write_init_abort();
674
                tpm_tis_prep_abort(s, locty, locty);
675
            break;
676

677
            case TPM_TIS_STATE_COMPLETION:
678
                s->rw_offset = 0;
679
                /* shortcut to ready state with C/R set */
680
                s->loc[locty].state = TPM_TIS_STATE_READY;
681
                if (!(s->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {
682
                    tpm_tis_sts_set(&s->loc[locty],
683
                                    TPM_TIS_STS_COMMAND_READY);
684
                    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
685
                }
686
                s->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);
687
            break;
688

689
            }
690
        } else if (val == TPM_TIS_STS_TPM_GO) {
691
            switch (s->loc[locty].state) {
692
            case TPM_TIS_STATE_RECEPTION:
693
                if ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {
694
                    tpm_tis_tpm_send(s, locty);
695
                }
696
                break;
697
            default:
698
                /* ignore */
699
                break;
700
            }
701
        } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {
702
            switch (s->loc[locty].state) {
703
            case TPM_TIS_STATE_COMPLETION:
704
                s->rw_offset = 0;
705
                tpm_tis_sts_set(&s->loc[locty],
706
                                TPM_TIS_STS_VALID|
707
                                TPM_TIS_STS_DATA_AVAILABLE);
708
                break;
709
            default:
710
                /* ignore */
711
                break;
712
            }
713
        }
714
        break;
715
    case TPM_TIS_REG_DATA_FIFO:
716
    case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
717
        /* data fifo */
718
        if (s->active_locty != locty) {
719
            break;
720
        }
721

722
        if (s->loc[locty].state == TPM_TIS_STATE_IDLE ||
723
            s->loc[locty].state == TPM_TIS_STATE_EXECUTION ||
724
            s->loc[locty].state == TPM_TIS_STATE_COMPLETION) {
725
            /* drop the byte */
726
        } else {
727
            trace_tpm_tis_mmio_write_data2send(val, size);
728
            if (s->loc[locty].state == TPM_TIS_STATE_READY) {
729
                s->loc[locty].state = TPM_TIS_STATE_RECEPTION;
730
                tpm_tis_sts_set(&s->loc[locty],
731
                                TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
732
            }
733

734
            val >>= shift;
735
            if (size > 4 - (addr & 0x3)) {
736
                /* prevent access beyond FIFO */
737
                size = 4 - (addr & 0x3);
738
            }
739

740
            while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) {
741
                if (s->rw_offset < s->be_buffer_size) {
742
                    s->buffer[s->rw_offset++] =
743
                        (uint8_t)val;
744
                    val >>= 8;
745
                    size--;
746
                } else {
747
                    tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID);
748
                }
749
            }
750

751
            /* check for complete packet */
752
            if (s->rw_offset > 5 &&
753
                (s->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
754
                /* we have a packet length - see if we have all of it */
755
                bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID);
756

757
                len = tpm_cmd_get_size(&s->buffer);
758
                if (len > s->rw_offset) {
759
                    tpm_tis_sts_set(&s->loc[locty],
760
                                    TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
761
                } else {
762
                    /* packet complete */
763
                    tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID);
764
                }
765
                if (need_irq) {
766
                    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
767
                }
768
            }
769
        }
770
        break;
771
    case TPM_TIS_REG_INTERFACE_ID:
772
        if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) {
773
            for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
774
                s->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK;
775
            }
776
        }
777
        break;
778
    }
779
}
780

781
/*
782
 * A wrapper write function so that it can be directly called without
783
 * mmio.
784
 */
785
void tpm_tis_write_data(TPMState *s, hwaddr addr, uint64_t val, uint32_t size)
786
{
787
    tpm_tis_mmio_write(s, addr, val, size);
788
}
789

790
const MemoryRegionOps tpm_tis_memory_ops = {
791
    .read = tpm_tis_mmio_read,
792
    .write = tpm_tis_mmio_write,
793
    .endianness = DEVICE_LITTLE_ENDIAN,
794
    .valid = {
795
        .min_access_size = 1,
796
        .max_access_size = 4,
797
    },
798
};
799

800
/*
801
 * Get the TPMVersion of the backend device being used
802
 */
803
enum TPMVersion tpm_tis_get_tpm_version(TPMState *s)
804
{
805
    if (tpm_backend_had_startup_error(s->be_driver)) {
806
        return TPM_VERSION_UNSPEC;
807
    }
808

809
    return tpm_backend_get_tpm_version(s->be_driver);
810
}
811

812
/*
813
 * This function is called when the machine starts, resets or due to
814
 * S3 resume.
815
 */
816
void tpm_tis_reset(TPMState *s)
817
{
818
    int c;
819

820
    s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
821
    s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),
822
                            TPM_TIS_BUFFER_MAX);
823

824
    if (s->ppi_enabled) {
825
        tpm_ppi_reset(&s->ppi);
826
    }
827
    tpm_backend_reset(s->be_driver);
828

829
    s->active_locty = TPM_TIS_NO_LOCALITY;
830
    s->next_locty = TPM_TIS_NO_LOCALITY;
831
    s->aborting_locty = TPM_TIS_NO_LOCALITY;
832

833
    for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
834
        s->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
835
        switch (s->be_tpm_version) {
836
        case TPM_VERSION_UNSPEC:
837
            break;
838
        case TPM_VERSION_1_2:
839
            s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2;
840
            s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3;
841
            break;
842
        case TPM_VERSION_2_0:
843
            s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0;
844
            s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0;
845
            break;
846
        }
847
        s->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
848
        s->loc[c].ints = 0;
849
        s->loc[c].state = TPM_TIS_STATE_IDLE;
850

851
        s->rw_offset = 0;
852
    }
853

854
    if (tpm_backend_startup_tpm(s->be_driver, s->be_buffer_size) < 0) {
855
        exit(1);
856
    }
857
}
858

859
/* persistent state handling */
860

861
int tpm_tis_pre_save(TPMState *s)
862
{
863
    uint8_t locty = s->active_locty;
864

865
    trace_tpm_tis_pre_save(locty, s->rw_offset);
866

867
    if (DEBUG_TIS) {
868
        tpm_tis_dump_state(s, 0);
869
    }
870

871
    /*
872
     * Synchronize with backend completion.
873
     */
874
    tpm_backend_finish_sync(s->be_driver);
875

876
    return 0;
877
}
878

879
const VMStateDescription vmstate_locty = {
880
    .name = "tpm-tis/locty",
881
    .version_id = 0,
882
    .fields = (const VMStateField[]) {
883
        VMSTATE_UINT32(state, TPMLocality),
884
        VMSTATE_UINT32(inte, TPMLocality),
885
        VMSTATE_UINT32(ints, TPMLocality),
886
        VMSTATE_UINT8(access, TPMLocality),
887
        VMSTATE_UINT32(sts, TPMLocality),
888
        VMSTATE_UINT32(iface_id, TPMLocality),
889
        VMSTATE_END_OF_LIST(),
890
    }
891
};
892

893

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

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

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

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