Statistics
| Branch: | Revision:

root / hw / tpm / tpm_tis.c @ 2c9b15ca

History | View | Annotate | Download (28.9 kB)

1 edff8678 Stefan Berger
/*
2 edff8678 Stefan Berger
 * tpm_tis.c - QEMU's TPM TIS interface emulator
3 edff8678 Stefan Berger
 *
4 edff8678 Stefan Berger
 * Copyright (C) 2006,2010-2013 IBM Corporation
5 edff8678 Stefan Berger
 *
6 edff8678 Stefan Berger
 * Authors:
7 edff8678 Stefan Berger
 *  Stefan Berger <stefanb@us.ibm.com>
8 edff8678 Stefan Berger
 *  David Safford <safford@us.ibm.com>
9 edff8678 Stefan Berger
 *
10 edff8678 Stefan Berger
 * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at>
11 edff8678 Stefan Berger
 *
12 edff8678 Stefan Berger
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
13 edff8678 Stefan Berger
 * See the COPYING file in the top-level directory.
14 edff8678 Stefan Berger
 *
15 edff8678 Stefan Berger
 * Implementation of the TIS interface according to specs found at
16 edff8678 Stefan Berger
 * http://www.trustedcomputinggroup.org. This implementation currently
17 edff8678 Stefan Berger
 * supports version 1.21, revision 1.0.
18 edff8678 Stefan Berger
 * In the developers menu choose the PC Client section then find the TIS
19 edff8678 Stefan Berger
 * specification.
20 edff8678 Stefan Berger
 */
21 edff8678 Stefan Berger
22 dccfcd0e Paolo Bonzini
#include "sysemu/tpm_backend.h"
23 edff8678 Stefan Berger
#include "tpm_int.h"
24 edff8678 Stefan Berger
#include "block/block.h"
25 edff8678 Stefan Berger
#include "exec/address-spaces.h"
26 edff8678 Stefan Berger
#include "hw/hw.h"
27 0d09e41a Paolo Bonzini
#include "hw/i386/pc.h"
28 edff8678 Stefan Berger
#include "hw/pci/pci_ids.h"
29 bdee56f5 Paolo Bonzini
#include "tpm_tis.h"
30 edff8678 Stefan Berger
#include "qemu-common.h"
31 edff8678 Stefan Berger
32 edff8678 Stefan Berger
/*#define DEBUG_TIS */
33 edff8678 Stefan Berger
34 edff8678 Stefan Berger
#ifdef DEBUG_TIS
35 edff8678 Stefan Berger
#define DPRINTF(fmt, ...) \
36 edff8678 Stefan Berger
    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
37 edff8678 Stefan Berger
#else
38 edff8678 Stefan Berger
#define DPRINTF(fmt, ...) \
39 edff8678 Stefan Berger
    do { } while (0)
40 edff8678 Stefan Berger
#endif
41 edff8678 Stefan Berger
42 edff8678 Stefan Berger
/* whether the STS interrupt is supported */
43 edff8678 Stefan Berger
#define RAISE_STS_IRQ
44 edff8678 Stefan Berger
45 edff8678 Stefan Berger
/* tis registers */
46 edff8678 Stefan Berger
#define TPM_TIS_REG_ACCESS                0x00
47 edff8678 Stefan Berger
#define TPM_TIS_REG_INT_ENABLE            0x08
48 edff8678 Stefan Berger
#define TPM_TIS_REG_INT_VECTOR            0x0c
49 edff8678 Stefan Berger
#define TPM_TIS_REG_INT_STATUS            0x10
50 edff8678 Stefan Berger
#define TPM_TIS_REG_INTF_CAPABILITY       0x14
51 edff8678 Stefan Berger
#define TPM_TIS_REG_STS                   0x18
52 edff8678 Stefan Berger
#define TPM_TIS_REG_DATA_FIFO             0x24
53 edff8678 Stefan Berger
#define TPM_TIS_REG_DID_VID               0xf00
54 edff8678 Stefan Berger
#define TPM_TIS_REG_RID                   0xf04
55 edff8678 Stefan Berger
56 8db7c415 Stefan Berger
/* vendor-specific registers */
57 8db7c415 Stefan Berger
#define TPM_TIS_REG_DEBUG                 0xf90
58 8db7c415 Stefan Berger
59 edff8678 Stefan Berger
#define TPM_TIS_STS_VALID                 (1 << 7)
60 edff8678 Stefan Berger
#define TPM_TIS_STS_COMMAND_READY         (1 << 6)
61 edff8678 Stefan Berger
#define TPM_TIS_STS_TPM_GO                (1 << 5)
62 edff8678 Stefan Berger
#define TPM_TIS_STS_DATA_AVAILABLE        (1 << 4)
63 edff8678 Stefan Berger
#define TPM_TIS_STS_EXPECT                (1 << 3)
64 edff8678 Stefan Berger
#define TPM_TIS_STS_RESPONSE_RETRY        (1 << 1)
65 edff8678 Stefan Berger
66 edff8678 Stefan Berger
#define TPM_TIS_BURST_COUNT_SHIFT         8
67 edff8678 Stefan Berger
#define TPM_TIS_BURST_COUNT(X) \
68 edff8678 Stefan Berger
    ((X) << TPM_TIS_BURST_COUNT_SHIFT)
69 edff8678 Stefan Berger
70 edff8678 Stefan Berger
#define TPM_TIS_ACCESS_TPM_REG_VALID_STS  (1 << 7)
71 edff8678 Stefan Berger
#define TPM_TIS_ACCESS_ACTIVE_LOCALITY    (1 << 5)
72 edff8678 Stefan Berger
#define TPM_TIS_ACCESS_BEEN_SEIZED        (1 << 4)
73 edff8678 Stefan Berger
#define TPM_TIS_ACCESS_SEIZE              (1 << 3)
74 edff8678 Stefan Berger
#define TPM_TIS_ACCESS_PENDING_REQUEST    (1 << 2)
75 edff8678 Stefan Berger
#define TPM_TIS_ACCESS_REQUEST_USE        (1 << 1)
76 edff8678 Stefan Berger
#define TPM_TIS_ACCESS_TPM_ESTABLISHMENT  (1 << 0)
77 edff8678 Stefan Berger
78 edff8678 Stefan Berger
#define TPM_TIS_INT_ENABLED               (1 << 31)
79 edff8678 Stefan Berger
#define TPM_TIS_INT_DATA_AVAILABLE        (1 << 0)
80 edff8678 Stefan Berger
#define TPM_TIS_INT_STS_VALID             (1 << 1)
81 edff8678 Stefan Berger
#define TPM_TIS_INT_LOCALITY_CHANGED      (1 << 2)
82 edff8678 Stefan Berger
#define TPM_TIS_INT_COMMAND_READY         (1 << 7)
83 edff8678 Stefan Berger
84 edff8678 Stefan Berger
#define TPM_TIS_INT_POLARITY_MASK         (3 << 3)
85 edff8678 Stefan Berger
#define TPM_TIS_INT_POLARITY_LOW_LEVEL    (1 << 3)
86 edff8678 Stefan Berger
87 edff8678 Stefan Berger
#ifndef RAISE_STS_IRQ
88 edff8678 Stefan Berger
89 edff8678 Stefan Berger
#define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
90 edff8678 Stefan Berger
                                      TPM_TIS_INT_DATA_AVAILABLE   | \
91 edff8678 Stefan Berger
                                      TPM_TIS_INT_COMMAND_READY)
92 edff8678 Stefan Berger
93 edff8678 Stefan Berger
#else
94 edff8678 Stefan Berger
95 edff8678 Stefan Berger
#define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
96 edff8678 Stefan Berger
                                      TPM_TIS_INT_DATA_AVAILABLE   | \
97 edff8678 Stefan Berger
                                      TPM_TIS_INT_STS_VALID | \
98 edff8678 Stefan Berger
                                      TPM_TIS_INT_COMMAND_READY)
99 edff8678 Stefan Berger
100 edff8678 Stefan Berger
#endif
101 edff8678 Stefan Berger
102 edff8678 Stefan Berger
#define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL  (1 << 4) /* support is mandatory */
103 edff8678 Stefan Berger
#define TPM_TIS_CAPABILITIES_SUPPORTED   (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
104 edff8678 Stefan Berger
                                          TPM_TIS_INTERRUPTS_SUPPORTED)
105 edff8678 Stefan Berger
106 edff8678 Stefan Berger
#define TPM_TIS_TPM_DID       0x0001
107 edff8678 Stefan Berger
#define TPM_TIS_TPM_VID       PCI_VENDOR_ID_IBM
108 edff8678 Stefan Berger
#define TPM_TIS_TPM_RID       0x0001
109 edff8678 Stefan Berger
110 edff8678 Stefan Berger
#define TPM_TIS_NO_DATA_BYTE  0xff
111 edff8678 Stefan Berger
112 8db7c415 Stefan Berger
/* local prototypes */
113 8db7c415 Stefan Berger
114 8db7c415 Stefan Berger
static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
115 8db7c415 Stefan Berger
                                  unsigned size);
116 8db7c415 Stefan Berger
117 edff8678 Stefan Berger
/* utility functions */
118 edff8678 Stefan Berger
119 edff8678 Stefan Berger
static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
120 edff8678 Stefan Berger
{
121 edff8678 Stefan Berger
    return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
122 edff8678 Stefan Berger
}
123 edff8678 Stefan Berger
124 edff8678 Stefan Berger
static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb)
125 edff8678 Stefan Berger
{
126 edff8678 Stefan Berger
    return be32_to_cpu(*(uint32_t *)&sb->buffer[2]);
127 edff8678 Stefan Berger
}
128 edff8678 Stefan Berger
129 edff8678 Stefan Berger
static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
130 edff8678 Stefan Berger
{
131 edff8678 Stefan Berger
#ifdef DEBUG_TIS
132 edff8678 Stefan Berger
    uint32_t len, i;
133 edff8678 Stefan Berger
134 edff8678 Stefan Berger
    len = tpm_tis_get_size_from_buffer(sb);
135 edff8678 Stefan Berger
    DPRINTF("tpm_tis: %s length = %d\n", string, len);
136 edff8678 Stefan Berger
    for (i = 0; i < len; i++) {
137 edff8678 Stefan Berger
        if (i && !(i % 16)) {
138 edff8678 Stefan Berger
            DPRINTF("\n");
139 edff8678 Stefan Berger
        }
140 edff8678 Stefan Berger
        DPRINTF("%.2X ", sb->buffer[i]);
141 edff8678 Stefan Berger
    }
142 edff8678 Stefan Berger
    DPRINTF("\n");
143 edff8678 Stefan Berger
#endif
144 edff8678 Stefan Berger
}
145 edff8678 Stefan Berger
146 edff8678 Stefan Berger
/*
147 edff8678 Stefan Berger
 * Send a request to the TPM.
148 edff8678 Stefan Berger
 */
149 edff8678 Stefan Berger
static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
150 edff8678 Stefan Berger
{
151 edff8678 Stefan Berger
    TPMTISEmuState *tis = &s->s.tis;
152 edff8678 Stefan Berger
153 edff8678 Stefan Berger
    tpm_tis_show_buffer(&tis->loc[locty].w_buffer, "tpm_tis: To TPM");
154 edff8678 Stefan Berger
155 edff8678 Stefan Berger
    s->locty_number = locty;
156 edff8678 Stefan Berger
    s->locty_data = &tis->loc[locty];
157 edff8678 Stefan Berger
158 edff8678 Stefan Berger
    /*
159 edff8678 Stefan Berger
     * w_offset serves as length indicator for length of data;
160 edff8678 Stefan Berger
     * it's reset when the response comes back
161 edff8678 Stefan Berger
     */
162 edff8678 Stefan Berger
    tis->loc[locty].state = TPM_TIS_STATE_EXECUTION;
163 edff8678 Stefan Berger
164 8f0605cc Stefan Berger
    tpm_backend_deliver_request(s->be_driver);
165 edff8678 Stefan Berger
}
166 edff8678 Stefan Berger
167 edff8678 Stefan Berger
/* raise an interrupt if allowed */
168 edff8678 Stefan Berger
static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask)
169 edff8678 Stefan Berger
{
170 edff8678 Stefan Berger
    TPMTISEmuState *tis = &s->s.tis;
171 edff8678 Stefan Berger
172 edff8678 Stefan Berger
    if (!TPM_TIS_IS_VALID_LOCTY(locty)) {
173 edff8678 Stefan Berger
        return;
174 edff8678 Stefan Berger
    }
175 edff8678 Stefan Berger
176 edff8678 Stefan Berger
    if ((tis->loc[locty].inte & TPM_TIS_INT_ENABLED) &&
177 edff8678 Stefan Berger
        (tis->loc[locty].inte & irqmask)) {
178 edff8678 Stefan Berger
        DPRINTF("tpm_tis: Raising IRQ for flag %08x\n", irqmask);
179 edff8678 Stefan Berger
        qemu_irq_raise(s->s.tis.irq);
180 edff8678 Stefan Berger
        tis->loc[locty].ints |= irqmask;
181 edff8678 Stefan Berger
    }
182 edff8678 Stefan Berger
}
183 edff8678 Stefan Berger
184 edff8678 Stefan Berger
static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty)
185 edff8678 Stefan Berger
{
186 edff8678 Stefan Berger
    uint8_t l;
187 edff8678 Stefan Berger
188 edff8678 Stefan Berger
    for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
189 edff8678 Stefan Berger
        if (l == locty) {
190 edff8678 Stefan Berger
            continue;
191 edff8678 Stefan Berger
        }
192 edff8678 Stefan Berger
        if ((s->s.tis.loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) {
193 edff8678 Stefan Berger
            return 1;
194 edff8678 Stefan Berger
        }
195 edff8678 Stefan Berger
    }
196 edff8678 Stefan Berger
197 edff8678 Stefan Berger
    return 0;
198 edff8678 Stefan Berger
}
199 edff8678 Stefan Berger
200 edff8678 Stefan Berger
static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
201 edff8678 Stefan Berger
{
202 edff8678 Stefan Berger
    TPMTISEmuState *tis = &s->s.tis;
203 edff8678 Stefan Berger
    bool change = (s->s.tis.active_locty != new_active_locty);
204 edff8678 Stefan Berger
    bool is_seize;
205 edff8678 Stefan Berger
    uint8_t mask;
206 edff8678 Stefan Berger
207 edff8678 Stefan Berger
    if (change && TPM_TIS_IS_VALID_LOCTY(s->s.tis.active_locty)) {
208 edff8678 Stefan Berger
        is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) &&
209 edff8678 Stefan Berger
                   tis->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE;
210 edff8678 Stefan Berger
211 edff8678 Stefan Berger
        if (is_seize) {
212 edff8678 Stefan Berger
            mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY);
213 edff8678 Stefan Berger
        } else {
214 edff8678 Stefan Berger
            mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY|
215 edff8678 Stefan Berger
                     TPM_TIS_ACCESS_REQUEST_USE);
216 edff8678 Stefan Berger
        }
217 edff8678 Stefan Berger
        /* reset flags on the old active locality */
218 edff8678 Stefan Berger
        tis->loc[s->s.tis.active_locty].access &= mask;
219 edff8678 Stefan Berger
220 edff8678 Stefan Berger
        if (is_seize) {
221 edff8678 Stefan Berger
            tis->loc[tis->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED;
222 edff8678 Stefan Berger
        }
223 edff8678 Stefan Berger
    }
224 edff8678 Stefan Berger
225 edff8678 Stefan Berger
    tis->active_locty = new_active_locty;
226 edff8678 Stefan Berger
227 edff8678 Stefan Berger
    DPRINTF("tpm_tis: Active locality is now %d\n", s->s.tis.active_locty);
228 edff8678 Stefan Berger
229 edff8678 Stefan Berger
    if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) {
230 edff8678 Stefan Berger
        /* set flags on the new active locality */
231 edff8678 Stefan Berger
        tis->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY;
232 edff8678 Stefan Berger
        tis->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE |
233 edff8678 Stefan Berger
                                               TPM_TIS_ACCESS_SEIZE);
234 edff8678 Stefan Berger
    }
235 edff8678 Stefan Berger
236 edff8678 Stefan Berger
    if (change) {
237 edff8678 Stefan Berger
        tpm_tis_raise_irq(s, tis->active_locty, TPM_TIS_INT_LOCALITY_CHANGED);
238 edff8678 Stefan Berger
    }
239 edff8678 Stefan Berger
}
240 edff8678 Stefan Berger
241 edff8678 Stefan Berger
/* abort -- this function switches the locality */
242 edff8678 Stefan Berger
static void tpm_tis_abort(TPMState *s, uint8_t locty)
243 edff8678 Stefan Berger
{
244 edff8678 Stefan Berger
    TPMTISEmuState *tis = &s->s.tis;
245 edff8678 Stefan Berger
246 edff8678 Stefan Berger
    tis->loc[locty].r_offset = 0;
247 edff8678 Stefan Berger
    tis->loc[locty].w_offset = 0;
248 edff8678 Stefan Berger
249 edff8678 Stefan Berger
    DPRINTF("tpm_tis: tis_abort: new active locality is %d\n", tis->next_locty);
250 edff8678 Stefan Berger
251 edff8678 Stefan Berger
    /*
252 edff8678 Stefan Berger
     * Need to react differently depending on who's aborting now and
253 edff8678 Stefan Berger
     * which locality will become active afterwards.
254 edff8678 Stefan Berger
     */
255 edff8678 Stefan Berger
    if (tis->aborting_locty == tis->next_locty) {
256 edff8678 Stefan Berger
        tis->loc[tis->aborting_locty].state = TPM_TIS_STATE_READY;
257 edff8678 Stefan Berger
        tis->loc[tis->aborting_locty].sts = TPM_TIS_STS_COMMAND_READY;
258 edff8678 Stefan Berger
        tpm_tis_raise_irq(s, tis->aborting_locty, TPM_TIS_INT_COMMAND_READY);
259 edff8678 Stefan Berger
    }
260 edff8678 Stefan Berger
261 edff8678 Stefan Berger
    /* locality after abort is another one than the current one */
262 edff8678 Stefan Berger
    tpm_tis_new_active_locality(s, tis->next_locty);
263 edff8678 Stefan Berger
264 edff8678 Stefan Berger
    tis->next_locty = TPM_TIS_NO_LOCALITY;
265 edff8678 Stefan Berger
    /* nobody's aborting a command anymore */
266 edff8678 Stefan Berger
    tis->aborting_locty = TPM_TIS_NO_LOCALITY;
267 edff8678 Stefan Berger
}
268 edff8678 Stefan Berger
269 edff8678 Stefan Berger
/* prepare aborting current command */
270 edff8678 Stefan Berger
static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
271 edff8678 Stefan Berger
{
272 edff8678 Stefan Berger
    TPMTISEmuState *tis = &s->s.tis;
273 edff8678 Stefan Berger
    uint8_t busy_locty;
274 edff8678 Stefan Berger
275 edff8678 Stefan Berger
    tis->aborting_locty = locty;
276 edff8678 Stefan Berger
    tis->next_locty = newlocty;  /* locality after successful abort */
277 edff8678 Stefan Berger
278 edff8678 Stefan Berger
    /*
279 edff8678 Stefan Berger
     * only abort a command using an interrupt if currently executing
280 edff8678 Stefan Berger
     * a command AND if there's a valid connection to the vTPM.
281 edff8678 Stefan Berger
     */
282 edff8678 Stefan Berger
    for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) {
283 edff8678 Stefan Berger
        if (tis->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) {
284 edff8678 Stefan Berger
            /*
285 edff8678 Stefan Berger
             * request the backend to cancel. Some backends may not
286 edff8678 Stefan Berger
             * support it
287 edff8678 Stefan Berger
             */
288 8f0605cc Stefan Berger
            tpm_backend_cancel_cmd(s->be_driver);
289 edff8678 Stefan Berger
            return;
290 edff8678 Stefan Berger
        }
291 edff8678 Stefan Berger
    }
292 edff8678 Stefan Berger
293 edff8678 Stefan Berger
    tpm_tis_abort(s, locty);
294 edff8678 Stefan Berger
}
295 edff8678 Stefan Berger
296 edff8678 Stefan Berger
static void tpm_tis_receive_bh(void *opaque)
297 edff8678 Stefan Berger
{
298 edff8678 Stefan Berger
    TPMState *s = opaque;
299 edff8678 Stefan Berger
    TPMTISEmuState *tis = &s->s.tis;
300 edff8678 Stefan Berger
    uint8_t locty = s->locty_number;
301 edff8678 Stefan Berger
302 edff8678 Stefan Berger
    tis->loc[locty].sts = TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE;
303 edff8678 Stefan Berger
    tis->loc[locty].state = TPM_TIS_STATE_COMPLETION;
304 edff8678 Stefan Berger
    tis->loc[locty].r_offset = 0;
305 edff8678 Stefan Berger
    tis->loc[locty].w_offset = 0;
306 edff8678 Stefan Berger
307 edff8678 Stefan Berger
    if (TPM_TIS_IS_VALID_LOCTY(tis->next_locty)) {
308 edff8678 Stefan Berger
        tpm_tis_abort(s, locty);
309 edff8678 Stefan Berger
    }
310 edff8678 Stefan Berger
311 edff8678 Stefan Berger
#ifndef RAISE_STS_IRQ
312 edff8678 Stefan Berger
    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_DATA_AVAILABLE);
313 edff8678 Stefan Berger
#else
314 edff8678 Stefan Berger
    tpm_tis_raise_irq(s, locty,
315 edff8678 Stefan Berger
                      TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
316 edff8678 Stefan Berger
#endif
317 edff8678 Stefan Berger
}
318 edff8678 Stefan Berger
319 edff8678 Stefan Berger
/*
320 edff8678 Stefan Berger
 * Callback from the TPM to indicate that the response was received.
321 edff8678 Stefan Berger
 */
322 edff8678 Stefan Berger
static void tpm_tis_receive_cb(TPMState *s, uint8_t locty)
323 edff8678 Stefan Berger
{
324 edff8678 Stefan Berger
    TPMTISEmuState *tis = &s->s.tis;
325 edff8678 Stefan Berger
326 edff8678 Stefan Berger
    assert(s->locty_number == locty);
327 edff8678 Stefan Berger
328 edff8678 Stefan Berger
    qemu_bh_schedule(tis->bh);
329 edff8678 Stefan Berger
}
330 edff8678 Stefan Berger
331 edff8678 Stefan Berger
/*
332 edff8678 Stefan Berger
 * Read a byte of response data
333 edff8678 Stefan Berger
 */
334 edff8678 Stefan Berger
static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
335 edff8678 Stefan Berger
{
336 edff8678 Stefan Berger
    TPMTISEmuState *tis = &s->s.tis;
337 edff8678 Stefan Berger
    uint32_t ret = TPM_TIS_NO_DATA_BYTE;
338 edff8678 Stefan Berger
    uint16_t len;
339 edff8678 Stefan Berger
340 edff8678 Stefan Berger
    if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
341 edff8678 Stefan Berger
        len = tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
342 edff8678 Stefan Berger
343 edff8678 Stefan Berger
        ret = tis->loc[locty].r_buffer.buffer[tis->loc[locty].r_offset++];
344 edff8678 Stefan Berger
        if (tis->loc[locty].r_offset >= len) {
345 edff8678 Stefan Berger
            /* got last byte */
346 edff8678 Stefan Berger
            tis->loc[locty].sts = TPM_TIS_STS_VALID;
347 edff8678 Stefan Berger
#ifdef RAISE_STS_IRQ
348 edff8678 Stefan Berger
            tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
349 edff8678 Stefan Berger
#endif
350 edff8678 Stefan Berger
        }
351 edff8678 Stefan Berger
        DPRINTF("tpm_tis: tpm_tis_data_read byte 0x%02x   [%d]\n",
352 edff8678 Stefan Berger
                ret, tis->loc[locty].r_offset-1);
353 edff8678 Stefan Berger
    }
354 edff8678 Stefan Berger
355 edff8678 Stefan Berger
    return ret;
356 edff8678 Stefan Berger
}
357 edff8678 Stefan Berger
358 8db7c415 Stefan Berger
#ifdef DEBUG_TIS
359 8db7c415 Stefan Berger
static void tpm_tis_dump_state(void *opaque, hwaddr addr)
360 8db7c415 Stefan Berger
{
361 8db7c415 Stefan Berger
    static const unsigned regs[] = {
362 8db7c415 Stefan Berger
        TPM_TIS_REG_ACCESS,
363 8db7c415 Stefan Berger
        TPM_TIS_REG_INT_ENABLE,
364 8db7c415 Stefan Berger
        TPM_TIS_REG_INT_VECTOR,
365 8db7c415 Stefan Berger
        TPM_TIS_REG_INT_STATUS,
366 8db7c415 Stefan Berger
        TPM_TIS_REG_INTF_CAPABILITY,
367 8db7c415 Stefan Berger
        TPM_TIS_REG_STS,
368 8db7c415 Stefan Berger
        TPM_TIS_REG_DID_VID,
369 8db7c415 Stefan Berger
        TPM_TIS_REG_RID,
370 8db7c415 Stefan Berger
        0xfff};
371 8db7c415 Stefan Berger
    int idx;
372 8db7c415 Stefan Berger
    uint8_t locty = tpm_tis_locality_from_addr(addr);
373 8db7c415 Stefan Berger
    hwaddr base = addr & ~0xfff;
374 8db7c415 Stefan Berger
    TPMState *s = opaque;
375 8db7c415 Stefan Berger
    TPMTISEmuState *tis = &s->s.tis;
376 8db7c415 Stefan Berger
377 8db7c415 Stefan Berger
    DPRINTF("tpm_tis: active locality      : %d\n"
378 8db7c415 Stefan Berger
            "tpm_tis: state of locality %d : %d\n"
379 8db7c415 Stefan Berger
            "tpm_tis: register dump:\n",
380 8db7c415 Stefan Berger
            tis->active_locty,
381 8db7c415 Stefan Berger
            locty, tis->loc[locty].state);
382 8db7c415 Stefan Berger
383 8db7c415 Stefan Berger
    for (idx = 0; regs[idx] != 0xfff; idx++) {
384 8db7c415 Stefan Berger
        DPRINTF("tpm_tis: 0x%04x : 0x%08x\n", regs[idx],
385 8db7c415 Stefan Berger
                (uint32_t)tpm_tis_mmio_read(opaque, base + regs[idx], 4));
386 8db7c415 Stefan Berger
    }
387 8db7c415 Stefan Berger
388 8db7c415 Stefan Berger
    DPRINTF("tpm_tis: read offset   : %d\n"
389 8db7c415 Stefan Berger
            "tpm_tis: result buffer : ",
390 8db7c415 Stefan Berger
            tis->loc[locty].r_offset);
391 8db7c415 Stefan Berger
    for (idx = 0;
392 8db7c415 Stefan Berger
         idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
393 8db7c415 Stefan Berger
         idx++) {
394 8db7c415 Stefan Berger
        DPRINTF("%c%02x%s",
395 8db7c415 Stefan Berger
                tis->loc[locty].r_offset == idx ? '>' : ' ',
396 8db7c415 Stefan Berger
                tis->loc[locty].r_buffer.buffer[idx],
397 8db7c415 Stefan Berger
                ((idx & 0xf) == 0xf) ? "\ntpm_tis:                 " : "");
398 8db7c415 Stefan Berger
    }
399 8db7c415 Stefan Berger
    DPRINTF("\n"
400 8db7c415 Stefan Berger
            "tpm_tis: write offset  : %d\n"
401 8db7c415 Stefan Berger
            "tpm_tis: request buffer: ",
402 8db7c415 Stefan Berger
            tis->loc[locty].w_offset);
403 8db7c415 Stefan Berger
    for (idx = 0;
404 8db7c415 Stefan Berger
         idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
405 8db7c415 Stefan Berger
         idx++) {
406 8db7c415 Stefan Berger
        DPRINTF("%c%02x%s",
407 8db7c415 Stefan Berger
                tis->loc[locty].w_offset == idx ? '>' : ' ',
408 8db7c415 Stefan Berger
                tis->loc[locty].w_buffer.buffer[idx],
409 8db7c415 Stefan Berger
                ((idx & 0xf) == 0xf) ? "\ntpm_tis:                 " : "");
410 8db7c415 Stefan Berger
    }
411 8db7c415 Stefan Berger
    DPRINTF("\n");
412 8db7c415 Stefan Berger
}
413 8db7c415 Stefan Berger
#endif
414 8db7c415 Stefan Berger
415 edff8678 Stefan Berger
/*
416 edff8678 Stefan Berger
 * Read a register of the TIS interface
417 edff8678 Stefan Berger
 * See specs pages 33-63 for description of the registers
418 edff8678 Stefan Berger
 */
419 edff8678 Stefan Berger
static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
420 edff8678 Stefan Berger
                                  unsigned size)
421 edff8678 Stefan Berger
{
422 edff8678 Stefan Berger
    TPMState *s = opaque;
423 edff8678 Stefan Berger
    TPMTISEmuState *tis = &s->s.tis;
424 edff8678 Stefan Berger
    uint16_t offset = addr & 0xffc;
425 edff8678 Stefan Berger
    uint8_t shift = (addr & 0x3) * 8;
426 edff8678 Stefan Berger
    uint32_t val = 0xffffffff;
427 edff8678 Stefan Berger
    uint8_t locty = tpm_tis_locality_from_addr(addr);
428 edff8678 Stefan Berger
    uint32_t avail;
429 edff8678 Stefan Berger
430 8f0605cc Stefan Berger
    if (tpm_backend_had_startup_error(s->be_driver)) {
431 edff8678 Stefan Berger
        return val;
432 edff8678 Stefan Berger
    }
433 edff8678 Stefan Berger
434 edff8678 Stefan Berger
    switch (offset) {
435 edff8678 Stefan Berger
    case TPM_TIS_REG_ACCESS:
436 edff8678 Stefan Berger
        /* never show the SEIZE flag even though we use it internally */
437 edff8678 Stefan Berger
        val = tis->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE;
438 edff8678 Stefan Berger
        /* the pending flag is always calculated */
439 edff8678 Stefan Berger
        if (tpm_tis_check_request_use_except(s, locty)) {
440 edff8678 Stefan Berger
            val |= TPM_TIS_ACCESS_PENDING_REQUEST;
441 edff8678 Stefan Berger
        }
442 8f0605cc Stefan Berger
        val |= !tpm_backend_get_tpm_established_flag(s->be_driver);
443 edff8678 Stefan Berger
        break;
444 edff8678 Stefan Berger
    case TPM_TIS_REG_INT_ENABLE:
445 edff8678 Stefan Berger
        val = tis->loc[locty].inte;
446 edff8678 Stefan Berger
        break;
447 edff8678 Stefan Berger
    case TPM_TIS_REG_INT_VECTOR:
448 edff8678 Stefan Berger
        val = tis->irq_num;
449 edff8678 Stefan Berger
        break;
450 edff8678 Stefan Berger
    case TPM_TIS_REG_INT_STATUS:
451 edff8678 Stefan Berger
        val = tis->loc[locty].ints;
452 edff8678 Stefan Berger
        break;
453 edff8678 Stefan Berger
    case TPM_TIS_REG_INTF_CAPABILITY:
454 edff8678 Stefan Berger
        val = TPM_TIS_CAPABILITIES_SUPPORTED;
455 edff8678 Stefan Berger
        break;
456 edff8678 Stefan Berger
    case TPM_TIS_REG_STS:
457 edff8678 Stefan Berger
        if (tis->active_locty == locty) {
458 edff8678 Stefan Berger
            if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
459 edff8678 Stefan Berger
                val = TPM_TIS_BURST_COUNT(
460 edff8678 Stefan Berger
                       tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer)
461 edff8678 Stefan Berger
                       - tis->loc[locty].r_offset) | tis->loc[locty].sts;
462 edff8678 Stefan Berger
            } else {
463 edff8678 Stefan Berger
                avail = tis->loc[locty].w_buffer.size
464 edff8678 Stefan Berger
                        - tis->loc[locty].w_offset;
465 edff8678 Stefan Berger
                /*
466 edff8678 Stefan Berger
                 * byte-sized reads should not return 0x00 for 0x100
467 edff8678 Stefan Berger
                 * available bytes.
468 edff8678 Stefan Berger
                 */
469 edff8678 Stefan Berger
                if (size == 1 && avail > 0xff) {
470 edff8678 Stefan Berger
                    avail = 0xff;
471 edff8678 Stefan Berger
                }
472 edff8678 Stefan Berger
                val = TPM_TIS_BURST_COUNT(avail) | tis->loc[locty].sts;
473 edff8678 Stefan Berger
            }
474 edff8678 Stefan Berger
        }
475 edff8678 Stefan Berger
        break;
476 edff8678 Stefan Berger
    case TPM_TIS_REG_DATA_FIFO:
477 edff8678 Stefan Berger
        if (tis->active_locty == locty) {
478 edff8678 Stefan Berger
            switch (tis->loc[locty].state) {
479 edff8678 Stefan Berger
            case TPM_TIS_STATE_COMPLETION:
480 edff8678 Stefan Berger
                val = tpm_tis_data_read(s, locty);
481 edff8678 Stefan Berger
                break;
482 edff8678 Stefan Berger
            default:
483 edff8678 Stefan Berger
                val = TPM_TIS_NO_DATA_BYTE;
484 edff8678 Stefan Berger
                break;
485 edff8678 Stefan Berger
            }
486 edff8678 Stefan Berger
        }
487 edff8678 Stefan Berger
        break;
488 edff8678 Stefan Berger
    case TPM_TIS_REG_DID_VID:
489 edff8678 Stefan Berger
        val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
490 edff8678 Stefan Berger
        break;
491 edff8678 Stefan Berger
    case TPM_TIS_REG_RID:
492 edff8678 Stefan Berger
        val = TPM_TIS_TPM_RID;
493 edff8678 Stefan Berger
        break;
494 8db7c415 Stefan Berger
#ifdef DEBUG_TIS
495 8db7c415 Stefan Berger
    case TPM_TIS_REG_DEBUG:
496 8db7c415 Stefan Berger
        tpm_tis_dump_state(opaque, addr);
497 8db7c415 Stefan Berger
        break;
498 8db7c415 Stefan Berger
#endif
499 edff8678 Stefan Berger
    }
500 edff8678 Stefan Berger
501 edff8678 Stefan Berger
    if (shift) {
502 edff8678 Stefan Berger
        val >>= shift;
503 edff8678 Stefan Berger
    }
504 edff8678 Stefan Berger
505 edff8678 Stefan Berger
    DPRINTF("tpm_tis:  read.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);
506 edff8678 Stefan Berger
507 edff8678 Stefan Berger
    return val;
508 edff8678 Stefan Berger
}
509 edff8678 Stefan Berger
510 edff8678 Stefan Berger
/*
511 edff8678 Stefan Berger
 * Write a value to a register of the TIS interface
512 edff8678 Stefan Berger
 * See specs pages 33-63 for description of the registers
513 edff8678 Stefan Berger
 */
514 edff8678 Stefan Berger
static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
515 edff8678 Stefan Berger
                                      uint64_t val, unsigned size,
516 edff8678 Stefan Berger
                                      bool hw_access)
517 edff8678 Stefan Berger
{
518 edff8678 Stefan Berger
    TPMState *s = opaque;
519 edff8678 Stefan Berger
    TPMTISEmuState *tis = &s->s.tis;
520 edff8678 Stefan Berger
    uint16_t off = addr & 0xfff;
521 edff8678 Stefan Berger
    uint8_t locty = tpm_tis_locality_from_addr(addr);
522 edff8678 Stefan Berger
    uint8_t active_locty, l;
523 edff8678 Stefan Berger
    int c, set_new_locty = 1;
524 edff8678 Stefan Berger
    uint16_t len;
525 edff8678 Stefan Berger
526 edff8678 Stefan Berger
    DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);
527 edff8678 Stefan Berger
528 edff8678 Stefan Berger
    if (locty == 4 && !hw_access) {
529 edff8678 Stefan Berger
        DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n");
530 edff8678 Stefan Berger
        return;
531 edff8678 Stefan Berger
    }
532 edff8678 Stefan Berger
533 8f0605cc Stefan Berger
    if (tpm_backend_had_startup_error(s->be_driver)) {
534 edff8678 Stefan Berger
        return;
535 edff8678 Stefan Berger
    }
536 edff8678 Stefan Berger
537 edff8678 Stefan Berger
    switch (off) {
538 edff8678 Stefan Berger
    case TPM_TIS_REG_ACCESS:
539 edff8678 Stefan Berger
540 edff8678 Stefan Berger
        if ((val & TPM_TIS_ACCESS_SEIZE)) {
541 edff8678 Stefan Berger
            val &= ~(TPM_TIS_ACCESS_REQUEST_USE |
542 edff8678 Stefan Berger
                     TPM_TIS_ACCESS_ACTIVE_LOCALITY);
543 edff8678 Stefan Berger
        }
544 edff8678 Stefan Berger
545 edff8678 Stefan Berger
        active_locty = tis->active_locty;
546 edff8678 Stefan Berger
547 edff8678 Stefan Berger
        if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {
548 edff8678 Stefan Berger
            /* give up locality if currently owned */
549 edff8678 Stefan Berger
            if (tis->active_locty == locty) {
550 edff8678 Stefan Berger
                DPRINTF("tpm_tis: Releasing locality %d\n", locty);
551 edff8678 Stefan Berger
552 edff8678 Stefan Berger
                uint8_t newlocty = TPM_TIS_NO_LOCALITY;
553 edff8678 Stefan Berger
                /* anybody wants the locality ? */
554 edff8678 Stefan Berger
                for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {
555 edff8678 Stefan Berger
                    if ((tis->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {
556 edff8678 Stefan Berger
                        DPRINTF("tpm_tis: Locality %d requests use.\n", c);
557 edff8678 Stefan Berger
                        newlocty = c;
558 edff8678 Stefan Berger
                        break;
559 edff8678 Stefan Berger
                    }
560 edff8678 Stefan Berger
                }
561 edff8678 Stefan Berger
                DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "
562 edff8678 Stefan Berger
                        "Next active locality: %d\n",
563 edff8678 Stefan Berger
                        newlocty);
564 edff8678 Stefan Berger
565 edff8678 Stefan Berger
                if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {
566 edff8678 Stefan Berger
                    set_new_locty = 0;
567 edff8678 Stefan Berger
                    tpm_tis_prep_abort(s, locty, newlocty);
568 edff8678 Stefan Berger
                } else {
569 edff8678 Stefan Berger
                    active_locty = TPM_TIS_NO_LOCALITY;
570 edff8678 Stefan Berger
                }
571 edff8678 Stefan Berger
            } else {
572 edff8678 Stefan Berger
                /* not currently the owner; clear a pending request */
573 edff8678 Stefan Berger
                tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;
574 edff8678 Stefan Berger
            }
575 edff8678 Stefan Berger
        }
576 edff8678 Stefan Berger
577 edff8678 Stefan Berger
        if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {
578 edff8678 Stefan Berger
            tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;
579 edff8678 Stefan Berger
        }
580 edff8678 Stefan Berger
581 edff8678 Stefan Berger
        if ((val & TPM_TIS_ACCESS_SEIZE)) {
582 edff8678 Stefan Berger
            /*
583 edff8678 Stefan Berger
             * allow seize if a locality is active and the requesting
584 edff8678 Stefan Berger
             * locality is higher than the one that's active
585 edff8678 Stefan Berger
             * OR
586 edff8678 Stefan Berger
             * allow seize for requesting locality if no locality is
587 edff8678 Stefan Berger
             * active
588 edff8678 Stefan Berger
             */
589 edff8678 Stefan Berger
            while ((TPM_TIS_IS_VALID_LOCTY(tis->active_locty) &&
590 edff8678 Stefan Berger
                    locty > tis->active_locty) ||
591 edff8678 Stefan Berger
                    !TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
592 edff8678 Stefan Berger
                bool higher_seize = FALSE;
593 edff8678 Stefan Berger
594 edff8678 Stefan Berger
                /* already a pending SEIZE ? */
595 edff8678 Stefan Berger
                if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {
596 edff8678 Stefan Berger
                    break;
597 edff8678 Stefan Berger
                }
598 edff8678 Stefan Berger
599 edff8678 Stefan Berger
                /* check for ongoing seize by a higher locality */
600 edff8678 Stefan Berger
                for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {
601 edff8678 Stefan Berger
                    if ((tis->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {
602 edff8678 Stefan Berger
                        higher_seize = TRUE;
603 edff8678 Stefan Berger
                        break;
604 edff8678 Stefan Berger
                    }
605 edff8678 Stefan Berger
                }
606 edff8678 Stefan Berger
607 edff8678 Stefan Berger
                if (higher_seize) {
608 edff8678 Stefan Berger
                    break;
609 edff8678 Stefan Berger
                }
610 edff8678 Stefan Berger
611 edff8678 Stefan Berger
                /* cancel any seize by a lower locality */
612 edff8678 Stefan Berger
                for (l = 0; l < locty - 1; l++) {
613 edff8678 Stefan Berger
                    tis->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;
614 edff8678 Stefan Berger
                }
615 edff8678 Stefan Berger
616 edff8678 Stefan Berger
                tis->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;
617 edff8678 Stefan Berger
                DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: "
618 edff8678 Stefan Berger
                        "Locality %d seized from locality %d\n",
619 edff8678 Stefan Berger
                        locty, tis->active_locty);
620 edff8678 Stefan Berger
                DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n");
621 edff8678 Stefan Berger
                set_new_locty = 0;
622 edff8678 Stefan Berger
                tpm_tis_prep_abort(s, tis->active_locty, locty);
623 edff8678 Stefan Berger
                break;
624 edff8678 Stefan Berger
            }
625 edff8678 Stefan Berger
        }
626 edff8678 Stefan Berger
627 edff8678 Stefan Berger
        if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {
628 edff8678 Stefan Berger
            if (tis->active_locty != locty) {
629 edff8678 Stefan Berger
                if (TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
630 edff8678 Stefan Berger
                    tis->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;
631 edff8678 Stefan Berger
                } else {
632 edff8678 Stefan Berger
                    /* no locality active -> make this one active now */
633 edff8678 Stefan Berger
                    active_locty = locty;
634 edff8678 Stefan Berger
                }
635 edff8678 Stefan Berger
            }
636 edff8678 Stefan Berger
        }
637 edff8678 Stefan Berger
638 edff8678 Stefan Berger
        if (set_new_locty) {
639 edff8678 Stefan Berger
            tpm_tis_new_active_locality(s, active_locty);
640 edff8678 Stefan Berger
        }
641 edff8678 Stefan Berger
642 edff8678 Stefan Berger
        break;
643 edff8678 Stefan Berger
    case TPM_TIS_REG_INT_ENABLE:
644 edff8678 Stefan Berger
        if (tis->active_locty != locty) {
645 edff8678 Stefan Berger
            break;
646 edff8678 Stefan Berger
        }
647 edff8678 Stefan Berger
648 edff8678 Stefan Berger
        tis->loc[locty].inte = (val & (TPM_TIS_INT_ENABLED |
649 edff8678 Stefan Berger
                                       TPM_TIS_INT_POLARITY_MASK |
650 edff8678 Stefan Berger
                                       TPM_TIS_INTERRUPTS_SUPPORTED));
651 edff8678 Stefan Berger
        break;
652 edff8678 Stefan Berger
    case TPM_TIS_REG_INT_VECTOR:
653 edff8678 Stefan Berger
        /* hard wired -- ignore */
654 edff8678 Stefan Berger
        break;
655 edff8678 Stefan Berger
    case TPM_TIS_REG_INT_STATUS:
656 edff8678 Stefan Berger
        if (tis->active_locty != locty) {
657 edff8678 Stefan Berger
            break;
658 edff8678 Stefan Berger
        }
659 edff8678 Stefan Berger
660 edff8678 Stefan Berger
        /* clearing of interrupt flags */
661 edff8678 Stefan Berger
        if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&
662 edff8678 Stefan Berger
            (tis->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {
663 edff8678 Stefan Berger
            tis->loc[locty].ints &= ~val;
664 edff8678 Stefan Berger
            if (tis->loc[locty].ints == 0) {
665 edff8678 Stefan Berger
                qemu_irq_lower(tis->irq);
666 edff8678 Stefan Berger
                DPRINTF("tpm_tis: Lowering IRQ\n");
667 edff8678 Stefan Berger
            }
668 edff8678 Stefan Berger
        }
669 edff8678 Stefan Berger
        tis->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);
670 edff8678 Stefan Berger
        break;
671 edff8678 Stefan Berger
    case TPM_TIS_REG_STS:
672 edff8678 Stefan Berger
        if (tis->active_locty != locty) {
673 edff8678 Stefan Berger
            break;
674 edff8678 Stefan Berger
        }
675 edff8678 Stefan Berger
676 edff8678 Stefan Berger
        val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
677 edff8678 Stefan Berger
                TPM_TIS_STS_RESPONSE_RETRY);
678 edff8678 Stefan Berger
679 edff8678 Stefan Berger
        if (val == TPM_TIS_STS_COMMAND_READY) {
680 edff8678 Stefan Berger
            switch (tis->loc[locty].state) {
681 edff8678 Stefan Berger
682 edff8678 Stefan Berger
            case TPM_TIS_STATE_READY:
683 edff8678 Stefan Berger
                tis->loc[locty].w_offset = 0;
684 edff8678 Stefan Berger
                tis->loc[locty].r_offset = 0;
685 edff8678 Stefan Berger
            break;
686 edff8678 Stefan Berger
687 edff8678 Stefan Berger
            case TPM_TIS_STATE_IDLE:
688 edff8678 Stefan Berger
                tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY;
689 edff8678 Stefan Berger
                tis->loc[locty].state = TPM_TIS_STATE_READY;
690 edff8678 Stefan Berger
                tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
691 edff8678 Stefan Berger
            break;
692 edff8678 Stefan Berger
693 edff8678 Stefan Berger
            case TPM_TIS_STATE_EXECUTION:
694 edff8678 Stefan Berger
            case TPM_TIS_STATE_RECEPTION:
695 edff8678 Stefan Berger
                /* abort currently running command */
696 edff8678 Stefan Berger
                DPRINTF("tpm_tis: %s: Initiating abort.\n",
697 edff8678 Stefan Berger
                        __func__);
698 edff8678 Stefan Berger
                tpm_tis_prep_abort(s, locty, locty);
699 edff8678 Stefan Berger
            break;
700 edff8678 Stefan Berger
701 edff8678 Stefan Berger
            case TPM_TIS_STATE_COMPLETION:
702 edff8678 Stefan Berger
                tis->loc[locty].w_offset = 0;
703 edff8678 Stefan Berger
                tis->loc[locty].r_offset = 0;
704 edff8678 Stefan Berger
                /* shortcut to ready state with C/R set */
705 edff8678 Stefan Berger
                tis->loc[locty].state = TPM_TIS_STATE_READY;
706 edff8678 Stefan Berger
                if (!(tis->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {
707 edff8678 Stefan Berger
                    tis->loc[locty].sts   = TPM_TIS_STS_COMMAND_READY;
708 edff8678 Stefan Berger
                    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
709 edff8678 Stefan Berger
                }
710 edff8678 Stefan Berger
                tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);
711 edff8678 Stefan Berger
            break;
712 edff8678 Stefan Berger
713 edff8678 Stefan Berger
            }
714 edff8678 Stefan Berger
        } else if (val == TPM_TIS_STS_TPM_GO) {
715 edff8678 Stefan Berger
            switch (tis->loc[locty].state) {
716 edff8678 Stefan Berger
            case TPM_TIS_STATE_RECEPTION:
717 edff8678 Stefan Berger
                if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {
718 edff8678 Stefan Berger
                    tpm_tis_tpm_send(s, locty);
719 edff8678 Stefan Berger
                }
720 edff8678 Stefan Berger
                break;
721 edff8678 Stefan Berger
            default:
722 edff8678 Stefan Berger
                /* ignore */
723 edff8678 Stefan Berger
                break;
724 edff8678 Stefan Berger
            }
725 edff8678 Stefan Berger
        } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {
726 edff8678 Stefan Berger
            switch (tis->loc[locty].state) {
727 edff8678 Stefan Berger
            case TPM_TIS_STATE_COMPLETION:
728 edff8678 Stefan Berger
                tis->loc[locty].r_offset = 0;
729 edff8678 Stefan Berger
                tis->loc[locty].sts = TPM_TIS_STS_VALID |
730 edff8678 Stefan Berger
                                      TPM_TIS_STS_DATA_AVAILABLE;
731 edff8678 Stefan Berger
                break;
732 edff8678 Stefan Berger
            default:
733 edff8678 Stefan Berger
                /* ignore */
734 edff8678 Stefan Berger
                break;
735 edff8678 Stefan Berger
            }
736 edff8678 Stefan Berger
        }
737 edff8678 Stefan Berger
        break;
738 edff8678 Stefan Berger
    case TPM_TIS_REG_DATA_FIFO:
739 edff8678 Stefan Berger
        /* data fifo */
740 edff8678 Stefan Berger
        if (tis->active_locty != locty) {
741 edff8678 Stefan Berger
            break;
742 edff8678 Stefan Berger
        }
743 edff8678 Stefan Berger
744 edff8678 Stefan Berger
        if (tis->loc[locty].state == TPM_TIS_STATE_IDLE ||
745 edff8678 Stefan Berger
            tis->loc[locty].state == TPM_TIS_STATE_EXECUTION ||
746 edff8678 Stefan Berger
            tis->loc[locty].state == TPM_TIS_STATE_COMPLETION) {
747 edff8678 Stefan Berger
            /* drop the byte */
748 edff8678 Stefan Berger
        } else {
749 edff8678 Stefan Berger
            DPRINTF("tpm_tis: Byte to send to TPM: %02x\n", (uint8_t)val);
750 edff8678 Stefan Berger
            if (tis->loc[locty].state == TPM_TIS_STATE_READY) {
751 edff8678 Stefan Berger
                tis->loc[locty].state = TPM_TIS_STATE_RECEPTION;
752 edff8678 Stefan Berger
                tis->loc[locty].sts = TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID;
753 edff8678 Stefan Berger
            }
754 edff8678 Stefan Berger
755 edff8678 Stefan Berger
            if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
756 edff8678 Stefan Berger
                if (tis->loc[locty].w_offset < tis->loc[locty].w_buffer.size) {
757 edff8678 Stefan Berger
                    tis->loc[locty].w_buffer.
758 edff8678 Stefan Berger
                        buffer[tis->loc[locty].w_offset++] = (uint8_t)val;
759 edff8678 Stefan Berger
                } else {
760 edff8678 Stefan Berger
                    tis->loc[locty].sts = TPM_TIS_STS_VALID;
761 edff8678 Stefan Berger
                }
762 edff8678 Stefan Berger
            }
763 edff8678 Stefan Berger
764 edff8678 Stefan Berger
            /* check for complete packet */
765 edff8678 Stefan Berger
            if (tis->loc[locty].w_offset > 5 &&
766 edff8678 Stefan Berger
                (tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
767 edff8678 Stefan Berger
                /* we have a packet length - see if we have all of it */
768 edff8678 Stefan Berger
#ifdef RAISE_STS_IRQ
769 edff8678 Stefan Berger
                bool needIrq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID);
770 edff8678 Stefan Berger
#endif
771 edff8678 Stefan Berger
                len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
772 edff8678 Stefan Berger
                if (len > tis->loc[locty].w_offset) {
773 edff8678 Stefan Berger
                    tis->loc[locty].sts = TPM_TIS_STS_EXPECT |
774 edff8678 Stefan Berger
                                          TPM_TIS_STS_VALID;
775 edff8678 Stefan Berger
                } else {
776 edff8678 Stefan Berger
                    /* packet complete */
777 edff8678 Stefan Berger
                    tis->loc[locty].sts = TPM_TIS_STS_VALID;
778 edff8678 Stefan Berger
                }
779 edff8678 Stefan Berger
#ifdef RAISE_STS_IRQ
780 edff8678 Stefan Berger
                if (needIrq) {
781 edff8678 Stefan Berger
                    tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
782 edff8678 Stefan Berger
                }
783 edff8678 Stefan Berger
#endif
784 edff8678 Stefan Berger
            }
785 edff8678 Stefan Berger
        }
786 edff8678 Stefan Berger
        break;
787 edff8678 Stefan Berger
    }
788 edff8678 Stefan Berger
}
789 edff8678 Stefan Berger
790 edff8678 Stefan Berger
static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
791 edff8678 Stefan Berger
                               uint64_t val, unsigned size)
792 edff8678 Stefan Berger
{
793 edff8678 Stefan Berger
    return tpm_tis_mmio_write_intern(opaque, addr, val, size, false);
794 edff8678 Stefan Berger
}
795 edff8678 Stefan Berger
796 edff8678 Stefan Berger
static const MemoryRegionOps tpm_tis_memory_ops = {
797 edff8678 Stefan Berger
    .read = tpm_tis_mmio_read,
798 edff8678 Stefan Berger
    .write = tpm_tis_mmio_write,
799 edff8678 Stefan Berger
    .endianness = DEVICE_LITTLE_ENDIAN,
800 edff8678 Stefan Berger
    .valid = {
801 edff8678 Stefan Berger
        .min_access_size = 1,
802 edff8678 Stefan Berger
        .max_access_size = 4,
803 edff8678 Stefan Berger
    },
804 edff8678 Stefan Berger
};
805 edff8678 Stefan Berger
806 edff8678 Stefan Berger
static int tpm_tis_do_startup_tpm(TPMState *s)
807 edff8678 Stefan Berger
{
808 8f0605cc Stefan Berger
    return tpm_backend_startup_tpm(s->be_driver);
809 edff8678 Stefan Berger
}
810 edff8678 Stefan Berger
811 edff8678 Stefan Berger
/*
812 edff8678 Stefan Berger
 * This function is called when the machine starts, resets or due to
813 edff8678 Stefan Berger
 * S3 resume.
814 edff8678 Stefan Berger
 */
815 edff8678 Stefan Berger
static void tpm_tis_reset(DeviceState *dev)
816 edff8678 Stefan Berger
{
817 edff8678 Stefan Berger
    TPMState *s = TPM(dev);
818 edff8678 Stefan Berger
    TPMTISEmuState *tis = &s->s.tis;
819 edff8678 Stefan Berger
    int c;
820 edff8678 Stefan Berger
821 8f0605cc Stefan Berger
    tpm_backend_reset(s->be_driver);
822 edff8678 Stefan Berger
823 edff8678 Stefan Berger
    tis->active_locty = TPM_TIS_NO_LOCALITY;
824 edff8678 Stefan Berger
    tis->next_locty = TPM_TIS_NO_LOCALITY;
825 edff8678 Stefan Berger
    tis->aborting_locty = TPM_TIS_NO_LOCALITY;
826 edff8678 Stefan Berger
827 edff8678 Stefan Berger
    for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
828 edff8678 Stefan Berger
        tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
829 edff8678 Stefan Berger
        tis->loc[c].sts = 0;
830 edff8678 Stefan Berger
        tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
831 edff8678 Stefan Berger
        tis->loc[c].ints = 0;
832 edff8678 Stefan Berger
        tis->loc[c].state = TPM_TIS_STATE_IDLE;
833 edff8678 Stefan Berger
834 edff8678 Stefan Berger
        tis->loc[c].w_offset = 0;
835 8f0605cc Stefan Berger
        tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].w_buffer);
836 edff8678 Stefan Berger
        tis->loc[c].r_offset = 0;
837 8f0605cc Stefan Berger
        tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].r_buffer);
838 edff8678 Stefan Berger
    }
839 edff8678 Stefan Berger
840 edff8678 Stefan Berger
    tpm_tis_do_startup_tpm(s);
841 edff8678 Stefan Berger
}
842 edff8678 Stefan Berger
843 edff8678 Stefan Berger
static const VMStateDescription vmstate_tpm_tis = {
844 edff8678 Stefan Berger
    .name = "tpm",
845 edff8678 Stefan Berger
    .unmigratable = 1,
846 edff8678 Stefan Berger
};
847 edff8678 Stefan Berger
848 edff8678 Stefan Berger
static Property tpm_tis_properties[] = {
849 edff8678 Stefan Berger
    DEFINE_PROP_UINT32("irq", TPMState,
850 edff8678 Stefan Berger
                       s.tis.irq_num, TPM_TIS_IRQ),
851 edff8678 Stefan Berger
    DEFINE_PROP_STRING("tpmdev", TPMState, backend),
852 edff8678 Stefan Berger
    DEFINE_PROP_END_OF_LIST(),
853 edff8678 Stefan Berger
};
854 edff8678 Stefan Berger
855 edff8678 Stefan Berger
static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
856 edff8678 Stefan Berger
{
857 edff8678 Stefan Berger
    TPMState *s = TPM(dev);
858 edff8678 Stefan Berger
    TPMTISEmuState *tis = &s->s.tis;
859 edff8678 Stefan Berger
860 edff8678 Stefan Berger
    s->be_driver = qemu_find_tpm(s->backend);
861 edff8678 Stefan Berger
    if (!s->be_driver) {
862 edff8678 Stefan Berger
        error_setg(errp, "tpm_tis: backend driver with id %s could not be "
863 edff8678 Stefan Berger
                   "found", s->backend);
864 edff8678 Stefan Berger
        return;
865 edff8678 Stefan Berger
    }
866 edff8678 Stefan Berger
867 edff8678 Stefan Berger
    s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
868 edff8678 Stefan Berger
869 8f0605cc Stefan Berger
    if (tpm_backend_init(s->be_driver, s, tpm_tis_receive_cb)) {
870 edff8678 Stefan Berger
        error_setg(errp, "tpm_tis: backend driver with id %s could not be "
871 edff8678 Stefan Berger
                   "initialized", s->backend);
872 edff8678 Stefan Berger
        return;
873 edff8678 Stefan Berger
    }
874 edff8678 Stefan Berger
875 edff8678 Stefan Berger
    if (tis->irq_num > 15) {
876 edff8678 Stefan Berger
        error_setg(errp, "tpm_tis: IRQ %d for TPM TIS is outside valid range "
877 edff8678 Stefan Berger
                   "of 0 to 15.\n", tis->irq_num);
878 edff8678 Stefan Berger
        return;
879 edff8678 Stefan Berger
    }
880 edff8678 Stefan Berger
881 edff8678 Stefan Berger
    tis->bh = qemu_bh_new(tpm_tis_receive_bh, s);
882 edff8678 Stefan Berger
883 edff8678 Stefan Berger
    isa_init_irq(&s->busdev, &tis->irq, tis->irq_num);
884 edff8678 Stefan Berger
}
885 edff8678 Stefan Berger
886 edff8678 Stefan Berger
static void tpm_tis_initfn(Object *obj)
887 edff8678 Stefan Berger
{
888 edff8678 Stefan Berger
    ISADevice *dev = ISA_DEVICE(obj);
889 edff8678 Stefan Berger
    TPMState *s = TPM(obj);
890 edff8678 Stefan Berger
891 2c9b15ca Paolo Bonzini
    memory_region_init_io(&s->mmio, NULL, &tpm_tis_memory_ops, s, "tpm-tis-mmio",
892 edff8678 Stefan Berger
                          TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
893 edff8678 Stefan Berger
    memory_region_add_subregion(isa_address_space(dev), TPM_TIS_ADDR_BASE,
894 edff8678 Stefan Berger
                                &s->mmio);
895 edff8678 Stefan Berger
}
896 edff8678 Stefan Berger
897 edff8678 Stefan Berger
static void tpm_tis_uninitfn(Object *obj)
898 edff8678 Stefan Berger
{
899 edff8678 Stefan Berger
    TPMState *s = TPM(obj);
900 edff8678 Stefan Berger
901 edff8678 Stefan Berger
    memory_region_del_subregion(get_system_memory(), &s->mmio);
902 edff8678 Stefan Berger
    memory_region_destroy(&s->mmio);
903 edff8678 Stefan Berger
}
904 edff8678 Stefan Berger
905 edff8678 Stefan Berger
static void tpm_tis_class_init(ObjectClass *klass, void *data)
906 edff8678 Stefan Berger
{
907 edff8678 Stefan Berger
    DeviceClass *dc = DEVICE_CLASS(klass);
908 edff8678 Stefan Berger
909 edff8678 Stefan Berger
    dc->realize = tpm_tis_realizefn;
910 edff8678 Stefan Berger
    dc->props = tpm_tis_properties;
911 edff8678 Stefan Berger
    dc->reset = tpm_tis_reset;
912 edff8678 Stefan Berger
    dc->vmsd  = &vmstate_tpm_tis;
913 edff8678 Stefan Berger
}
914 edff8678 Stefan Berger
915 edff8678 Stefan Berger
static const TypeInfo tpm_tis_info = {
916 edff8678 Stefan Berger
    .name = TYPE_TPM_TIS,
917 edff8678 Stefan Berger
    .parent = TYPE_ISA_DEVICE,
918 edff8678 Stefan Berger
    .instance_size = sizeof(TPMState),
919 edff8678 Stefan Berger
    .instance_init = tpm_tis_initfn,
920 edff8678 Stefan Berger
    .instance_finalize = tpm_tis_uninitfn,
921 edff8678 Stefan Berger
    .class_init  = tpm_tis_class_init,
922 edff8678 Stefan Berger
};
923 edff8678 Stefan Berger
924 edff8678 Stefan Berger
static void tpm_tis_register(void)
925 edff8678 Stefan Berger
{
926 edff8678 Stefan Berger
    type_register_static(&tpm_tis_info);
927 edff8678 Stefan Berger
    tpm_register_model(TPM_MODEL_TPM_TIS);
928 edff8678 Stefan Berger
}
929 edff8678 Stefan Berger
930 edff8678 Stefan Berger
type_init(tpm_tis_register)