Statistics
| Branch: | Revision:

root / hw / tpm / tpm_tis.c @ 6a1751b7

History | View | Annotate | Download (29 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 "sysemu/tpm_backend.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_tis.h"
30
#include "qemu-common.h"
31
#include "qemu/main-loop.h"
32

    
33
/*#define DEBUG_TIS */
34

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

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

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

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

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

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

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

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

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

    
88
#ifndef RAISE_STS_IRQ
89

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

    
94
#else
95

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

    
101
#endif
102

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

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

    
111
#define TPM_TIS_NO_DATA_BYTE  0xff
112

    
113
/* local prototypes */
114

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

    
118
/* utility functions */
119

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
198
    return 0;
199
}
200

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

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

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

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

    
226
    tis->active_locty = new_active_locty;
227

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

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

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

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

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

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

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

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

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

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

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

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

    
294
    tpm_tis_abort(s, locty);
295
}
296

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

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

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

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

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

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

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

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

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

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

    
356
    return ret;
357
}
358

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

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

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

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

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

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

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

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

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

    
508
    return val;
509
}
510

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

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

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

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

    
538
    switch (off) {
539
    case TPM_TIS_REG_ACCESS:
540

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

    
546
        active_locty = tis->active_locty;
547

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
822
    tpm_backend_reset(s->be_driver);
823

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

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

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

    
841
    tpm_tis_do_startup_tpm(s);
842
}
843

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

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

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

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

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

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

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

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

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

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

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

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

    
903
    memory_region_del_subregion(get_system_memory(), &s->mmio);
904
    memory_region_destroy(&s->mmio);
905
}
906

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

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

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

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

    
932
type_init(tpm_tis_register)