Statistics
| Branch: | Revision:

root / tpm / tpm_tis.c @ 0d09e41a

History | View | Annotate | Download (28.9 kB)

1
/*
2
 * tpm_tis.c - QEMU's TPM TIS interface emulator
3
 *
4
 * Copyright (C) 2006,2010-2013 IBM Corporation
5
 *
6
 * Authors:
7
 *  Stefan Berger <stefanb@us.ibm.com>
8
 *  David Safford <safford@us.ibm.com>
9
 *
10
 * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at>
11
 *
12
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
13
 * See the COPYING file in the top-level directory.
14
 *
15
 * Implementation of the TIS interface according to specs found at
16
 * http://www.trustedcomputinggroup.org. This implementation currently
17
 * supports version 1.21, revision 1.0.
18
 * In the developers menu choose the PC Client section then find the TIS
19
 * specification.
20
 */
21

    
22
#include "backends/tpm.h"
23
#include "tpm_int.h"
24
#include "block/block.h"
25
#include "exec/address-spaces.h"
26
#include "hw/hw.h"
27
#include "hw/i386/pc.h"
28
#include "hw/pci/pci_ids.h"
29
#include "tpm/tpm_tis.h"
30
#include "qemu-common.h"
31

    
32
/*#define DEBUG_TIS */
33

    
34
#ifdef DEBUG_TIS
35
#define DPRINTF(fmt, ...) \
36
    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
37
#else
38
#define DPRINTF(fmt, ...) \
39
    do { } while (0)
40
#endif
41

    
42
/* whether the STS interrupt is supported */
43
#define RAISE_STS_IRQ
44

    
45
/* tis registers */
46
#define TPM_TIS_REG_ACCESS                0x00
47
#define TPM_TIS_REG_INT_ENABLE            0x08
48
#define TPM_TIS_REG_INT_VECTOR            0x0c
49
#define TPM_TIS_REG_INT_STATUS            0x10
50
#define TPM_TIS_REG_INTF_CAPABILITY       0x14
51
#define TPM_TIS_REG_STS                   0x18
52
#define TPM_TIS_REG_DATA_FIFO             0x24
53
#define TPM_TIS_REG_DID_VID               0xf00
54
#define TPM_TIS_REG_RID                   0xf04
55

    
56
/* vendor-specific registers */
57
#define TPM_TIS_REG_DEBUG                 0xf90
58

    
59
#define TPM_TIS_STS_VALID                 (1 << 7)
60
#define TPM_TIS_STS_COMMAND_READY         (1 << 6)
61
#define TPM_TIS_STS_TPM_GO                (1 << 5)
62
#define TPM_TIS_STS_DATA_AVAILABLE        (1 << 4)
63
#define TPM_TIS_STS_EXPECT                (1 << 3)
64
#define TPM_TIS_STS_RESPONSE_RETRY        (1 << 1)
65

    
66
#define TPM_TIS_BURST_COUNT_SHIFT         8
67
#define TPM_TIS_BURST_COUNT(X) \
68
    ((X) << TPM_TIS_BURST_COUNT_SHIFT)
69

    
70
#define TPM_TIS_ACCESS_TPM_REG_VALID_STS  (1 << 7)
71
#define TPM_TIS_ACCESS_ACTIVE_LOCALITY    (1 << 5)
72
#define TPM_TIS_ACCESS_BEEN_SEIZED        (1 << 4)
73
#define TPM_TIS_ACCESS_SEIZE              (1 << 3)
74
#define TPM_TIS_ACCESS_PENDING_REQUEST    (1 << 2)
75
#define TPM_TIS_ACCESS_REQUEST_USE        (1 << 1)
76
#define TPM_TIS_ACCESS_TPM_ESTABLISHMENT  (1 << 0)
77

    
78
#define TPM_TIS_INT_ENABLED               (1 << 31)
79
#define TPM_TIS_INT_DATA_AVAILABLE        (1 << 0)
80
#define TPM_TIS_INT_STS_VALID             (1 << 1)
81
#define TPM_TIS_INT_LOCALITY_CHANGED      (1 << 2)
82
#define TPM_TIS_INT_COMMAND_READY         (1 << 7)
83

    
84
#define TPM_TIS_INT_POLARITY_MASK         (3 << 3)
85
#define TPM_TIS_INT_POLARITY_LOW_LEVEL    (1 << 3)
86

    
87
#ifndef RAISE_STS_IRQ
88

    
89
#define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
90
                                      TPM_TIS_INT_DATA_AVAILABLE   | \
91
                                      TPM_TIS_INT_COMMAND_READY)
92

    
93
#else
94

    
95
#define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
96
                                      TPM_TIS_INT_DATA_AVAILABLE   | \
97
                                      TPM_TIS_INT_STS_VALID | \
98
                                      TPM_TIS_INT_COMMAND_READY)
99

    
100
#endif
101

    
102
#define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL  (1 << 4) /* support is mandatory */
103
#define TPM_TIS_CAPABILITIES_SUPPORTED   (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
104
                                          TPM_TIS_INTERRUPTS_SUPPORTED)
105

    
106
#define TPM_TIS_TPM_DID       0x0001
107
#define TPM_TIS_TPM_VID       PCI_VENDOR_ID_IBM
108
#define TPM_TIS_TPM_RID       0x0001
109

    
110
#define TPM_TIS_NO_DATA_BYTE  0xff
111

    
112
/* local prototypes */
113

    
114
static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
115
                                  unsigned size);
116

    
117
/* utility functions */
118

    
119
static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
120
{
121
    return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
122
}
123

    
124
static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb)
125
{
126
    return be32_to_cpu(*(uint32_t *)&sb->buffer[2]);
127
}
128

    
129
static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
130
{
131
#ifdef DEBUG_TIS
132
    uint32_t len, i;
133

    
134
    len = tpm_tis_get_size_from_buffer(sb);
135
    DPRINTF("tpm_tis: %s length = %d\n", string, len);
136
    for (i = 0; i < len; i++) {
137
        if (i && !(i % 16)) {
138
            DPRINTF("\n");
139
        }
140
        DPRINTF("%.2X ", sb->buffer[i]);
141
    }
142
    DPRINTF("\n");
143
#endif
144
}
145

    
146
/*
147
 * Send a request to the TPM.
148
 */
149
static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
150
{
151
    TPMTISEmuState *tis = &s->s.tis;
152

    
153
    tpm_tis_show_buffer(&tis->loc[locty].w_buffer, "tpm_tis: To TPM");
154

    
155
    s->locty_number = locty;
156
    s->locty_data = &tis->loc[locty];
157

    
158
    /*
159
     * w_offset serves as length indicator for length of data;
160
     * it's reset when the response comes back
161
     */
162
    tis->loc[locty].state = TPM_TIS_STATE_EXECUTION;
163

    
164
    tpm_backend_deliver_request(s->be_driver);
165
}
166

    
167
/* raise an interrupt if allowed */
168
static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask)
169
{
170
    TPMTISEmuState *tis = &s->s.tis;
171

    
172
    if (!TPM_TIS_IS_VALID_LOCTY(locty)) {
173
        return;
174
    }
175

    
176
    if ((tis->loc[locty].inte & TPM_TIS_INT_ENABLED) &&
177
        (tis->loc[locty].inte & irqmask)) {
178
        DPRINTF("tpm_tis: Raising IRQ for flag %08x\n", irqmask);
179
        qemu_irq_raise(s->s.tis.irq);
180
        tis->loc[locty].ints |= irqmask;
181
    }
182
}
183

    
184
static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty)
185
{
186
    uint8_t l;
187

    
188
    for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
189
        if (l == locty) {
190
            continue;
191
        }
192
        if ((s->s.tis.loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) {
193
            return 1;
194
        }
195
    }
196

    
197
    return 0;
198
}
199

    
200
static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
201
{
202
    TPMTISEmuState *tis = &s->s.tis;
203
    bool change = (s->s.tis.active_locty != new_active_locty);
204
    bool is_seize;
205
    uint8_t mask;
206

    
207
    if (change && TPM_TIS_IS_VALID_LOCTY(s->s.tis.active_locty)) {
208
        is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) &&
209
                   tis->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE;
210

    
211
        if (is_seize) {
212
            mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY);
213
        } else {
214
            mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY|
215
                     TPM_TIS_ACCESS_REQUEST_USE);
216
        }
217
        /* reset flags on the old active locality */
218
        tis->loc[s->s.tis.active_locty].access &= mask;
219

    
220
        if (is_seize) {
221
            tis->loc[tis->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED;
222
        }
223
    }
224

    
225
    tis->active_locty = new_active_locty;
226

    
227
    DPRINTF("tpm_tis: Active locality is now %d\n", s->s.tis.active_locty);
228

    
229
    if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) {
230
        /* set flags on the new active locality */
231
        tis->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY;
232
        tis->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE |
233
                                               TPM_TIS_ACCESS_SEIZE);
234
    }
235

    
236
    if (change) {
237
        tpm_tis_raise_irq(s, tis->active_locty, TPM_TIS_INT_LOCALITY_CHANGED);
238
    }
239
}
240

    
241
/* abort -- this function switches the locality */
242
static void tpm_tis_abort(TPMState *s, uint8_t locty)
243
{
244
    TPMTISEmuState *tis = &s->s.tis;
245

    
246
    tis->loc[locty].r_offset = 0;
247
    tis->loc[locty].w_offset = 0;
248

    
249
    DPRINTF("tpm_tis: tis_abort: new active locality is %d\n", tis->next_locty);
250

    
251
    /*
252
     * Need to react differently depending on who's aborting now and
253
     * which locality will become active afterwards.
254
     */
255
    if (tis->aborting_locty == tis->next_locty) {
256
        tis->loc[tis->aborting_locty].state = TPM_TIS_STATE_READY;
257
        tis->loc[tis->aborting_locty].sts = TPM_TIS_STS_COMMAND_READY;
258
        tpm_tis_raise_irq(s, tis->aborting_locty, TPM_TIS_INT_COMMAND_READY);
259
    }
260

    
261
    /* locality after abort is another one than the current one */
262
    tpm_tis_new_active_locality(s, tis->next_locty);
263

    
264
    tis->next_locty = TPM_TIS_NO_LOCALITY;
265
    /* nobody's aborting a command anymore */
266
    tis->aborting_locty = TPM_TIS_NO_LOCALITY;
267
}
268

    
269
/* prepare aborting current command */
270
static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
271
{
272
    TPMTISEmuState *tis = &s->s.tis;
273
    uint8_t busy_locty;
274

    
275
    tis->aborting_locty = locty;
276
    tis->next_locty = newlocty;  /* locality after successful abort */
277

    
278
    /*
279
     * only abort a command using an interrupt if currently executing
280
     * a command AND if there's a valid connection to the vTPM.
281
     */
282
    for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) {
283
        if (tis->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) {
284
            /*
285
             * request the backend to cancel. Some backends may not
286
             * support it
287
             */
288
            tpm_backend_cancel_cmd(s->be_driver);
289
            return;
290
        }
291
    }
292

    
293
    tpm_tis_abort(s, locty);
294
}
295

    
296
static void tpm_tis_receive_bh(void *opaque)
297
{
298
    TPMState *s = opaque;
299
    TPMTISEmuState *tis = &s->s.tis;
300
    uint8_t locty = s->locty_number;
301

    
302
    tis->loc[locty].sts = TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE;
303
    tis->loc[locty].state = TPM_TIS_STATE_COMPLETION;
304
    tis->loc[locty].r_offset = 0;
305
    tis->loc[locty].w_offset = 0;
306

    
307
    if (TPM_TIS_IS_VALID_LOCTY(tis->next_locty)) {
308
        tpm_tis_abort(s, locty);
309
    }
310

    
311
#ifndef RAISE_STS_IRQ
312
    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_DATA_AVAILABLE);
313
#else
314
    tpm_tis_raise_irq(s, locty,
315
                      TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
316
#endif
317
}
318

    
319
/*
320
 * Callback from the TPM to indicate that the response was received.
321
 */
322
static void tpm_tis_receive_cb(TPMState *s, uint8_t locty)
323
{
324
    TPMTISEmuState *tis = &s->s.tis;
325

    
326
    assert(s->locty_number == locty);
327

    
328
    qemu_bh_schedule(tis->bh);
329
}
330

    
331
/*
332
 * Read a byte of response data
333
 */
334
static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
335
{
336
    TPMTISEmuState *tis = &s->s.tis;
337
    uint32_t ret = TPM_TIS_NO_DATA_BYTE;
338
    uint16_t len;
339

    
340
    if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
341
        len = tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
342

    
343
        ret = tis->loc[locty].r_buffer.buffer[tis->loc[locty].r_offset++];
344
        if (tis->loc[locty].r_offset >= len) {
345
            /* got last byte */
346
            tis->loc[locty].sts = TPM_TIS_STS_VALID;
347
#ifdef RAISE_STS_IRQ
348
            tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
349
#endif
350
        }
351
        DPRINTF("tpm_tis: tpm_tis_data_read byte 0x%02x   [%d]\n",
352
                ret, tis->loc[locty].r_offset-1);
353
    }
354

    
355
    return ret;
356
}
357

    
358
#ifdef DEBUG_TIS
359
static void tpm_tis_dump_state(void *opaque, hwaddr addr)
360
{
361
    static const unsigned regs[] = {
362
        TPM_TIS_REG_ACCESS,
363
        TPM_TIS_REG_INT_ENABLE,
364
        TPM_TIS_REG_INT_VECTOR,
365
        TPM_TIS_REG_INT_STATUS,
366
        TPM_TIS_REG_INTF_CAPABILITY,
367
        TPM_TIS_REG_STS,
368
        TPM_TIS_REG_DID_VID,
369
        TPM_TIS_REG_RID,
370
        0xfff};
371
    int idx;
372
    uint8_t locty = tpm_tis_locality_from_addr(addr);
373
    hwaddr base = addr & ~0xfff;
374
    TPMState *s = opaque;
375
    TPMTISEmuState *tis = &s->s.tis;
376

    
377
    DPRINTF("tpm_tis: active locality      : %d\n"
378
            "tpm_tis: state of locality %d : %d\n"
379
            "tpm_tis: register dump:\n",
380
            tis->active_locty,
381
            locty, tis->loc[locty].state);
382

    
383
    for (idx = 0; regs[idx] != 0xfff; idx++) {
384
        DPRINTF("tpm_tis: 0x%04x : 0x%08x\n", regs[idx],
385
                (uint32_t)tpm_tis_mmio_read(opaque, base + regs[idx], 4));
386
    }
387

    
388
    DPRINTF("tpm_tis: read offset   : %d\n"
389
            "tpm_tis: result buffer : ",
390
            tis->loc[locty].r_offset);
391
    for (idx = 0;
392
         idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
393
         idx++) {
394
        DPRINTF("%c%02x%s",
395
                tis->loc[locty].r_offset == idx ? '>' : ' ',
396
                tis->loc[locty].r_buffer.buffer[idx],
397
                ((idx & 0xf) == 0xf) ? "\ntpm_tis:                 " : "");
398
    }
399
    DPRINTF("\n"
400
            "tpm_tis: write offset  : %d\n"
401
            "tpm_tis: request buffer: ",
402
            tis->loc[locty].w_offset);
403
    for (idx = 0;
404
         idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
405
         idx++) {
406
        DPRINTF("%c%02x%s",
407
                tis->loc[locty].w_offset == idx ? '>' : ' ',
408
                tis->loc[locty].w_buffer.buffer[idx],
409
                ((idx & 0xf) == 0xf) ? "\ntpm_tis:                 " : "");
410
    }
411
    DPRINTF("\n");
412
}
413
#endif
414

    
415
/*
416
 * Read a register of the TIS interface
417
 * See specs pages 33-63 for description of the registers
418
 */
419
static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
420
                                  unsigned size)
421
{
422
    TPMState *s = opaque;
423
    TPMTISEmuState *tis = &s->s.tis;
424
    uint16_t offset = addr & 0xffc;
425
    uint8_t shift = (addr & 0x3) * 8;
426
    uint32_t val = 0xffffffff;
427
    uint8_t locty = tpm_tis_locality_from_addr(addr);
428
    uint32_t avail;
429

    
430
    if (tpm_backend_had_startup_error(s->be_driver)) {
431
        return val;
432
    }
433

    
434
    switch (offset) {
435
    case TPM_TIS_REG_ACCESS:
436
        /* never show the SEIZE flag even though we use it internally */
437
        val = tis->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE;
438
        /* the pending flag is always calculated */
439
        if (tpm_tis_check_request_use_except(s, locty)) {
440
            val |= TPM_TIS_ACCESS_PENDING_REQUEST;
441
        }
442
        val |= !tpm_backend_get_tpm_established_flag(s->be_driver);
443
        break;
444
    case TPM_TIS_REG_INT_ENABLE:
445
        val = tis->loc[locty].inte;
446
        break;
447
    case TPM_TIS_REG_INT_VECTOR:
448
        val = tis->irq_num;
449
        break;
450
    case TPM_TIS_REG_INT_STATUS:
451
        val = tis->loc[locty].ints;
452
        break;
453
    case TPM_TIS_REG_INTF_CAPABILITY:
454
        val = TPM_TIS_CAPABILITIES_SUPPORTED;
455
        break;
456
    case TPM_TIS_REG_STS:
457
        if (tis->active_locty == locty) {
458
            if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
459
                val = TPM_TIS_BURST_COUNT(
460
                       tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer)
461
                       - tis->loc[locty].r_offset) | tis->loc[locty].sts;
462
            } else {
463
                avail = tis->loc[locty].w_buffer.size
464
                        - tis->loc[locty].w_offset;
465
                /*
466
                 * byte-sized reads should not return 0x00 for 0x100
467
                 * available bytes.
468
                 */
469
                if (size == 1 && avail > 0xff) {
470
                    avail = 0xff;
471
                }
472
                val = TPM_TIS_BURST_COUNT(avail) | tis->loc[locty].sts;
473
            }
474
        }
475
        break;
476
    case TPM_TIS_REG_DATA_FIFO:
477
        if (tis->active_locty == locty) {
478
            switch (tis->loc[locty].state) {
479
            case TPM_TIS_STATE_COMPLETION:
480
                val = tpm_tis_data_read(s, locty);
481
                break;
482
            default:
483
                val = TPM_TIS_NO_DATA_BYTE;
484
                break;
485
            }
486
        }
487
        break;
488
    case TPM_TIS_REG_DID_VID:
489
        val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
490
        break;
491
    case TPM_TIS_REG_RID:
492
        val = TPM_TIS_TPM_RID;
493
        break;
494
#ifdef DEBUG_TIS
495
    case TPM_TIS_REG_DEBUG:
496
        tpm_tis_dump_state(opaque, addr);
497
        break;
498
#endif
499
    }
500

    
501
    if (shift) {
502
        val >>= shift;
503
    }
504

    
505
    DPRINTF("tpm_tis:  read.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);
506

    
507
    return val;
508
}
509

    
510
/*
511
 * Write a value to a register of the TIS interface
512
 * See specs pages 33-63 for description of the registers
513
 */
514
static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
515
                                      uint64_t val, unsigned size,
516
                                      bool hw_access)
517
{
518
    TPMState *s = opaque;
519
    TPMTISEmuState *tis = &s->s.tis;
520
    uint16_t off = addr & 0xfff;
521
    uint8_t locty = tpm_tis_locality_from_addr(addr);
522
    uint8_t active_locty, l;
523
    int c, set_new_locty = 1;
524
    uint16_t len;
525

    
526
    DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);
527

    
528
    if (locty == 4 && !hw_access) {
529
        DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n");
530
        return;
531
    }
532

    
533
    if (tpm_backend_had_startup_error(s->be_driver)) {
534
        return;
535
    }
536

    
537
    switch (off) {
538
    case TPM_TIS_REG_ACCESS:
539

    
540
        if ((val & TPM_TIS_ACCESS_SEIZE)) {
541
            val &= ~(TPM_TIS_ACCESS_REQUEST_USE |
542
                     TPM_TIS_ACCESS_ACTIVE_LOCALITY);
543
        }
544

    
545
        active_locty = tis->active_locty;
546

    
547
        if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {
548
            /* give up locality if currently owned */
549
            if (tis->active_locty == locty) {
550
                DPRINTF("tpm_tis: Releasing locality %d\n", locty);
551

    
552
                uint8_t newlocty = TPM_TIS_NO_LOCALITY;
553
                /* anybody wants the locality ? */
554
                for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {
555
                    if ((tis->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {
556
                        DPRINTF("tpm_tis: Locality %d requests use.\n", c);
557
                        newlocty = c;
558
                        break;
559
                    }
560
                }
561
                DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "
562
                        "Next active locality: %d\n",
563
                        newlocty);
564

    
565
                if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {
566
                    set_new_locty = 0;
567
                    tpm_tis_prep_abort(s, locty, newlocty);
568
                } else {
569
                    active_locty = TPM_TIS_NO_LOCALITY;
570
                }
571
            } else {
572
                /* not currently the owner; clear a pending request */
573
                tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;
574
            }
575
        }
576

    
577
        if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {
578
            tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;
579
        }
580

    
581
        if ((val & TPM_TIS_ACCESS_SEIZE)) {
582
            /*
583
             * allow seize if a locality is active and the requesting
584
             * locality is higher than the one that's active
585
             * OR
586
             * allow seize for requesting locality if no locality is
587
             * active
588
             */
589
            while ((TPM_TIS_IS_VALID_LOCTY(tis->active_locty) &&
590
                    locty > tis->active_locty) ||
591
                    !TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
592
                bool higher_seize = FALSE;
593

    
594
                /* already a pending SEIZE ? */
595
                if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {
596
                    break;
597
                }
598

    
599
                /* check for ongoing seize by a higher locality */
600
                for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {
601
                    if ((tis->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {
602
                        higher_seize = TRUE;
603
                        break;
604
                    }
605
                }
606

    
607
                if (higher_seize) {
608
                    break;
609
                }
610

    
611
                /* cancel any seize by a lower locality */
612
                for (l = 0; l < locty - 1; l++) {
613
                    tis->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;
614
                }
615

    
616
                tis->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;
617
                DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: "
618
                        "Locality %d seized from locality %d\n",
619
                        locty, tis->active_locty);
620
                DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n");
621
                set_new_locty = 0;
622
                tpm_tis_prep_abort(s, tis->active_locty, locty);
623
                break;
624
            }
625
        }
626

    
627
        if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {
628
            if (tis->active_locty != locty) {
629
                if (TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
630
                    tis->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;
631
                } else {
632
                    /* no locality active -> make this one active now */
633
                    active_locty = locty;
634
                }
635
            }
636
        }
637

    
638
        if (set_new_locty) {
639
            tpm_tis_new_active_locality(s, active_locty);
640
        }
641

    
642
        break;
643
    case TPM_TIS_REG_INT_ENABLE:
644
        if (tis->active_locty != locty) {
645
            break;
646
        }
647

    
648
        tis->loc[locty].inte = (val & (TPM_TIS_INT_ENABLED |
649
                                       TPM_TIS_INT_POLARITY_MASK |
650
                                       TPM_TIS_INTERRUPTS_SUPPORTED));
651
        break;
652
    case TPM_TIS_REG_INT_VECTOR:
653
        /* hard wired -- ignore */
654
        break;
655
    case TPM_TIS_REG_INT_STATUS:
656
        if (tis->active_locty != locty) {
657
            break;
658
        }
659

    
660
        /* clearing of interrupt flags */
661
        if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&
662
            (tis->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {
663
            tis->loc[locty].ints &= ~val;
664
            if (tis->loc[locty].ints == 0) {
665
                qemu_irq_lower(tis->irq);
666
                DPRINTF("tpm_tis: Lowering IRQ\n");
667
            }
668
        }
669
        tis->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);
670
        break;
671
    case TPM_TIS_REG_STS:
672
        if (tis->active_locty != locty) {
673
            break;
674
        }
675

    
676
        val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
677
                TPM_TIS_STS_RESPONSE_RETRY);
678

    
679
        if (val == TPM_TIS_STS_COMMAND_READY) {
680
            switch (tis->loc[locty].state) {
681

    
682
            case TPM_TIS_STATE_READY:
683
                tis->loc[locty].w_offset = 0;
684
                tis->loc[locty].r_offset = 0;
685
            break;
686

    
687
            case TPM_TIS_STATE_IDLE:
688
                tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY;
689
                tis->loc[locty].state = TPM_TIS_STATE_READY;
690
                tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
691
            break;
692

    
693
            case TPM_TIS_STATE_EXECUTION:
694
            case TPM_TIS_STATE_RECEPTION:
695
                /* abort currently running command */
696
                DPRINTF("tpm_tis: %s: Initiating abort.\n",
697
                        __func__);
698
                tpm_tis_prep_abort(s, locty, locty);
699
            break;
700

    
701
            case TPM_TIS_STATE_COMPLETION:
702
                tis->loc[locty].w_offset = 0;
703
                tis->loc[locty].r_offset = 0;
704
                /* shortcut to ready state with C/R set */
705
                tis->loc[locty].state = TPM_TIS_STATE_READY;
706
                if (!(tis->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {
707
                    tis->loc[locty].sts   = TPM_TIS_STS_COMMAND_READY;
708
                    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
709
                }
710
                tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);
711
            break;
712

    
713
            }
714
        } else if (val == TPM_TIS_STS_TPM_GO) {
715
            switch (tis->loc[locty].state) {
716
            case TPM_TIS_STATE_RECEPTION:
717
                if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {
718
                    tpm_tis_tpm_send(s, locty);
719
                }
720
                break;
721
            default:
722
                /* ignore */
723
                break;
724
            }
725
        } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {
726
            switch (tis->loc[locty].state) {
727
            case TPM_TIS_STATE_COMPLETION:
728
                tis->loc[locty].r_offset = 0;
729
                tis->loc[locty].sts = TPM_TIS_STS_VALID |
730
                                      TPM_TIS_STS_DATA_AVAILABLE;
731
                break;
732
            default:
733
                /* ignore */
734
                break;
735
            }
736
        }
737
        break;
738
    case TPM_TIS_REG_DATA_FIFO:
739
        /* data fifo */
740
        if (tis->active_locty != locty) {
741
            break;
742
        }
743

    
744
        if (tis->loc[locty].state == TPM_TIS_STATE_IDLE ||
745
            tis->loc[locty].state == TPM_TIS_STATE_EXECUTION ||
746
            tis->loc[locty].state == TPM_TIS_STATE_COMPLETION) {
747
            /* drop the byte */
748
        } else {
749
            DPRINTF("tpm_tis: Byte to send to TPM: %02x\n", (uint8_t)val);
750
            if (tis->loc[locty].state == TPM_TIS_STATE_READY) {
751
                tis->loc[locty].state = TPM_TIS_STATE_RECEPTION;
752
                tis->loc[locty].sts = TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID;
753
            }
754

    
755
            if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
756
                if (tis->loc[locty].w_offset < tis->loc[locty].w_buffer.size) {
757
                    tis->loc[locty].w_buffer.
758
                        buffer[tis->loc[locty].w_offset++] = (uint8_t)val;
759
                } else {
760
                    tis->loc[locty].sts = TPM_TIS_STS_VALID;
761
                }
762
            }
763

    
764
            /* check for complete packet */
765
            if (tis->loc[locty].w_offset > 5 &&
766
                (tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
767
                /* we have a packet length - see if we have all of it */
768
#ifdef RAISE_STS_IRQ
769
                bool needIrq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID);
770
#endif
771
                len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
772
                if (len > tis->loc[locty].w_offset) {
773
                    tis->loc[locty].sts = TPM_TIS_STS_EXPECT |
774
                                          TPM_TIS_STS_VALID;
775
                } else {
776
                    /* packet complete */
777
                    tis->loc[locty].sts = TPM_TIS_STS_VALID;
778
                }
779
#ifdef RAISE_STS_IRQ
780
                if (needIrq) {
781
                    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
782
                }
783
#endif
784
            }
785
        }
786
        break;
787
    }
788
}
789

    
790
static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
791
                               uint64_t val, unsigned size)
792
{
793
    return tpm_tis_mmio_write_intern(opaque, addr, val, size, false);
794
}
795

    
796
static const MemoryRegionOps tpm_tis_memory_ops = {
797
    .read = tpm_tis_mmio_read,
798
    .write = tpm_tis_mmio_write,
799
    .endianness = DEVICE_LITTLE_ENDIAN,
800
    .valid = {
801
        .min_access_size = 1,
802
        .max_access_size = 4,
803
    },
804
};
805

    
806
static int tpm_tis_do_startup_tpm(TPMState *s)
807
{
808
    return tpm_backend_startup_tpm(s->be_driver);
809
}
810

    
811
/*
812
 * This function is called when the machine starts, resets or due to
813
 * S3 resume.
814
 */
815
static void tpm_tis_reset(DeviceState *dev)
816
{
817
    TPMState *s = TPM(dev);
818
    TPMTISEmuState *tis = &s->s.tis;
819
    int c;
820

    
821
    tpm_backend_reset(s->be_driver);
822

    
823
    tis->active_locty = TPM_TIS_NO_LOCALITY;
824
    tis->next_locty = TPM_TIS_NO_LOCALITY;
825
    tis->aborting_locty = TPM_TIS_NO_LOCALITY;
826

    
827
    for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
828
        tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
829
        tis->loc[c].sts = 0;
830
        tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
831
        tis->loc[c].ints = 0;
832
        tis->loc[c].state = TPM_TIS_STATE_IDLE;
833

    
834
        tis->loc[c].w_offset = 0;
835
        tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].w_buffer);
836
        tis->loc[c].r_offset = 0;
837
        tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].r_buffer);
838
    }
839

    
840
    tpm_tis_do_startup_tpm(s);
841
}
842

    
843
static const VMStateDescription vmstate_tpm_tis = {
844
    .name = "tpm",
845
    .unmigratable = 1,
846
};
847

    
848
static Property tpm_tis_properties[] = {
849
    DEFINE_PROP_UINT32("irq", TPMState,
850
                       s.tis.irq_num, TPM_TIS_IRQ),
851
    DEFINE_PROP_STRING("tpmdev", TPMState, backend),
852
    DEFINE_PROP_END_OF_LIST(),
853
};
854

    
855
static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
856
{
857
    TPMState *s = TPM(dev);
858
    TPMTISEmuState *tis = &s->s.tis;
859

    
860
    s->be_driver = qemu_find_tpm(s->backend);
861
    if (!s->be_driver) {
862
        error_setg(errp, "tpm_tis: backend driver with id %s could not be "
863
                   "found", s->backend);
864
        return;
865
    }
866

    
867
    s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
868

    
869
    if (tpm_backend_init(s->be_driver, s, tpm_tis_receive_cb)) {
870
        error_setg(errp, "tpm_tis: backend driver with id %s could not be "
871
                   "initialized", s->backend);
872
        return;
873
    }
874

    
875
    if (tis->irq_num > 15) {
876
        error_setg(errp, "tpm_tis: IRQ %d for TPM TIS is outside valid range "
877
                   "of 0 to 15.\n", tis->irq_num);
878
        return;
879
    }
880

    
881
    tis->bh = qemu_bh_new(tpm_tis_receive_bh, s);
882

    
883
    isa_init_irq(&s->busdev, &tis->irq, tis->irq_num);
884
}
885

    
886
static void tpm_tis_initfn(Object *obj)
887
{
888
    ISADevice *dev = ISA_DEVICE(obj);
889
    TPMState *s = TPM(obj);
890

    
891
    memory_region_init_io(&s->mmio, &tpm_tis_memory_ops, s, "tpm-tis-mmio",
892
                          TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
893
    memory_region_add_subregion(isa_address_space(dev), TPM_TIS_ADDR_BASE,
894
                                &s->mmio);
895
}
896

    
897
static void tpm_tis_uninitfn(Object *obj)
898
{
899
    TPMState *s = TPM(obj);
900

    
901
    memory_region_del_subregion(get_system_memory(), &s->mmio);
902
    memory_region_destroy(&s->mmio);
903
}
904

    
905
static void tpm_tis_class_init(ObjectClass *klass, void *data)
906
{
907
    DeviceClass *dc = DEVICE_CLASS(klass);
908

    
909
    dc->realize = tpm_tis_realizefn;
910
    dc->props = tpm_tis_properties;
911
    dc->reset = tpm_tis_reset;
912
    dc->vmsd  = &vmstate_tpm_tis;
913
}
914

    
915
static const TypeInfo tpm_tis_info = {
916
    .name = TYPE_TPM_TIS,
917
    .parent = TYPE_ISA_DEVICE,
918
    .instance_size = sizeof(TPMState),
919
    .instance_init = tpm_tis_initfn,
920
    .instance_finalize = tpm_tis_uninitfn,
921
    .class_init  = tpm_tis_class_init,
922
};
923

    
924
static void tpm_tis_register(void)
925
{
926
    type_register_static(&tpm_tis_info);
927
    tpm_register_model(TPM_MODEL_TPM_TIS);
928
}
929

    
930
type_init(tpm_tis_register)