test: tpm-tis: Get prepared to share tests between ISA and sysbus devices

ISA and sysbus TPM-TIS devices will share their tests. Only
the main() will change (instantiation option is different).
Also the base address of the TPM-TIS device is going to be
different. on x86 it is located at 0xFED40000 while on ARM
it can be located at any location, discovered through the
device tree description.

So we put shared test functions in a new object module.
Each test needs to set tpm_tis_base_addr global variable.

Also take benefit of this move to fix "block comments using
a leading */ on a separate line" checkpatch warnings.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Message-id: 20200305165149.618-10-eric.auger@redhat.com
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
stable-5.0
Eric Auger 2020-03-05 17:51:48 +01:00 committed by Stefan Berger
parent 551cabdfa9
commit 5166c32617
9 changed files with 493 additions and 415 deletions

View File

@ -302,7 +302,7 @@ tests/qtest/tpm-crb-swtpm-test$(EXESUF): tests/qtest/tpm-crb-swtpm-test.o tests/
tests/qtest/tpm-crb-test$(EXESUF): tests/qtest/tpm-crb-test.o tests/qtest/tpm-emu.o $(test-io-obj-y)
tests/qtest/tpm-tis-swtpm-test$(EXESUF): tests/qtest/tpm-tis-swtpm-test.o tests/qtest/tpm-emu.o \
tests/qtest/tpm-util.o tests/qtest/tpm-tests.o $(test-io-obj-y)
tests/qtest/tpm-tis-test$(EXESUF): tests/qtest/tpm-tis-test.o tests/qtest/tpm-emu.o $(test-io-obj-y)
tests/qtest/tpm-tis-test$(EXESUF): tests/qtest/tpm-tis-test.o tests/qtest/tpm-tis-util.o tests/qtest/tpm-emu.o $(test-io-obj-y)
# QTest rules

View File

@ -18,6 +18,10 @@
#include "libqtest.h"
#include "qemu/module.h"
#include "tpm-tests.h"
#include "hw/acpi/tpm.h"
/* Not used but needed for linking */
uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE;
typedef struct TestState {
char *src_tpm_path;

View File

@ -19,6 +19,9 @@
#include "qemu/module.h"
#include "tpm-emu.h"
/* Not used but needed for linking */
uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE;
#define TPM_CMD "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"
static void tpm_crb_test(const void *data)

View File

@ -18,6 +18,9 @@
#include "libqtest.h"
#include "qemu/module.h"
#include "tpm-tests.h"
#include "hw/acpi/tpm.h"
uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE;
typedef struct TestState {
char *src_tpm_path;

View File

@ -1,5 +1,5 @@
/*
* QTest testcase for TPM TIS
* QTest testcase for ISA TPM TIS
*
* Copyright (c) 2018 Red Hat, Inc.
* Copyright (c) 2018 IBM Corporation
@ -20,417 +20,9 @@
#include "libqtest-single.h"
#include "qemu/module.h"
#include "tpm-emu.h"
#include "tpm-tis-util.h"
#define TIS_REG(LOCTY, REG) \
(TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG)
#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";
static 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);
}
}
static 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
*/
static 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
*/
static 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
*/
static 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));
}
uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE;
int main(int argc, char **argv)
{

View File

@ -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));
}

View File

@ -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 */

View File

@ -19,9 +19,6 @@
#include "tpm-util.h"
#include "qapi/qmp/qdict.h"
#define TIS_REG(LOCTY, REG) \
(TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG)
void tpm_util_crb_transfer(QTestState *s,
const unsigned char *req, size_t req_size,
unsigned char *rsp, size_t rsp_size)

View File

@ -15,6 +15,11 @@
#include "io/channel-socket.h"
extern uint64_t tpm_tis_base_addr;
#define TIS_REG(LOCTY, REG) \
(tpm_tis_base_addr + ((LOCTY) << 12) + REG)
typedef void (tx_func)(QTestState *s,
const unsigned char *req, size_t req_size,
unsigned char *rsp, size_t rsp_size);