Browse Source
-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEEuBi5yt+QicLVzsZrda1lgCoLQhEFAl5hNQEACgkQda1lgCoL QhH7Egf/esr+B1d6kfD8bfy3byplFu3fnNTJRino2c6ElaRLXKG6kl1ODb7oQZ0g 37aVL+UVtVyTIkuTKT6Xx4xNq4TbrXB6hcNqoB/J9DaTVVYCLLQWrHRRmA8VrtLM 6H7hdmi7zPEOm6BDtDJzUyDmWsuZEwGcsToUixfMlG+rCbc3bC4rGQwVg2/t5Y55 LvP8SF6NngmL099ZtZbHsvaVxprZZ5fxx7NzjX6tW19TBg0PqtIV2Ro0VnCliaIN L5xv5amlghIdBbkZKmc6hNERJ/U37lF3AxyY4dxCLn0waMN+DgYvfjr2ZSrB9PQ/ 8yts/x5pIThCffvE0DSir2kQz8yUNg== =MeFg -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/stefanberger/tags/pull-tpm-2020-03-04-2' into staging Merge tpm 2020/03/04 v2 # gpg: Signature made Thu 05 Mar 2020 17:21:05 GMT # gpg: using RSA key B818B9CADF9089C2D5CEC66B75AD65802A0B4211 # gpg: Good signature from "Stefan Berger <stefanb@linux.vnet.ibm.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: B818 B9CA DF90 89C2 D5CE C66B 75AD 6580 2A0B 4211 * remotes/stefanberger/tags/pull-tpm-2020-03-04-2: test: tpm-tis: Add Sysbus TPM-TIS device test test: tpm-tis: Get prepared to share tests between ISA and sysbus devices test: tpm: pass optional machine options to swtpm test functions docs/specs/tpm: Document TPM_TIS sysbus device for ARM hw/arm/virt: vTPM support tpm: Add the SysBus TPM TIS device tpm: Separate TPM_TIS and TPM_TIS_ISA configs tpm: Separate tpm_tis common functions from isa code tpm: Use TPMState as a common struct tpm: rename TPM_TIS into TPM_TIS_ISA Signed-off-by: Peter Maydell <peter.maydell@linaro.org>pull/88/head
27 changed files with 1207 additions and 609 deletions
@ -0,0 +1,91 @@ |
|||
/*
|
|||
* tpm_tis.h - QEMU's TPM TIS common header |
|||
* |
|||
* Copyright (C) 2006,2010-2013 IBM Corporation |
|||
* |
|||
* Authors: |
|||
* Stefan Berger <stefanb@us.ibm.com> |
|||
* David Safford <safford@us.ibm.com> |
|||
* |
|||
* Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at> |
|||
* |
|||
* This work is licensed under the terms of the GNU GPL, version 2 or later. |
|||
* See the COPYING file in the top-level directory. |
|||
* |
|||
* Implementation of the TIS interface according to specs found at |
|||
* http://www.trustedcomputinggroup.org. This implementation currently
|
|||
* supports version 1.3, 21 March 2013 |
|||
* In the developers menu choose the PC Client section then find the TIS |
|||
* specification. |
|||
* |
|||
* TPM TIS for TPM 2 implementation following TCG PC Client Platform |
|||
* TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 |
|||
*/ |
|||
#ifndef TPM_TPM_TIS_H |
|||
#define TPM_TPM_TIS_H |
|||
|
|||
#include "qemu/osdep.h" |
|||
#include "sysemu/tpm_backend.h" |
|||
#include "tpm_ppi.h" |
|||
|
|||
#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */ |
|||
#define TPM_TIS_LOCALITY_SHIFT 12 |
|||
#define TPM_TIS_NO_LOCALITY 0xff |
|||
|
|||
#define TPM_TIS_IS_VALID_LOCTY(x) ((x) < TPM_TIS_NUM_LOCALITIES) |
|||
|
|||
#define TPM_TIS_BUFFER_MAX 4096 |
|||
|
|||
typedef enum { |
|||
TPM_TIS_STATE_IDLE = 0, |
|||
TPM_TIS_STATE_READY, |
|||
TPM_TIS_STATE_COMPLETION, |
|||
TPM_TIS_STATE_EXECUTION, |
|||
TPM_TIS_STATE_RECEPTION, |
|||
} TPMTISState; |
|||
|
|||
/* locality data -- all fields are persisted */ |
|||
typedef struct TPMLocality { |
|||
TPMTISState state; |
|||
uint8_t access; |
|||
uint32_t sts; |
|||
uint32_t iface_id; |
|||
uint32_t inte; |
|||
uint32_t ints; |
|||
} TPMLocality; |
|||
|
|||
typedef struct TPMState { |
|||
MemoryRegion mmio; |
|||
|
|||
unsigned char buffer[TPM_TIS_BUFFER_MAX]; |
|||
uint16_t rw_offset; |
|||
|
|||
uint8_t active_locty; |
|||
uint8_t aborting_locty; |
|||
uint8_t next_locty; |
|||
|
|||
TPMLocality loc[TPM_TIS_NUM_LOCALITIES]; |
|||
|
|||
qemu_irq irq; |
|||
uint32_t irq_num; |
|||
|
|||
TPMBackendCmd cmd; |
|||
|
|||
TPMBackend *be_driver; |
|||
TPMVersion be_tpm_version; |
|||
|
|||
size_t be_buffer_size; |
|||
|
|||
bool ppi_enabled; |
|||
TPMPPI ppi; |
|||
} TPMState; |
|||
|
|||
extern const VMStateDescription vmstate_locty; |
|||
extern const MemoryRegionOps tpm_tis_memory_ops; |
|||
|
|||
int tpm_tis_pre_save(TPMState *s); |
|||
void tpm_tis_reset(TPMState *s); |
|||
enum TPMVersion tpm_tis_get_tpm_version(TPMState *s); |
|||
void tpm_tis_request_completed(TPMState *s, int ret); |
|||
|
|||
#endif /* TPM_TPM_TIS_H */ |
|||
@ -0,0 +1,170 @@ |
|||
/*
|
|||
* tpm_tis_isa.c - QEMU's TPM TIS ISA Device |
|||
* |
|||
* Copyright (C) 2006,2010-2013 IBM Corporation |
|||
* |
|||
* Authors: |
|||
* Stefan Berger <stefanb@us.ibm.com> |
|||
* David Safford <safford@us.ibm.com> |
|||
* |
|||
* Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at> |
|||
* |
|||
* This work is licensed under the terms of the GNU GPL, version 2 or later. |
|||
* See the COPYING file in the top-level directory. |
|||
* |
|||
* Implementation of the TIS interface according to specs found at |
|||
* http://www.trustedcomputinggroup.org. This implementation currently
|
|||
* supports version 1.3, 21 March 2013 |
|||
* In the developers menu choose the PC Client section then find the TIS |
|||
* specification. |
|||
* |
|||
* TPM TIS for TPM 2 implementation following TCG PC Client Platform |
|||
* TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 |
|||
*/ |
|||
|
|||
#include "qemu/osdep.h" |
|||
#include "hw/isa/isa.h" |
|||
#include "hw/qdev-properties.h" |
|||
#include "migration/vmstate.h" |
|||
#include "tpm_util.h" |
|||
#include "tpm_tis.h" |
|||
|
|||
typedef struct TPMStateISA { |
|||
/*< private >*/ |
|||
ISADevice parent_obj; |
|||
|
|||
/*< public >*/ |
|||
TPMState state; /* not a QOM object */ |
|||
} TPMStateISA; |
|||
|
|||
#define TPM_TIS_ISA(obj) OBJECT_CHECK(TPMStateISA, (obj), TYPE_TPM_TIS_ISA) |
|||
|
|||
static int tpm_tis_pre_save_isa(void *opaque) |
|||
{ |
|||
TPMStateISA *isadev = opaque; |
|||
|
|||
return tpm_tis_pre_save(&isadev->state); |
|||
} |
|||
|
|||
static const VMStateDescription vmstate_tpm_tis_isa = { |
|||
.name = "tpm-tis", |
|||
.version_id = 0, |
|||
.pre_save = tpm_tis_pre_save_isa, |
|||
.fields = (VMStateField[]) { |
|||
VMSTATE_BUFFER(state.buffer, TPMStateISA), |
|||
VMSTATE_UINT16(state.rw_offset, TPMStateISA), |
|||
VMSTATE_UINT8(state.active_locty, TPMStateISA), |
|||
VMSTATE_UINT8(state.aborting_locty, TPMStateISA), |
|||
VMSTATE_UINT8(state.next_locty, TPMStateISA), |
|||
|
|||
VMSTATE_STRUCT_ARRAY(state.loc, TPMStateISA, TPM_TIS_NUM_LOCALITIES, 0, |
|||
vmstate_locty, TPMLocality), |
|||
|
|||
VMSTATE_END_OF_LIST() |
|||
} |
|||
}; |
|||
|
|||
static void tpm_tis_isa_request_completed(TPMIf *ti, int ret) |
|||
{ |
|||
TPMStateISA *isadev = TPM_TIS_ISA(ti); |
|||
TPMState *s = &isadev->state; |
|||
|
|||
tpm_tis_request_completed(s, ret); |
|||
} |
|||
|
|||
static enum TPMVersion tpm_tis_isa_get_tpm_version(TPMIf *ti) |
|||
{ |
|||
TPMStateISA *isadev = TPM_TIS_ISA(ti); |
|||
TPMState *s = &isadev->state; |
|||
|
|||
return tpm_tis_get_tpm_version(s); |
|||
} |
|||
|
|||
static void tpm_tis_isa_reset(DeviceState *dev) |
|||
{ |
|||
TPMStateISA *isadev = TPM_TIS_ISA(dev); |
|||
TPMState *s = &isadev->state; |
|||
|
|||
return tpm_tis_reset(s); |
|||
} |
|||
|
|||
static Property tpm_tis_isa_properties[] = { |
|||
DEFINE_PROP_UINT32("irq", TPMStateISA, state.irq_num, TPM_TIS_IRQ), |
|||
DEFINE_PROP_TPMBE("tpmdev", TPMStateISA, state.be_driver), |
|||
DEFINE_PROP_BOOL("ppi", TPMStateISA, state.ppi_enabled, true), |
|||
DEFINE_PROP_END_OF_LIST(), |
|||
}; |
|||
|
|||
static void tpm_tis_isa_initfn(Object *obj) |
|||
{ |
|||
TPMStateISA *isadev = TPM_TIS_ISA(obj); |
|||
TPMState *s = &isadev->state; |
|||
|
|||
memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, |
|||
s, "tpm-tis-mmio", |
|||
TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); |
|||
} |
|||
|
|||
static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp) |
|||
{ |
|||
TPMStateISA *isadev = TPM_TIS_ISA(dev); |
|||
TPMState *s = &isadev->state; |
|||
|
|||
if (!tpm_find()) { |
|||
error_setg(errp, "at most one TPM device is permitted"); |
|||
return; |
|||
} |
|||
|
|||
if (!s->be_driver) { |
|||
error_setg(errp, "'tpmdev' property is required"); |
|||
return; |
|||
} |
|||
if (s->irq_num > 15) { |
|||
error_setg(errp, "IRQ %d is outside valid range of 0 to 15", |
|||
s->irq_num); |
|||
return; |
|||
} |
|||
|
|||
isa_init_irq(ISA_DEVICE(dev), &s->irq, s->irq_num); |
|||
|
|||
memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), |
|||
TPM_TIS_ADDR_BASE, &s->mmio); |
|||
|
|||
if (s->ppi_enabled) { |
|||
tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)), |
|||
TPM_PPI_ADDR_BASE, OBJECT(dev)); |
|||
} |
|||
} |
|||
|
|||
static void tpm_tis_isa_class_init(ObjectClass *klass, void *data) |
|||
{ |
|||
DeviceClass *dc = DEVICE_CLASS(klass); |
|||
TPMIfClass *tc = TPM_IF_CLASS(klass); |
|||
|
|||
device_class_set_props(dc, tpm_tis_isa_properties); |
|||
dc->vmsd = &vmstate_tpm_tis_isa; |
|||
tc->model = TPM_MODEL_TPM_TIS; |
|||
dc->realize = tpm_tis_isa_realizefn; |
|||
dc->reset = tpm_tis_isa_reset; |
|||
tc->request_completed = tpm_tis_isa_request_completed; |
|||
tc->get_version = tpm_tis_isa_get_tpm_version; |
|||
} |
|||
|
|||
static const TypeInfo tpm_tis_isa_info = { |
|||
.name = TYPE_TPM_TIS_ISA, |
|||
.parent = TYPE_ISA_DEVICE, |
|||
.instance_size = sizeof(TPMStateISA), |
|||
.instance_init = tpm_tis_isa_initfn, |
|||
.class_init = tpm_tis_isa_class_init, |
|||
.interfaces = (InterfaceInfo[]) { |
|||
{ TYPE_TPM_IF }, |
|||
{ } |
|||
} |
|||
}; |
|||
|
|||
static void tpm_tis_isa_register(void) |
|||
{ |
|||
type_register_static(&tpm_tis_isa_info); |
|||
} |
|||
|
|||
type_init(tpm_tis_isa_register) |
|||
@ -0,0 +1,159 @@ |
|||
/*
|
|||
* tpm_tis_sysbus.c - QEMU's TPM TIS SYSBUS Device |
|||
* |
|||
* Copyright (C) 2006,2010-2013 IBM Corporation |
|||
* |
|||
* Authors: |
|||
* Stefan Berger <stefanb@us.ibm.com> |
|||
* David Safford <safford@us.ibm.com> |
|||
* |
|||
* Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at> |
|||
* |
|||
* This work is licensed under the terms of the GNU GPL, version 2 or later. |
|||
* See the COPYING file in the top-level directory. |
|||
* |
|||
* Implementation of the TIS interface according to specs found at |
|||
* http://www.trustedcomputinggroup.org. This implementation currently
|
|||
* supports version 1.3, 21 March 2013 |
|||
* In the developers menu choose the PC Client section then find the TIS |
|||
* specification. |
|||
* |
|||
* TPM TIS for TPM 2 implementation following TCG PC Client Platform |
|||
* TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 |
|||
*/ |
|||
|
|||
#include "qemu/osdep.h" |
|||
#include "hw/qdev-properties.h" |
|||
#include "migration/vmstate.h" |
|||
#include "tpm_util.h" |
|||
#include "hw/sysbus.h" |
|||
#include "tpm_tis.h" |
|||
|
|||
typedef struct TPMStateSysBus { |
|||
/*< private >*/ |
|||
SysBusDevice parent_obj; |
|||
|
|||
/*< public >*/ |
|||
TPMState state; /* not a QOM object */ |
|||
} TPMStateSysBus; |
|||
|
|||
#define TPM_TIS_SYSBUS(obj) OBJECT_CHECK(TPMStateSysBus, (obj), TYPE_TPM_TIS_SYSBUS) |
|||
|
|||
static int tpm_tis_pre_save_sysbus(void *opaque) |
|||
{ |
|||
TPMStateSysBus *sbdev = opaque; |
|||
|
|||
return tpm_tis_pre_save(&sbdev->state); |
|||
} |
|||
|
|||
static const VMStateDescription vmstate_tpm_tis_sysbus = { |
|||
.name = "tpm-tis", |
|||
.version_id = 0, |
|||
.pre_save = tpm_tis_pre_save_sysbus, |
|||
.fields = (VMStateField[]) { |
|||
VMSTATE_BUFFER(state.buffer, TPMStateSysBus), |
|||
VMSTATE_UINT16(state.rw_offset, TPMStateSysBus), |
|||
VMSTATE_UINT8(state.active_locty, TPMStateSysBus), |
|||
VMSTATE_UINT8(state.aborting_locty, TPMStateSysBus), |
|||
VMSTATE_UINT8(state.next_locty, TPMStateSysBus), |
|||
|
|||
VMSTATE_STRUCT_ARRAY(state.loc, TPMStateSysBus, TPM_TIS_NUM_LOCALITIES, |
|||
0, vmstate_locty, TPMLocality), |
|||
|
|||
VMSTATE_END_OF_LIST() |
|||
} |
|||
}; |
|||
|
|||
static void tpm_tis_sysbus_request_completed(TPMIf *ti, int ret) |
|||
{ |
|||
TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(ti); |
|||
TPMState *s = &sbdev->state; |
|||
|
|||
tpm_tis_request_completed(s, ret); |
|||
} |
|||
|
|||
static enum TPMVersion tpm_tis_sysbus_get_tpm_version(TPMIf *ti) |
|||
{ |
|||
TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(ti); |
|||
TPMState *s = &sbdev->state; |
|||
|
|||
return tpm_tis_get_tpm_version(s); |
|||
} |
|||
|
|||
static void tpm_tis_sysbus_reset(DeviceState *dev) |
|||
{ |
|||
TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(dev); |
|||
TPMState *s = &sbdev->state; |
|||
|
|||
return tpm_tis_reset(s); |
|||
} |
|||
|
|||
static Property tpm_tis_sysbus_properties[] = { |
|||
DEFINE_PROP_UINT32("irq", TPMStateSysBus, state.irq_num, TPM_TIS_IRQ), |
|||
DEFINE_PROP_TPMBE("tpmdev", TPMStateSysBus, state.be_driver), |
|||
DEFINE_PROP_BOOL("ppi", TPMStateSysBus, state.ppi_enabled, true), |
|||
DEFINE_PROP_END_OF_LIST(), |
|||
}; |
|||
|
|||
static void tpm_tis_sysbus_initfn(Object *obj) |
|||
{ |
|||
TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(obj); |
|||
TPMState *s = &sbdev->state; |
|||
|
|||
memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, |
|||
s, "tpm-tis-mmio", |
|||
TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); |
|||
|
|||
sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); |
|||
sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); |
|||
} |
|||
|
|||
static void tpm_tis_sysbus_realizefn(DeviceState *dev, Error **errp) |
|||
{ |
|||
TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(dev); |
|||
TPMState *s = &sbdev->state; |
|||
|
|||
if (!tpm_find()) { |
|||
error_setg(errp, "at most one TPM device is permitted"); |
|||
return; |
|||
} |
|||
|
|||
if (!s->be_driver) { |
|||
error_setg(errp, "'tpmdev' property is required"); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
static void tpm_tis_sysbus_class_init(ObjectClass *klass, void *data) |
|||
{ |
|||
DeviceClass *dc = DEVICE_CLASS(klass); |
|||
TPMIfClass *tc = TPM_IF_CLASS(klass); |
|||
|
|||
device_class_set_props(dc, tpm_tis_sysbus_properties); |
|||
dc->vmsd = &vmstate_tpm_tis_sysbus; |
|||
tc->model = TPM_MODEL_TPM_TIS; |
|||
dc->realize = tpm_tis_sysbus_realizefn; |
|||
dc->user_creatable = true; |
|||
dc->reset = tpm_tis_sysbus_reset; |
|||
tc->request_completed = tpm_tis_sysbus_request_completed; |
|||
tc->get_version = tpm_tis_sysbus_get_tpm_version; |
|||
} |
|||
|
|||
static const TypeInfo tpm_tis_sysbus_info = { |
|||
.name = TYPE_TPM_TIS_SYSBUS, |
|||
.parent = TYPE_SYS_BUS_DEVICE, |
|||
.instance_size = sizeof(TPMStateSysBus), |
|||
.instance_init = tpm_tis_sysbus_initfn, |
|||
.class_init = tpm_tis_sysbus_class_init, |
|||
.interfaces = (InterfaceInfo[]) { |
|||
{ TYPE_TPM_IF }, |
|||
{ } |
|||
} |
|||
}; |
|||
|
|||
static void tpm_tis_sysbus_register(void) |
|||
{ |
|||
type_register_static(&tpm_tis_sysbus_info); |
|||
} |
|||
|
|||
type_init(tpm_tis_sysbus_register) |
|||
@ -0,0 +1,76 @@ |
|||
/*
|
|||
* QTest testcase for Sysbus TPM TIS talking to external swtpm and swtpm |
|||
* migration |
|||
* |
|||
* Copyright (c) 2018 IBM Corporation |
|||
* with parts borrowed from migration-test.c that is: |
|||
* Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates |
|||
* |
|||
* Authors: |
|||
* Stefan Berger <stefanb@linux.vnet.ibm.com> |
|||
* |
|||
* This work is licensed under the terms of the GNU GPL, version 2 or later. |
|||
* See the COPYING file in the top-level directory. |
|||
*/ |
|||
|
|||
#include "qemu/osdep.h" |
|||
#include <glib/gstdio.h> |
|||
|
|||
#include "libqtest.h" |
|||
#include "qemu/module.h" |
|||
#include "tpm-tests.h" |
|||
#include "hw/acpi/tpm.h" |
|||
|
|||
uint64_t tpm_tis_base_addr = 0xc000000; |
|||
#define MACHINE_OPTIONS "-machine virt,gic-version=max -accel tcg" |
|||
|
|||
typedef struct TestState { |
|||
char *src_tpm_path; |
|||
char *dst_tpm_path; |
|||
char *uri; |
|||
} TestState; |
|||
|
|||
static void tpm_tis_swtpm_test(const void *data) |
|||
{ |
|||
const TestState *ts = data; |
|||
|
|||
tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, |
|||
"tpm-tis-device", MACHINE_OPTIONS); |
|||
} |
|||
|
|||
static void tpm_tis_swtpm_migration_test(const void *data) |
|||
{ |
|||
const TestState *ts = data; |
|||
|
|||
tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri, |
|||
tpm_util_tis_transfer, "tpm-tis-device", |
|||
MACHINE_OPTIONS); |
|||
} |
|||
|
|||
int main(int argc, char **argv) |
|||
{ |
|||
int ret; |
|||
TestState ts = { 0 }; |
|||
|
|||
ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-tis-device-swtpm-test.XXXXXX", |
|||
NULL); |
|||
ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-tis-device-swtpm-test.XXXXXX", |
|||
NULL); |
|||
ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path); |
|||
|
|||
module_call_init(MODULE_INIT_QOM); |
|||
g_test_init(&argc, &argv, NULL); |
|||
|
|||
qtest_add_data_func("/tpm/tis-swtpm/test", &ts, tpm_tis_swtpm_test); |
|||
qtest_add_data_func("/tpm/tis-swtpm-migration/test", &ts, |
|||
tpm_tis_swtpm_migration_test); |
|||
ret = g_test_run(); |
|||
|
|||
g_rmdir(ts.dst_tpm_path); |
|||
g_free(ts.dst_tpm_path); |
|||
g_rmdir(ts.src_tpm_path); |
|||
g_free(ts.src_tpm_path); |
|||
g_free(ts.uri); |
|||
|
|||
return ret; |
|||
} |
|||
@ -0,0 +1,87 @@ |
|||
/*
|
|||
* QTest testcase for SYSBUS TPM TIS |
|||
* |
|||
* Copyright (c) 2018 Red Hat, Inc. |
|||
* Copyright (c) 2018 IBM Corporation |
|||
* |
|||
* Authors: |
|||
* Marc-André Lureau <marcandre.lureau@redhat.com> |
|||
* Stefan Berger <stefanb@linux.vnet.ibm.com> |
|||
* |
|||
* This work is licensed under the terms of the GNU GPL, version 2 or later. |
|||
* See the COPYING file in the top-level directory. |
|||
*/ |
|||
|
|||
#include "qemu/osdep.h" |
|||
#include <glib/gstdio.h> |
|||
|
|||
#include "io/channel-socket.h" |
|||
#include "libqtest-single.h" |
|||
#include "qemu/module.h" |
|||
#include "tpm-emu.h" |
|||
#include "tpm-util.h" |
|||
#include "tpm-tis-util.h" |
|||
|
|||
/*
|
|||
* As the Sysbus tpm-tis-device is instantiated on the ARM virt |
|||
* platform bus and it is the only sysbus device dynamically |
|||
* instantiated, it gets plugged at its base address |
|||
*/ |
|||
uint64_t tpm_tis_base_addr = 0xc000000; |
|||
|
|||
int main(int argc, char **argv) |
|||
{ |
|||
char *tmp_path = g_dir_make_tmp("qemu-tpm-tis-device-test.XXXXXX", NULL); |
|||
GThread *thread; |
|||
TestState test; |
|||
char *args; |
|||
int ret; |
|||
|
|||
module_call_init(MODULE_INIT_QOM); |
|||
g_test_init(&argc, &argv, NULL); |
|||
|
|||
test.addr = g_new0(SocketAddress, 1); |
|||
test.addr->type = SOCKET_ADDRESS_TYPE_UNIX; |
|||
test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL); |
|||
g_mutex_init(&test.data_mutex); |
|||
g_cond_init(&test.data_cond); |
|||
test.data_cond_signal = false; |
|||
|
|||
thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test); |
|||
tpm_emu_test_wait_cond(&test); |
|||
|
|||
args = g_strdup_printf( |
|||
"-machine virt,gic-version=max -accel tcg " |
|||
"-chardev socket,id=chr,path=%s " |
|||
"-tpmdev emulator,id=dev,chardev=chr " |
|||
"-device tpm-tis-device,tpmdev=dev", |
|||
test.addr->u.q_unix.path); |
|||
qtest_start(args); |
|||
|
|||
qtest_add_data_func("/tpm-tis/test_check_localities", &test, |
|||
tpm_tis_test_check_localities); |
|||
|
|||
qtest_add_data_func("/tpm-tis/test_check_access_reg", &test, |
|||
tpm_tis_test_check_access_reg); |
|||
|
|||
qtest_add_data_func("/tpm-tis/test_check_access_reg_seize", &test, |
|||
tpm_tis_test_check_access_reg_seize); |
|||
|
|||
qtest_add_data_func("/tpm-tis/test_check_access_reg_release", &test, |
|||
tpm_tis_test_check_access_reg_release); |
|||
|
|||
qtest_add_data_func("/tpm-tis/test_check_transmit", &test, |
|||
tpm_tis_test_check_transmit); |
|||
|
|||
ret = g_test_run(); |
|||
|
|||
qtest_end(); |
|||
|
|||
g_thread_join(thread); |
|||
g_unlink(test.addr->u.q_unix.path); |
|||
qapi_free_SocketAddress(test.addr); |
|||
g_rmdir(tmp_path); |
|||
g_free(tmp_path); |
|||
g_free(args); |
|||
return ret; |
|||
} |
|||
@ -0,0 +1,451 @@ |
|||
/*
|
|||
* QTest testcase for TPM TIS: common test functions used for both |
|||
* the ISA and SYSBUS devices |
|||
* |
|||
* Copyright (c) 2018 Red Hat, Inc. |
|||
* Copyright (c) 2018 IBM Corporation |
|||
* |
|||
* Authors: |
|||
* Marc-André Lureau <marcandre.lureau@redhat.com> |
|||
* Stefan Berger <stefanb@linux.vnet.ibm.com> |
|||
* |
|||
* This work is licensed under the terms of the GNU GPL, version 2 or later. |
|||
* See the COPYING file in the top-level directory. |
|||
*/ |
|||
|
|||
#include "qemu/osdep.h" |
|||
#include <glib/gstdio.h> |
|||
|
|||
#include "hw/acpi/tpm.h" |
|||
#include "io/channel-socket.h" |
|||
#include "libqtest-single.h" |
|||
#include "qemu/module.h" |
|||
#include "tpm-emu.h" |
|||
#include "tpm-util.h" |
|||
#include "tpm-tis-util.h" |
|||
|
|||
#define DEBUG_TIS_TEST 0 |
|||
|
|||
#define DPRINTF(fmt, ...) do { \ |
|||
if (DEBUG_TIS_TEST) { \ |
|||
printf(fmt, ## __VA_ARGS__); \ |
|||
} \ |
|||
} while (0) |
|||
|
|||
#define DPRINTF_ACCESS \ |
|||
DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \ |
|||
__func__, __LINE__, locty, l, access, pending_request_flag) |
|||
|
|||
#define DPRINTF_STS \ |
|||
DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts) |
|||
|
|||
static const uint8_t TPM_CMD[12] = |
|||
"\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"; |
|||
|
|||
void tpm_tis_test_check_localities(const void *data) |
|||
{ |
|||
uint8_t locty; |
|||
uint8_t access; |
|||
uint32_t ifaceid; |
|||
uint32_t capability; |
|||
uint32_t didvid; |
|||
uint32_t rid; |
|||
|
|||
for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) { |
|||
access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY)); |
|||
g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0); |
|||
|
|||
ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID)); |
|||
g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0); |
|||
|
|||
didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID)); |
|||
g_assert_cmpint(didvid, !=, 0); |
|||
g_assert_cmpint(didvid, !=, 0xffffffff); |
|||
|
|||
rid = readl(TIS_REG(locty, TPM_TIS_REG_RID)); |
|||
g_assert_cmpint(rid, !=, 0); |
|||
g_assert_cmpint(rid, !=, 0xffffffff); |
|||
} |
|||
} |
|||
|
|||
void tpm_tis_test_check_access_reg(const void *data) |
|||
{ |
|||
uint8_t locty; |
|||
uint8_t access; |
|||
|
|||
/* do not test locality 4 (hw only) */ |
|||
for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { |
|||
access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/* request use of locality */ |
|||
writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); |
|||
|
|||
access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/* release access */ |
|||
writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY); |
|||
access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
} |
|||
} |
|||
|
|||
/*
|
|||
* Test case for seizing access by a higher number locality |
|||
*/ |
|||
void tpm_tis_test_check_access_reg_seize(const void *data) |
|||
{ |
|||
int locty, l; |
|||
uint8_t access; |
|||
uint8_t pending_request_flag; |
|||
|
|||
/* do not test locality 4 (hw only) */ |
|||
for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { |
|||
pending_request_flag = 0; |
|||
|
|||
access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/* request use of locality */ |
|||
writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); |
|||
access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/* lower localities cannot seize access */ |
|||
for (l = 0; l < locty; l++) { |
|||
/* lower locality is not active */ |
|||
access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); |
|||
DPRINTF_ACCESS; |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
pending_request_flag | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/* try to request use from 'l' */ |
|||
writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); |
|||
|
|||
/*
|
|||
* requesting use from 'l' was not possible; |
|||
* we must see REQUEST_USE and possibly PENDING_REQUEST |
|||
*/ |
|||
access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); |
|||
DPRINTF_ACCESS; |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_REQUEST_USE | |
|||
pending_request_flag | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/*
|
|||
* locality 'locty' must be unchanged; |
|||
* we must see PENDING_REQUEST |
|||
*/ |
|||
access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY | |
|||
TPM_TIS_ACCESS_PENDING_REQUEST | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/* try to seize from 'l' */ |
|||
writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); |
|||
/* seize from 'l' was not possible */ |
|||
access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); |
|||
DPRINTF_ACCESS; |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_REQUEST_USE | |
|||
pending_request_flag | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/* locality 'locty' must be unchanged */ |
|||
access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY | |
|||
TPM_TIS_ACCESS_PENDING_REQUEST | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/*
|
|||
* on the next loop we will have a PENDING_REQUEST flag |
|||
* set for locality 'l' |
|||
*/ |
|||
pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; |
|||
} |
|||
|
|||
/*
|
|||
* higher localities can 'seize' access but not 'request use'; |
|||
* note: this will activate first l+1, then l+2 etc. |
|||
*/ |
|||
for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { |
|||
/* try to 'request use' from 'l' */ |
|||
writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); |
|||
|
|||
/*
|
|||
* requesting use from 'l' was not possible; we should see |
|||
* REQUEST_USE and may see PENDING_REQUEST |
|||
*/ |
|||
access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); |
|||
DPRINTF_ACCESS; |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_REQUEST_USE | |
|||
pending_request_flag | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/*
|
|||
* locality 'l-1' must be unchanged; we should always |
|||
* see PENDING_REQUEST from 'l' requesting access |
|||
*/ |
|||
access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); |
|||
DPRINTF_ACCESS; |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY | |
|||
TPM_TIS_ACCESS_PENDING_REQUEST | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/* try to seize from 'l' */ |
|||
writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); |
|||
|
|||
/* seize from 'l' was possible */ |
|||
access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); |
|||
DPRINTF_ACCESS; |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY | |
|||
pending_request_flag | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/* l - 1 should show that it has BEEN_SEIZED */ |
|||
access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); |
|||
DPRINTF_ACCESS; |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_BEEN_SEIZED | |
|||
pending_request_flag | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/* clear the BEEN_SEIZED flag and make sure it's gone */ |
|||
writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS), |
|||
TPM_TIS_ACCESS_BEEN_SEIZED); |
|||
|
|||
access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
pending_request_flag | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
} |
|||
|
|||
/*
|
|||
* PENDING_REQUEST will not be set if locty = 0 since all localities |
|||
* were active; in case of locty = 1, locality 0 will be active |
|||
* but no PENDING_REQUEST anywhere |
|||
*/ |
|||
if (locty <= 1) { |
|||
pending_request_flag = 0; |
|||
} |
|||
|
|||
/* release access from l - 1; this activates locty - 1 */ |
|||
l--; |
|||
|
|||
access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); |
|||
DPRINTF_ACCESS; |
|||
|
|||
DPRINTF("%s: %d: relinquishing control on l = %d\n", |
|||
__func__, __LINE__, l); |
|||
writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY); |
|||
|
|||
access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); |
|||
DPRINTF_ACCESS; |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
pending_request_flag | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
for (l = locty - 1; l >= 0; l--) { |
|||
access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); |
|||
DPRINTF_ACCESS; |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY | |
|||
pending_request_flag | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/* release this locality */ |
|||
writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY); |
|||
|
|||
if (l == 1) { |
|||
pending_request_flag = 0; |
|||
} |
|||
} |
|||
|
|||
/* no locality may be active now */ |
|||
for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { |
|||
access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); |
|||
DPRINTF_ACCESS; |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/*
|
|||
* Test case for getting access when higher number locality relinquishes access |
|||
*/ |
|||
void tpm_tis_test_check_access_reg_release(const void *data) |
|||
{ |
|||
int locty, l; |
|||
uint8_t access; |
|||
uint8_t pending_request_flag; |
|||
|
|||
/* do not test locality 4 (hw only) */ |
|||
for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) { |
|||
pending_request_flag = 0; |
|||
|
|||
access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/* request use of locality */ |
|||
writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); |
|||
access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
/* request use of all other localities */ |
|||
for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { |
|||
if (l == locty) { |
|||
continue; |
|||
} |
|||
/*
|
|||
* request use of locality 'l' -- we MUST see REQUEST USE and |
|||
* may see PENDING_REQUEST |
|||
*/ |
|||
writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); |
|||
access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); |
|||
DPRINTF_ACCESS; |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_REQUEST_USE | |
|||
pending_request_flag | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; |
|||
} |
|||
/* release locality 'locty' */ |
|||
writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY); |
|||
/*
|
|||
* highest locality should now be active; release it and make sure the |
|||
* next higest locality is active afterwards |
|||
*/ |
|||
for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) { |
|||
if (l == locty) { |
|||
continue; |
|||
} |
|||
/* 'l' should be active now */ |
|||
access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); |
|||
DPRINTF_ACCESS; |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY | |
|||
pending_request_flag | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
/* 'l' relinquishes access */ |
|||
writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY); |
|||
access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); |
|||
DPRINTF_ACCESS; |
|||
if (l == 1 || (locty <= 1 && l == 2)) { |
|||
pending_request_flag = 0; |
|||
} |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
pending_request_flag | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/*
|
|||
* Test case for transmitting packets |
|||
*/ |
|||
void tpm_tis_test_check_transmit(const void *data) |
|||
{ |
|||
const TestState *s = data; |
|||
uint8_t access; |
|||
uint32_t sts; |
|||
uint16_t bcount; |
|||
size_t i; |
|||
|
|||
/* request use of locality 0 */ |
|||
writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); |
|||
access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); |
|||
g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | |
|||
TPM_TIS_ACCESS_ACTIVE_LOCALITY | |
|||
TPM_TIS_ACCESS_TPM_ESTABLISHMENT); |
|||
|
|||
sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); |
|||
DPRINTF_STS; |
|||
|
|||
g_assert_cmpint(sts & 0xff, ==, 0); |
|||
g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==, |
|||
TPM_TIS_STS_TPM_FAMILY2_0); |
|||
|
|||
bcount = (sts >> 8) & 0xffff; |
|||
g_assert_cmpint(bcount, >=, 128); |
|||
|
|||
writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY); |
|||
sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); |
|||
DPRINTF_STS; |
|||
g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY); |
|||
|
|||
/* transmit command */ |
|||
for (i = 0; i < sizeof(TPM_CMD); i++) { |
|||
writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]); |
|||
sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); |
|||
DPRINTF_STS; |
|||
if (i < sizeof(TPM_CMD) - 1) { |
|||
g_assert_cmpint(sts & 0xff, ==, |
|||
TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); |
|||
} else { |
|||
g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID); |
|||
} |
|||
g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); |
|||
} |
|||
/* start processing */ |
|||
writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO); |
|||
|
|||
uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND; |
|||
do { |
|||
sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); |
|||
if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) { |
|||
break; |
|||
} |
|||
} while (g_get_monotonic_time() < end_time); |
|||
|
|||
sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); |
|||
DPRINTF_STS; |
|||
g_assert_cmpint(sts & 0xff, == , |
|||
TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); |
|||
bcount = (sts >> 8) & 0xffff; |
|||
|
|||
/* read response */ |
|||
uint8_t tpm_msg[sizeof(struct tpm_hdr)]; |
|||
g_assert_cmpint(sizeof(tpm_msg), ==, bcount); |
|||
|
|||
for (i = 0; i < sizeof(tpm_msg); i++) { |
|||
tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO)); |
|||
sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); |
|||
DPRINTF_STS; |
|||
if (sts & TPM_TIS_STS_DATA_AVAILABLE) { |
|||
g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); |
|||
} |
|||
} |
|||
g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg)); |
|||
|
|||
/* relinquish use of locality 0 */ |
|||
writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY); |
|||
access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/*
|
|||
* QTest TPM TIS: Common test functions used for both the |
|||
* ISA and SYSBUS devices |
|||
* |
|||
* Copyright (c) 2018 IBM Corporation |
|||
* |
|||
* Authors: |
|||
* Stefan Berger <stefanb@linux.vnet.ibm.com> |
|||
* |
|||
* This work is licensed under the terms of the GNU GPL, version 2 or later. |
|||
* See the COPYING file in the top-level directory. |
|||
*/ |
|||
|
|||
#ifndef TESTS_TPM_TIS_UTIL_H |
|||
#define TESTS_TPM_TIS_UTIL_H |
|||
|
|||
void tpm_tis_test_check_localities(const void *data); |
|||
void tpm_tis_test_check_access_reg(const void *data); |
|||
void tpm_tis_test_check_access_reg_seize(const void *data); |
|||
void tpm_tis_test_check_access_reg_release(const void *data); |
|||
void tpm_tis_test_check_transmit(const void *data); |
|||
|
|||
#endif /* TESTS_TPM_TIS_UTIL_H */ |
|||
Loading…
Reference in new issue