qemu-patch-raspberry4/tests/qtest/tpm-util.c
Eric Auger 5166c32617 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>
2020-03-05 12:18:39 -05:00

287 lines
8.3 KiB
C

/*
* QTest TPM utilities
*
* Copyright (c) 2018 IBM Corporation
* Copyright (c) 2018 Red Hat, Inc.
*
* Authors:
* Stefan Berger <stefanb@linux.vnet.ibm.com>
* Marc-André Lureau <marcandre.lureau@redhat.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 "hw/acpi/tpm.h"
#include "libqtest.h"
#include "tpm-util.h"
#include "qapi/qmp/qdict.h"
void tpm_util_crb_transfer(QTestState *s,
const unsigned char *req, size_t req_size,
unsigned char *rsp, size_t rsp_size)
{
uint64_t caddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_CMD_LADDR);
uint64_t raddr = qtest_readq(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_RSP_ADDR);
qtest_writeb(s, TPM_CRB_ADDR_BASE + A_CRB_LOC_CTRL, 1);
qtest_memwrite(s, caddr, req, req_size);
uint32_t sts, start = 1;
uint64_t end_time = g_get_monotonic_time() + 5 * G_TIME_SPAN_SECOND;
qtest_writel(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START, start);
while (true) {
start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
if ((start & 1) == 0) {
break;
}
if (g_get_monotonic_time() >= end_time) {
break;
}
};
start = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_START);
g_assert_cmpint(start & 1, ==, 0);
sts = qtest_readl(s, TPM_CRB_ADDR_BASE + A_CRB_CTRL_STS);
g_assert_cmpint(sts & 1, ==, 0);
qtest_memread(s, raddr, rsp, rsp_size);
}
void tpm_util_tis_transfer(QTestState *s,
const unsigned char *req, size_t req_size,
unsigned char *rsp, size_t rsp_size)
{
uint32_t sts;
uint16_t bcount;
size_t i;
/* request use of locality 0 */
qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE);
qtest_writel(s, TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY);
sts = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
bcount = (sts >> 8) & 0xffff;
g_assert_cmpint(bcount, >=, req_size);
/* transmit command */
for (i = 0; i < req_size; i++) {
qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_DATA_FIFO), req[i]);
}
/* start processing */
qtest_writeb(s, 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 = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) {
break;
}
} while (g_get_monotonic_time() < end_time);
sts = qtest_readl(s, TIS_REG(0, TPM_TIS_REG_STS));
bcount = (sts >> 8) & 0xffff;
memset(rsp, 0, rsp_size);
for (i = 0; i < bcount; i++) {
rsp[i] = qtest_readb(s, TIS_REG(0, TPM_TIS_REG_DATA_FIFO));
}
/* relinquish use of locality 0 */
qtest_writeb(s, TIS_REG(0, TPM_TIS_REG_ACCESS),
TPM_TIS_ACCESS_ACTIVE_LOCALITY);
}
void tpm_util_startup(QTestState *s, tx_func *tx)
{
unsigned char buffer[1024];
unsigned char tpm_startup[] =
"\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00";
unsigned char tpm_startup_resp[] =
"\x80\x01\x00\x00\x00\x0a\x00\x00\x00\x00";
tx(s, tpm_startup, sizeof(tpm_startup), buffer, sizeof(buffer));
g_assert_cmpmem(buffer, sizeof(tpm_startup_resp),
tpm_startup_resp, sizeof(tpm_startup_resp));
}
void tpm_util_pcrextend(QTestState *s, tx_func *tx)
{
unsigned char buffer[1024];
unsigned char tpm_pcrextend[] =
"\x80\x02\x00\x00\x00\x41\x00\x00\x01\x82\x00\x00\x00\x0a\x00\x00"
"\x00\x09\x40\x00\x00\x09\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00"
"\x0b\x74\x65\x73\x74\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00";
unsigned char tpm_pcrextend_resp[] =
"\x80\x02\x00\x00\x00\x13\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x01\x00\x00";
tx(s, tpm_pcrextend, sizeof(tpm_pcrextend), buffer, sizeof(buffer));
g_assert_cmpmem(buffer, sizeof(tpm_pcrextend_resp),
tpm_pcrextend_resp, sizeof(tpm_pcrextend_resp));
}
void tpm_util_pcrread(QTestState *s, tx_func *tx,
const unsigned char *exp_resp, size_t exp_resp_size)
{
unsigned char buffer[1024];
unsigned char tpm_pcrread[] =
"\x80\x01\x00\x00\x00\x14\x00\x00\x01\x7e\x00\x00\x00\x01\x00\x0b"
"\x03\x00\x04\x00";
tx(s, tpm_pcrread, sizeof(tpm_pcrread), buffer, sizeof(buffer));
g_assert_cmpmem(buffer, exp_resp_size, exp_resp, exp_resp_size);
}
bool tpm_util_swtpm_has_tpm2(void)
{
bool has_tpm2 = false;
char *out = NULL;
static const char *argv[] = {
"swtpm", "socket", "--help", NULL
};
if (!g_spawn_sync(NULL /* working_dir */,
(char **)argv,
NULL /* envp */,
G_SPAWN_SEARCH_PATH,
NULL /* child_setup */,
NULL /* user_data */,
&out,
NULL /* err */,
NULL /* exit_status */,
NULL)) {
return false;
}
if (strstr(out, "--tpm2")) {
has_tpm2 = true;
}
g_free(out);
return has_tpm2;
}
gboolean tpm_util_swtpm_start(const char *path, GPid *pid,
SocketAddress **addr, GError **error)
{
char *swtpm_argv_tpmstate = g_strdup_printf("dir=%s", path);
char *swtpm_argv_ctrl = g_strdup_printf("type=unixio,path=%s/sock",
path);
gchar *swtpm_argv[] = {
g_strdup("swtpm"), g_strdup("socket"),
g_strdup("--tpmstate"), swtpm_argv_tpmstate,
g_strdup("--ctrl"), swtpm_argv_ctrl,
g_strdup("--tpm2"),
NULL
};
gboolean succ;
unsigned i;
*addr = g_new0(SocketAddress, 1);
(*addr)->type = SOCKET_ADDRESS_TYPE_UNIX;
(*addr)->u.q_unix.path = g_build_filename(path, "sock", NULL);
succ = g_spawn_async(NULL, swtpm_argv, NULL, G_SPAWN_SEARCH_PATH,
NULL, NULL, pid, error);
for (i = 0; swtpm_argv[i]; i++) {
g_free(swtpm_argv[i]);
}
return succ;
}
void tpm_util_swtpm_kill(GPid pid)
{
int n;
if (!pid) {
return;
}
g_spawn_close_pid(pid);
n = kill(pid, 0);
if (n < 0) {
return;
}
kill(pid, SIGKILL);
}
void tpm_util_migrate(QTestState *who, const char *uri)
{
QDict *rsp;
rsp = qtest_qmp(who,
"{ 'execute': 'migrate', 'arguments': { 'uri': %s } }",
uri);
g_assert(qdict_haskey(rsp, "return"));
qobject_unref(rsp);
}
void tpm_util_wait_for_migration_complete(QTestState *who)
{
while (true) {
QDict *rsp_return;
bool completed;
const char *status;
qtest_qmp_send(who, "{ 'execute': 'query-migrate' }");
rsp_return = qtest_qmp_receive_success(who, NULL, NULL);
status = qdict_get_str(rsp_return, "status");
completed = strcmp(status, "completed") == 0;
g_assert_cmpstr(status, !=, "failed");
qobject_unref(rsp_return);
if (completed) {
return;
}
usleep(1000);
}
}
void tpm_util_migration_start_qemu(QTestState **src_qemu,
QTestState **dst_qemu,
SocketAddress *src_tpm_addr,
SocketAddress *dst_tpm_addr,
const char *miguri,
const char *ifmodel,
const char *machine_options)
{
char *src_qemu_args, *dst_qemu_args;
src_qemu_args = g_strdup_printf(
"%s "
"-chardev socket,id=chr,path=%s "
"-tpmdev emulator,id=dev,chardev=chr "
"-device %s,tpmdev=dev ",
machine_options ? : "", src_tpm_addr->u.q_unix.path, ifmodel);
*src_qemu = qtest_init(src_qemu_args);
dst_qemu_args = g_strdup_printf(
"%s "
"-chardev socket,id=chr,path=%s "
"-tpmdev emulator,id=dev,chardev=chr "
"-device %s,tpmdev=dev "
"-incoming %s",
machine_options ? : "",
dst_tpm_addr->u.q_unix.path,
ifmodel, miguri);
*dst_qemu = qtest_init(dst_qemu_args);
free(src_qemu_args);
free(dst_qemu_args);
}