qemu

Форк
0
/
tpm_crb.c 
352 строки · 9.8 Кб
1
/*
2
 * tpm_crb.c - QEMU's TPM CRB interface emulator
3
 *
4
 * Copyright (c) 2018 Red Hat, Inc.
5
 *
6
 * Authors:
7
 *   Marc-André Lureau <marcandre.lureau@redhat.com>
8
 *
9
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10
 * See the COPYING file in the top-level directory.
11
 *
12
 * tpm_crb is a device for TPM 2.0 Command Response Buffer (CRB) Interface
13
 * as defined in TCG PC Client Platform TPM Profile (PTP) Specification
14
 * Family “2.0” Level 00 Revision 01.03 v22
15
 */
16

17
#include "qemu/osdep.h"
18

19
#include "qemu/module.h"
20
#include "qapi/error.h"
21
#include "exec/address-spaces.h"
22
#include "hw/qdev-properties.h"
23
#include "hw/pci/pci_ids.h"
24
#include "hw/acpi/tpm.h"
25
#include "migration/vmstate.h"
26
#include "sysemu/tpm_backend.h"
27
#include "sysemu/tpm_util.h"
28
#include "sysemu/reset.h"
29
#include "sysemu/xen.h"
30
#include "tpm_prop.h"
31
#include "tpm_ppi.h"
32
#include "trace.h"
33
#include "qom/object.h"
34

35
struct CRBState {
36
    DeviceState parent_obj;
37

38
    TPMBackend *tpmbe;
39
    TPMBackendCmd cmd;
40
    uint32_t regs[TPM_CRB_R_MAX];
41
    MemoryRegion mmio;
42
    MemoryRegion cmdmem;
43

44
    size_t be_buffer_size;
45

46
    bool ppi_enabled;
47
    TPMPPI ppi;
48
};
49
typedef struct CRBState CRBState;
50

51
DECLARE_INSTANCE_CHECKER(CRBState, CRB,
52
                         TYPE_TPM_CRB)
53

54
#define CRB_INTF_TYPE_CRB_ACTIVE 0b1
55
#define CRB_INTF_VERSION_CRB 0b1
56
#define CRB_INTF_CAP_LOCALITY_0_ONLY 0b0
57
#define CRB_INTF_CAP_IDLE_FAST 0b0
58
#define CRB_INTF_CAP_XFER_SIZE_64 0b11
59
#define CRB_INTF_CAP_FIFO_NOT_SUPPORTED 0b0
60
#define CRB_INTF_CAP_CRB_SUPPORTED 0b1
61
#define CRB_INTF_IF_SELECTOR_CRB 0b1
62

63
#define CRB_CTRL_CMD_SIZE (TPM_CRB_ADDR_SIZE - A_CRB_DATA_BUFFER)
64

65
enum crb_loc_ctrl {
66
    CRB_LOC_CTRL_REQUEST_ACCESS = BIT(0),
67
    CRB_LOC_CTRL_RELINQUISH = BIT(1),
68
    CRB_LOC_CTRL_SEIZE = BIT(2),
69
    CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT = BIT(3),
70
};
71

72
enum crb_ctrl_req {
73
    CRB_CTRL_REQ_CMD_READY = BIT(0),
74
    CRB_CTRL_REQ_GO_IDLE = BIT(1),
75
};
76

77
enum crb_start {
78
    CRB_START_INVOKE = BIT(0),
79
};
80

81
enum crb_cancel {
82
    CRB_CANCEL_INVOKE = BIT(0),
83
};
84

85
#define TPM_CRB_NO_LOCALITY 0xff
86

87
static uint64_t tpm_crb_mmio_read(void *opaque, hwaddr addr,
88
                                  unsigned size)
89
{
90
    CRBState *s = CRB(opaque);
91
    void *regs = (void *)&s->regs + (addr & ~3);
92
    unsigned offset = addr & 3;
93
    uint32_t val = *(uint32_t *)regs >> (8 * offset);
94

95
    switch (addr) {
96
    case A_CRB_LOC_STATE:
97
        val |= !tpm_backend_get_tpm_established_flag(s->tpmbe);
98
        break;
99
    }
100

101
    trace_tpm_crb_mmio_read(addr, size, val);
102

103
    return val;
104
}
105

106
static uint8_t tpm_crb_get_active_locty(CRBState *s)
107
{
108
    if (!ARRAY_FIELD_EX32(s->regs, CRB_LOC_STATE, locAssigned)) {
109
        return TPM_CRB_NO_LOCALITY;
110
    }
111
    return ARRAY_FIELD_EX32(s->regs, CRB_LOC_STATE, activeLocality);
112
}
113

114
static void tpm_crb_mmio_write(void *opaque, hwaddr addr,
115
                               uint64_t val, unsigned size)
116
{
117
    CRBState *s = CRB(opaque);
118
    uint8_t locty =  addr >> 12;
119

120
    trace_tpm_crb_mmio_write(addr, size, val);
121

122
    switch (addr) {
123
    case A_CRB_CTRL_REQ:
124
        switch (val) {
125
        case CRB_CTRL_REQ_CMD_READY:
126
            ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS,
127
                             tpmIdle, 0);
128
            break;
129
        case CRB_CTRL_REQ_GO_IDLE:
130
            ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS,
131
                             tpmIdle, 1);
132
            break;
133
        }
134
        break;
135
    case A_CRB_CTRL_CANCEL:
136
        if (val == CRB_CANCEL_INVOKE &&
137
            s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE) {
138
            tpm_backend_cancel_cmd(s->tpmbe);
139
        }
140
        break;
141
    case A_CRB_CTRL_START:
142
        if (val == CRB_START_INVOKE &&
143
            !(s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE) &&
144
            tpm_crb_get_active_locty(s) == locty) {
145
            void *mem = memory_region_get_ram_ptr(&s->cmdmem);
146

147
            s->regs[R_CRB_CTRL_START] |= CRB_START_INVOKE;
148
            s->cmd = (TPMBackendCmd) {
149
                .in = mem,
150
                .in_len = MIN(tpm_cmd_get_size(mem), s->be_buffer_size),
151
                .out = mem,
152
                .out_len = s->be_buffer_size,
153
            };
154

155
            tpm_backend_deliver_request(s->tpmbe, &s->cmd);
156
        }
157
        break;
158
    case A_CRB_LOC_CTRL:
159
        switch (val) {
160
        case CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT:
161
            /* not loc 3 or 4 */
162
            break;
163
        case CRB_LOC_CTRL_RELINQUISH:
164
            ARRAY_FIELD_DP32(s->regs, CRB_LOC_STATE,
165
                             locAssigned, 0);
166
            ARRAY_FIELD_DP32(s->regs, CRB_LOC_STS,
167
                             Granted, 0);
168
            break;
169
        case CRB_LOC_CTRL_REQUEST_ACCESS:
170
            ARRAY_FIELD_DP32(s->regs, CRB_LOC_STS,
171
                             Granted, 1);
172
            ARRAY_FIELD_DP32(s->regs, CRB_LOC_STS,
173
                             beenSeized, 0);
174
            ARRAY_FIELD_DP32(s->regs, CRB_LOC_STATE,
175
                             locAssigned, 1);
176
            break;
177
        }
178
        break;
179
    }
180
}
181

182
static const MemoryRegionOps tpm_crb_memory_ops = {
183
    .read = tpm_crb_mmio_read,
184
    .write = tpm_crb_mmio_write,
185
    .endianness = DEVICE_LITTLE_ENDIAN,
186
    .valid = {
187
        .min_access_size = 1,
188
        .max_access_size = 4,
189
    },
190
};
191

192
static void tpm_crb_request_completed(TPMIf *ti, int ret)
193
{
194
    CRBState *s = CRB(ti);
195

196
    s->regs[R_CRB_CTRL_START] &= ~CRB_START_INVOKE;
197
    if (ret != 0) {
198
        ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS,
199
                         tpmSts, 1); /* fatal error */
200
    }
201
    memory_region_set_dirty(&s->cmdmem, 0, CRB_CTRL_CMD_SIZE);
202
}
203

204
static enum TPMVersion tpm_crb_get_version(TPMIf *ti)
205
{
206
    CRBState *s = CRB(ti);
207

208
    return tpm_backend_get_tpm_version(s->tpmbe);
209
}
210

211
static int tpm_crb_pre_save(void *opaque)
212
{
213
    CRBState *s = opaque;
214

215
    tpm_backend_finish_sync(s->tpmbe);
216

217
    return 0;
218
}
219

220
static const VMStateDescription vmstate_tpm_crb = {
221
    .name = "tpm-crb",
222
    .pre_save = tpm_crb_pre_save,
223
    .fields = (const VMStateField[]) {
224
        VMSTATE_UINT32_ARRAY(regs, CRBState, TPM_CRB_R_MAX),
225
        VMSTATE_END_OF_LIST(),
226
    }
227
};
228

229
static Property tpm_crb_properties[] = {
230
    DEFINE_PROP_TPMBE("tpmdev", CRBState, tpmbe),
231
    DEFINE_PROP_BOOL("ppi", CRBState, ppi_enabled, true),
232
    DEFINE_PROP_END_OF_LIST(),
233
};
234

235
static void tpm_crb_reset(void *dev)
236
{
237
    CRBState *s = CRB(dev);
238

239
    if (s->ppi_enabled) {
240
        tpm_ppi_reset(&s->ppi);
241
    }
242
    tpm_backend_reset(s->tpmbe);
243

244
    memset(s->regs, 0, sizeof(s->regs));
245

246
    ARRAY_FIELD_DP32(s->regs, CRB_LOC_STATE,
247
                     tpmRegValidSts, 1);
248
    ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS,
249
                     tpmIdle, 1);
250
    ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
251
                     InterfaceType, CRB_INTF_TYPE_CRB_ACTIVE);
252
    ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
253
                     InterfaceVersion, CRB_INTF_VERSION_CRB);
254
    ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
255
                     CapLocality, CRB_INTF_CAP_LOCALITY_0_ONLY);
256
    ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
257
                     CapCRBIdleBypass, CRB_INTF_CAP_IDLE_FAST);
258
    ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
259
                     CapDataXferSizeSupport, CRB_INTF_CAP_XFER_SIZE_64);
260
    ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
261
                     CapFIFO, CRB_INTF_CAP_FIFO_NOT_SUPPORTED);
262
    ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
263
                     CapCRB, CRB_INTF_CAP_CRB_SUPPORTED);
264
    ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
265
                     InterfaceSelector, CRB_INTF_IF_SELECTOR_CRB);
266
    ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
267
                     RID, 0b0000);
268
    ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID2,
269
                     VID, PCI_VENDOR_ID_IBM);
270

271
    s->regs[R_CRB_CTRL_CMD_SIZE] = CRB_CTRL_CMD_SIZE;
272
    s->regs[R_CRB_CTRL_CMD_LADDR] = TPM_CRB_ADDR_BASE + A_CRB_DATA_BUFFER;
273
    s->regs[R_CRB_CTRL_RSP_SIZE] = CRB_CTRL_CMD_SIZE;
274
    s->regs[R_CRB_CTRL_RSP_ADDR] = TPM_CRB_ADDR_BASE + A_CRB_DATA_BUFFER;
275

276
    s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->tpmbe),
277
                            CRB_CTRL_CMD_SIZE);
278

279
    if (tpm_backend_startup_tpm(s->tpmbe, s->be_buffer_size) < 0) {
280
        exit(1);
281
    }
282
}
283

284
static void tpm_crb_realize(DeviceState *dev, Error **errp)
285
{
286
    CRBState *s = CRB(dev);
287

288
    if (!tpm_find()) {
289
        error_setg(errp, "at most one TPM device is permitted");
290
        return;
291
    }
292
    if (!s->tpmbe) {
293
        error_setg(errp, "'tpmdev' property is required");
294
        return;
295
    }
296

297
    memory_region_init_io(&s->mmio, OBJECT(s), &tpm_crb_memory_ops, s,
298
        "tpm-crb-mmio", sizeof(s->regs));
299
    memory_region_init_ram(&s->cmdmem, OBJECT(s),
300
        "tpm-crb-cmd", CRB_CTRL_CMD_SIZE, errp);
301

302
    memory_region_add_subregion(get_system_memory(),
303
        TPM_CRB_ADDR_BASE, &s->mmio);
304
    memory_region_add_subregion(get_system_memory(),
305
        TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem);
306

307
    if (s->ppi_enabled) {
308
        tpm_ppi_init(&s->ppi, get_system_memory(),
309
                     TPM_PPI_ADDR_BASE, OBJECT(s));
310
    }
311

312
    if (xen_enabled()) {
313
        tpm_crb_reset(dev);
314
    } else {
315
        qemu_register_reset(tpm_crb_reset, dev);
316
    }
317
}
318

319
static void tpm_crb_class_init(ObjectClass *klass, void *data)
320
{
321
    DeviceClass *dc = DEVICE_CLASS(klass);
322
    TPMIfClass *tc = TPM_IF_CLASS(klass);
323

324
    dc->realize = tpm_crb_realize;
325
    device_class_set_props(dc, tpm_crb_properties);
326
    dc->vmsd  = &vmstate_tpm_crb;
327
    dc->user_creatable = true;
328
    tc->model = TPM_MODEL_TPM_CRB;
329
    tc->get_version = tpm_crb_get_version;
330
    tc->request_completed = tpm_crb_request_completed;
331

332
    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
333
}
334

335
static const TypeInfo tpm_crb_info = {
336
    .name = TYPE_TPM_CRB,
337
    /* could be TYPE_SYS_BUS_DEVICE (or LPC etc) */
338
    .parent = TYPE_DEVICE,
339
    .instance_size = sizeof(CRBState),
340
    .class_init  = tpm_crb_class_init,
341
    .interfaces = (InterfaceInfo[]) {
342
        { TYPE_TPM_IF },
343
        { }
344
    }
345
};
346

347
static void tpm_crb_register(void)
348
{
349
    type_register_static(&tpm_crb_info);
350
}
351

352
type_init(tpm_crb_register)
353

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

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

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

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