From patchwork Fri Nov 1 18:57:14 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: dan tan X-Patchwork-Id: 2005265 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=LjNgZ6OR; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Xg9Bl4BSlz1xy1 for ; Sat, 2 Nov 2024 05:59:11 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1t6wqk-0008MU-DG; Fri, 01 Nov 2024 14:58:22 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1t6wqS-0008IZ-7g; Fri, 01 Nov 2024 14:58:05 -0400 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1t6wqN-0000gP-Pj; Fri, 01 Nov 2024 14:58:02 -0400 Received: from pps.filterd (m0353725.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4A1GHaN8003796; Fri, 1 Nov 2024 18:57:56 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to; s=pp1; bh=DxbIC6 leOuRpxsG3FC7FXGuDy63cQWmFy3Ljbh1Skr0=; b=LjNgZ6ORXzvbBNIigCCoOC h4QIpBgN0ayJfAVC4maSS7hwfFPqJAHM6XnvmAMp4txMux5Lu0gP09n0ZW6sQmsM zrVs0ZI7QFTk2htDFMCDKL5X3t356BGrtuxAOYxMByMaZeNoyqjUygEtclFYwH/M r8iSGst/9m3SLLb8vl60kWcKDABPf3uDd/BUWusEbzRuC+MhsmtCYW9dTv0N39iD WZSbcOn0Qm252Ha7p1mHfsBKiUrnshWgtMkOc8cGkAKrZ19km4fyD+xj6bbQP6t/ uj/LYpy06G/Bn34fJ+Elccn3ge+6mtn+5v8fYHq5wX+7LO4kHLdZ1bk1dDnEhgSw == Received: from ppma11.dal12v.mail.ibm.com (db.9e.1632.ip4.static.sl-reverse.com [50.22.158.219]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 42mvp221da-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 01 Nov 2024 18:57:55 +0000 (GMT) Received: from pps.filterd (ppma11.dal12v.mail.ibm.com [127.0.0.1]) by ppma11.dal12v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 4A1HmbFu015836; Fri, 1 Nov 2024 18:57:55 GMT Received: from smtprelay03.dal12v.mail.ibm.com ([172.16.1.5]) by ppma11.dal12v.mail.ibm.com (PPS) with ESMTPS id 42hdf1tq34-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 01 Nov 2024 18:57:55 +0000 Received: from smtpav05.wdc07v.mail.ibm.com (smtpav05.wdc07v.mail.ibm.com [10.39.53.232]) by smtprelay03.dal12v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 4A1Ivs1I53346740 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 1 Nov 2024 18:57:54 GMT Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 79C8458059; Fri, 1 Nov 2024 18:57:54 +0000 (GMT) Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 08D6558043; Fri, 1 Nov 2024 18:57:54 +0000 (GMT) Received: from gfwa829.aus.stglabs.ibm.com (unknown [9.3.84.19]) by smtpav05.wdc07v.mail.ibm.com (Postfix) with ESMTP; Fri, 1 Nov 2024 18:57:53 +0000 (GMT) From: dan tan To: qemu-devel@nongnu.org Cc: qemu-ppc@nongnu.org, stefanb@linux.vnet.ibm.com, pbonzini@redhat.com, farosas@suse.de, lvivier@redhat.com, clg@kaod.org Subject: [PATCH v3 1/5] tpm/tpm_tis_spi: Support TPM for SPI (Serial Peripheral Interface) Date: Fri, 1 Nov 2024 13:57:14 -0500 Message-Id: <20241101185718.5847-2-dantan@linux.vnet.ibm.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241101185718.5847-1-dantan@linux.vnet.ibm.com> References: <20241101185718.5847-1-dantan@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: aPOowho5LMyDeqlutP_gjbgVAU_Bwimu X-Proofpoint-GUID: aPOowho5LMyDeqlutP_gjbgVAU_Bwimu X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1051,Hydra:6.0.680,FMLib:17.12.62.30 definitions=2024-10-15_01,2024-10-11_01,2024-09-30_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 impostorscore=0 mlxlogscore=999 spamscore=0 clxscore=1015 malwarescore=0 phishscore=0 priorityscore=1501 lowpriorityscore=0 mlxscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2409260000 definitions=main-2411010134 Received-SPF: none client-ip=148.163.158.5; envelope-from=dantan@linux.vnet.ibm.com; helo=mx0b-001b2d01.pphosted.com X-Spam_score_int: -26 X-Spam_score: -2.7 X-Spam_bar: -- X-Spam_report: (-2.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-ppc@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org Implement support for TPM via SPI interface. The SPI bus master is provided by PowerNV SPI device which is an SSI peripheral. It can uses the tpm_emulator driver backend with the external swtpm. Although the implementation is endian neutral, the SPI bus master provider, pnv_spi.c is only supported on the PowerNV platform, thus, is big endian specific. Signed-off-by: dan tan --- docs/specs/tpm.rst | 15 ++ include/sysemu/tpm.h | 3 + hw/tpm/tpm_tis_spi.c | 328 +++++++++++++++++++++++++++++++++++++++++++ hw/tpm/Kconfig | 6 + hw/tpm/meson.build | 1 + hw/tpm/trace-events | 7 + 6 files changed, 360 insertions(+) create mode 100644 hw/tpm/tpm_tis_spi.c diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst index 1ad36ad709..63c3a43c7d 100644 --- a/docs/specs/tpm.rst +++ b/docs/specs/tpm.rst @@ -24,6 +24,7 @@ QEMU files related to TPM TIS interface: - ``hw/tpm/tpm_tis_isa.c`` - ``hw/tpm/tpm_tis_sysbus.c`` - ``hw/tpm/tpm_tis_i2c.c`` + - ``hw/tpm/tpm_tis_spi.c`` - ``hw/tpm/tpm_tis.h`` Both an ISA device and a sysbus device are available. The former is @@ -33,6 +34,9 @@ Arm virt machine. An I2C device support is also provided which can be instantiated in the Arm based emulation machines. This device only supports the TPM 2 protocol. +A Serial Peripheral Interface (SPI) device support has been added to the +PowerNV emulation machines. This device only supports the TPM 2 protocol. + CRB interface ------------- @@ -371,6 +375,17 @@ attached to I2C bus, use the following command line: echo tpm_tis_i2c 0x2e > /sys/bus/i2c/devices/i2c-12/new_device +In case a PowerNV machine is emulated and you want to use a TPM device +attached to SPI bus, use the following command line (SPI bus master is +provided by PowerNV SPI device): + +.. code-block:: console + + qemu-system-ppc64 -m 2G -machine powernv10 -nographic \ + -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis-spi,tpmdev=tpm0,bus=pnv-spi-bus.4 + In case SeaBIOS is used as firmware, it should show the TPM menu item after entering the menu with 'ESC'. diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h index 1ee568b3b6..22b05110e2 100644 --- a/include/sysemu/tpm.h +++ b/include/sysemu/tpm.h @@ -49,6 +49,7 @@ struct TPMIfClass { #define TYPE_TPM_CRB "tpm-crb" #define TYPE_TPM_SPAPR "tpm-spapr" #define TYPE_TPM_TIS_I2C "tpm-tis-i2c" +#define TYPE_TPM_TIS_SPI "tpm-tis-spi" #define TPM_IS_TIS_ISA(chr) \ object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS_ISA) @@ -60,6 +61,8 @@ struct TPMIfClass { object_dynamic_cast(OBJECT(chr), TYPE_TPM_SPAPR) #define TPM_IS_TIS_I2C(chr) \ object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS_I2C) +#define TPM_IS_TIS_SPI(chr) \ + object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS_SPI) /* returns NULL unless there is exactly one TPM device */ static inline TPMIf *tpm_find(void) diff --git a/hw/tpm/tpm_tis_spi.c b/hw/tpm/tpm_tis_spi.c new file mode 100644 index 0000000000..5aacae8467 --- /dev/null +++ b/hw/tpm/tpm_tis_spi.c @@ -0,0 +1,328 @@ +/* + * QEMU PowerPC SPI TPM 2.0 model + * + * Copyright (c) 2024, IBM Corporation. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#define IBM_PONQ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/sysbus.h" +#include "hw/acpi/tpm.h" +#include "tpm_prop.h" +#include "qemu/log.h" +#include "trace.h" +#include "tpm_tis.h" +#include "hw/ssi/ssi.h" + +typedef struct TPMStateSPI { + /*< private >*/ + SSIPeripheral parent_object; + + uint8_t byte_offset; /* byte offset in transfer */ + uint8_t wait_state_cnt; /* wait state counter */ + uint8_t xfer_size; /* data size of transfer */ + uint32_t reg_addr; /* register address of transfer */ + uint32_t tis_addr; /* tis address including locty */ + + uint8_t spi_state; /* READ / WRITE / IDLE */ +#define SPI_STATE_IDLE 0 +#define SPI_STATE_WRITE 1 +#define SPI_STATE_READ 2 + + bool command; + + /*< public >*/ + TPMState tpm_state; /* not a QOM object */ + +} TPMStateSPI; + +#define CMD_BYTE_WRITE (1 << 7) +#define CMD_BYTE_XFER_SZ_MASK 0x1f +#define TIS_SPI_HIGH_ADDR_BYTE 0xd4 + +DECLARE_INSTANCE_CHECKER(TPMStateSPI, TPM_TIS_SPI, TYPE_TPM_TIS_SPI) + +static inline void tpm_tis_spi_clear_data(TPMStateSPI *spist) +{ + spist->spi_state = 0; + spist->byte_offset = 0; + spist->wait_state_cnt = 0; + spist->xfer_size = 0; + spist->reg_addr = 0; + spist->tis_addr = 0xffffffff; + + return; +} + +/* Callback from TPM to indicate that response is copied */ +static void tpm_tis_spi_request_completed(TPMIf *ti, int ret) +{ + TPMStateSPI *spist = TPM_TIS_SPI(ti); + TPMState *s = &spist->tpm_state; + + /* Inform the common code. */ + tpm_tis_request_completed(s, ret); +} + +static enum TPMVersion tpm_tis_spi_get_tpm_version(TPMIf *ti) +{ + TPMStateSPI *spist = TPM_TIS_SPI(ti); + TPMState *s = &spist->tpm_state; + + return tpm_tis_get_tpm_version(s); +} + +/* + * TCG PC Client Platform TPM Profile Specification for TPM 2.0 ver 1.05 rev 14 + * + * For system Software, the TPM has a 64-bit address of 0x0000_0000_FED4_xxxx. + * On SPI, the chipset passes the least significant 24 bits to the TPM. + * The upper bytes will be used by the chipset to select the TPM’s SPI CS# + * signal. Table 9 shows the locality based on the 16 least significant address + * bits and assume that either the LPC TPM sync or SPI TPM CS# is used. + * + */ +static void tpm_tis_spi_write(TPMStateSPI *spist, uint32_t addr, uint8_t val) +{ + TPMState *tpm_st = &spist->tpm_state; + + trace_tpm_tis_spi_write(addr, val); + tpm_tis_write_data(tpm_st, addr, val, 1); +} + +static uint8_t tpm_tis_spi_read(TPMStateSPI *spist, uint32_t addr) +{ + TPMState *tpm_st = &spist->tpm_state; + uint8_t data; + + data = tpm_tis_read_data(tpm_st, addr, 1); + trace_tpm_tis_spi_read(addr, data); + return data; +} + +static Property tpm_tis_spi_properties[] = { + DEFINE_PROP_TPMBE("tpmdev", TPMStateSPI, tpm_state.be_driver), + DEFINE_PROP_UINT32("irq", TPMStateSPI, tpm_state.irq_num, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void tpm_tis_spi_reset(DeviceState *dev) +{ + TPMStateSPI *spist = TPM_TIS_SPI(dev); + TPMState *s = &spist->tpm_state; + + tpm_tis_spi_clear_data(spist); + return tpm_tis_reset(s); +} + +static uint32_t tpm_transfer(SSIPeripheral *ss, uint32_t tx) +{ + TPMStateSPI *spist = TPM_TIS_SPI(ss); + uint32_t rx = 0; + uint8_t byte; /* reversed byte value */ + uint8_t offset = 0; /* offset of byte in payload */ + uint8_t index; /* index of data byte in transfer */ + + /* new transfer or not */ + if (spist->command) { /* new transfer start */ + if (spist->spi_state != SPI_STATE_IDLE) { + qemu_log_mask(LOG_GUEST_ERROR, "unexpected new transfer\n"); + } + spist->byte_offset = 0; + spist->wait_state_cnt = 0; + } + /* + * Explanation of wait_state: + * The original TPM model did not have wait state or "flow control" support + * built in. If you wanted to read a TPM register through SPI you sent + * the first byte with the read/write bit and size, then three address bytes + * and any additional bytes after that were don't care bytes for reads and + * the model would begin returning byte data to the SPI reader from the + * register address provided. In the real world this would mean that a + * TPM device had only the time between the 31st clock and the 32nd clock + * to fetch the register data that it had to provide to SPI MISO starting + * with the 32nd clock. + * + * In reality the TPM begins introducing a wait state at the 31st clock + * by holding MISO low. This is how it controls the "flow" of the + * operation. Once the data the TPM needs to return is ready it will + * select bit 31 + (8*N) to send back a 1 which indicates that it will + * now start returning data on MISO. + * + * The same wait states are applied to writes. In either the read or write + * case the wait state occurs between the command+address (4 bytes) and the + * data (1-n bytes) sections of the SPI frame. The code below introduces + * the support for a 32 bit wait state for P10. All reads and writes + * through the SPI interface MUST now be aware of the need to do flow + * control in order to use the TPM via SPI. + * + * In conjunction with these changes there were changes made to the SPIM + * engine that was introduced in P10 to support the 6x op code which is + * used to receive wait state 0s on the MISO line until it sees the b'1' + * come back before continuing to read real data from the SPI device(TPM). + */ + + trace_tpm_tis_spi_transfer_data("Payload byte_offset", spist->byte_offset); + /* process payload data */ + while (offset < 4) { + spist->command = false; + byte = (tx >> (24 - 8 * offset)) & 0xFF; + trace_tpm_tis_spi_transfer_data("Extracted byte", byte); + trace_tpm_tis_spi_transfer_data("Payload offset", offset); + switch (spist->byte_offset) { + case 0: /* command byte */ + if ((byte & CMD_BYTE_WRITE) == 0) { /* bit-7 */ + spist->spi_state = SPI_STATE_WRITE; + trace_tpm_tis_spi_transfer_event("spi write"); + } else { + spist->spi_state = SPI_STATE_READ; + trace_tpm_tis_spi_transfer_event("spi read"); + } + spist->xfer_size = (byte & CMD_BYTE_XFER_SZ_MASK) + 1; + trace_tpm_tis_spi_transfer_data("xfer_size", spist->xfer_size); + break; + case 1: /* 1st address byte */ + if (byte != TIS_SPI_HIGH_ADDR_BYTE) { + qemu_log_mask(LOG_GUEST_ERROR, "incorrect high address 0x%x\n", + byte); + } + spist->reg_addr = byte << 16; + trace_tpm_tis_spi_transfer_data("first addr byte", byte); + trace_tpm_tis_spi_transfer_addr("reg_addr", spist->reg_addr); + break; + case 2: /* 2nd address byte */ + spist->reg_addr |= byte << 8; + trace_tpm_tis_spi_transfer_data("second addr byte", byte); + trace_tpm_tis_spi_transfer_addr("reg_addr", spist->reg_addr); + break; + case 3: /* 3rd address byte */ + spist->reg_addr |= byte; + trace_tpm_tis_spi_transfer_data("third addr byte", byte); + trace_tpm_tis_spi_transfer_addr("reg_addr", spist->reg_addr); + break; + default: /* data bytes */ + if (spist->wait_state_cnt < 4) { + spist->wait_state_cnt++; + if (spist->wait_state_cnt == 4) { + trace_tpm_tis_spi_transfer_data("wait complete, count", + spist->wait_state_cnt); + rx = rx | (0x01 << (24 - offset * 8)); + return rx; + } else { + trace_tpm_tis_spi_transfer_data("in wait state, count", + spist->wait_state_cnt); + rx = 0; + } + } else { + index = spist->byte_offset - 4; + trace_tpm_tis_spi_transfer_data("index", index); + trace_tpm_tis_spi_transfer_data("data byte", byte); + trace_tpm_tis_spi_transfer_addr("reg_addr", spist->reg_addr); + if (index >= spist->xfer_size) { + /* + * SPI SSI framework limits both rx and tx + * to fixed 4-byte with each xfer + */ + trace_tpm_tis_spi_transfer_event("index exceeds xfer_size"); + return rx; + } + spist->tis_addr = spist->reg_addr + (index % 4); + if (spist->spi_state == SPI_STATE_WRITE) { + tpm_tis_spi_write(spist, spist->tis_addr, byte); + } else { + byte = tpm_tis_spi_read(spist, spist->tis_addr); + rx = rx | (byte << (24 - offset * 8)); + trace_tpm_tis_spi_transfer_data("byte added to response", + byte); + trace_tpm_tis_spi_transfer_data("offset", offset); + } + } + break; + } + if ((spist->wait_state_cnt == 0) || (spist->wait_state_cnt == 4)) { + offset++; + spist->byte_offset++; + } else { + break; + } + } + return rx; +} + +static int tpm_cs(SSIPeripheral *ss, bool select) +{ + TPMStateSPI *spist = TPM_TIS_SPI(ss); + + if (select) { + spist->command = false; + spist->spi_state = SPI_STATE_IDLE; + } else { + spist->command = true; + } + return 0; +} + +static void tpm_realize(SSIPeripheral *dev, Error **errp) +{ + TPMStateSPI *spist = TPM_TIS_SPI(dev); + TPMState *s = &spist->tpm_state; + + spist->command = true; + spist->spi_state = SPI_STATE_IDLE; + + if (!tpm_find()) { + error_setg(errp, "at most one TPM device is permitted"); + return; + } + + s->be_driver = qemu_find_tpm_be("tpm0"); + + if (!s->be_driver) { + error_setg(errp, "unable to find tpm backend device"); + return; + } +} + +static void tpm_tis_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + TPMIfClass *tc = TPM_IF_CLASS(klass); + SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass); + + k->transfer = tpm_transfer; + k->realize = tpm_realize; + k->set_cs = tpm_cs; + k->cs_polarity = SSI_CS_LOW; + + device_class_set_legacy_reset(dc, tpm_tis_spi_reset); + device_class_set_props(dc, tpm_tis_spi_properties); + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + + dc->desc = "PowerNV SPI TPM"; + + tc->model = TPM_MODEL_TPM_TIS; + tc->request_completed = tpm_tis_spi_request_completed; + tc->get_version = tpm_tis_spi_get_tpm_version; +} + +static const TypeInfo tpm_tis_spi_info = { + .name = TYPE_TPM_TIS_SPI, + .parent = TYPE_SSI_PERIPHERAL, + .instance_size = sizeof(TPMStateSPI), + .class_init = tpm_tis_spi_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_TPM_IF }, + { } + } +}; + +static void tpm_tis_spi_register_types(void) +{ + type_register_static(&tpm_tis_spi_info); +} + +type_init(tpm_tis_spi_register_types) diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig index a46663288c..5951c225cc 100644 --- a/hw/tpm/Kconfig +++ b/hw/tpm/Kconfig @@ -5,6 +5,12 @@ config TPM_TIS_I2C select I2C select TPM_TIS +config TPM_TIS_SPI + bool + depends on TPM + select TPM_BACKEND + select TPM_TIS + config TPM_TIS_ISA bool depends on TPM && ISA_BUS diff --git a/hw/tpm/meson.build b/hw/tpm/meson.build index 6968e60b3f..e03cfb11b9 100644 --- a/hw/tpm/meson.build +++ b/hw/tpm/meson.build @@ -2,6 +2,7 @@ system_ss.add(when: 'CONFIG_TPM_TIS', if_true: files('tpm_tis_common.c')) system_ss.add(when: 'CONFIG_TPM_TIS_ISA', if_true: files('tpm_tis_isa.c')) system_ss.add(when: 'CONFIG_TPM_TIS_SYSBUS', if_true: files('tpm_tis_sysbus.c')) system_ss.add(when: 'CONFIG_TPM_TIS_I2C', if_true: files('tpm_tis_i2c.c')) +system_ss.add(when: 'CONFIG_TPM_TIS_SPI', if_true: files('tpm_tis_spi.c')) system_ss.add(when: 'CONFIG_TPM_CRB', if_true: files('tpm_crb.c')) system_ss.add(when: 'CONFIG_TPM_TIS', if_true: files('tpm_ppi.c')) system_ss.add(when: 'CONFIG_TPM_CRB', if_true: files('tpm_ppi.c')) diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events index fa882dfefe..4b39be13e2 100644 --- a/hw/tpm/trace-events +++ b/hw/tpm/trace-events @@ -42,3 +42,10 @@ tpm_tis_i2c_recv(uint8_t data) "TPM I2C read: 0x%X" tpm_tis_i2c_send(uint8_t data) "TPM I2C write: 0x%X" tpm_tis_i2c_event(const char *event) "TPM I2C event: %s" tpm_tis_i2c_send_reg(const char *name, int reg) "TPM I2C write register: %s(0x%X)" + +# tpm_tis_spi.c +tpm_tis_spi_write(uint32_t addr, uint8_t val) "TPM SPI write - addr:0x%X 0x%x" +tpm_tis_spi_read(uint32_t addr, uint8_t val) "TPM SPI read - addr:0x%X 0x%x" +tpm_tis_spi_transfer_event(const char *event) "TPM SPI XFER event: %s" +tpm_tis_spi_transfer_data(const char *name, uint8_t val) "TPM SPI XFER: %s = 0x%x" +tpm_tis_spi_transfer_addr(const char *name, uint8_t val) "TPM SPI XFER: %s = 0x%08x" From patchwork Fri Nov 1 18:57:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: dan tan X-Patchwork-Id: 2005271 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=CI5RRPSd; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Xg9C33KyMz1xy1 for ; Sat, 2 Nov 2024 05:59:27 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1t6wr7-00009V-LQ; Fri, 01 Nov 2024 14:58:45 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1t6wqf-0008KK-FH; Fri, 01 Nov 2024 14:58:19 -0400 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1t6wqa-0000gv-7m; Fri, 01 Nov 2024 14:58:14 -0400 Received: from pps.filterd (m0353725.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4A1ADeBp020395; Fri, 1 Nov 2024 18:58:04 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=ZfhX3YeMVLxQlwGzE sKUbv3aFY83tCbWhOxV2cEhV9Y=; b=CI5RRPSdvtJPUlJnNLCI+zRb4eI0xrkqd 5vvXYDJp0Ead66gJO28K/FGftgCaxEuLcNtuqZq55iTDxHbhp6uEHp1atdrHMZFZ 55xZEqmMT4vEeRJcyUb2eQUTjNiLRoGXylB16ztTgB9gojh4cMYErL7ihYrs2Ri8 ws++UtkcQfSX0aeXNePlN9ixq6iQHHUnesYWZCbYvFUfLFZ3VwyxydoUyiM9yOjr 9dMSZiGidxlnnu/FVZktNtrM3Apeoy2fMKhtEIzRdF3PpgOY8S/aPRO0W036vC11 GCUAO08S35WXAE6DMh6QM13JzRRWTkmMVGjwrAEHoWJ1cBDKU5AoA== Received: from ppma21.wdc07v.mail.ibm.com (5b.69.3da9.ip4.static.sl-reverse.com [169.61.105.91]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 42mvp221dr-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 01 Nov 2024 18:58:03 +0000 (GMT) Received: from pps.filterd (ppma21.wdc07v.mail.ibm.com [127.0.0.1]) by ppma21.wdc07v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 4A1FwwAE013589; Fri, 1 Nov 2024 18:58:03 GMT Received: from smtprelay04.wdc07v.mail.ibm.com ([172.16.1.71]) by ppma21.wdc07v.mail.ibm.com (PPS) with ESMTPS id 42hbrnb11u-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 01 Nov 2024 18:58:03 +0000 Received: from smtpav05.wdc07v.mail.ibm.com (smtpav05.wdc07v.mail.ibm.com [10.39.53.232]) by smtprelay04.wdc07v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 4A1Iw2Vh14942826 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 1 Nov 2024 18:58:03 GMT Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id DBA0858053; Fri, 1 Nov 2024 18:58:02 +0000 (GMT) Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4757D58043; Fri, 1 Nov 2024 18:58:02 +0000 (GMT) Received: from gfwa829.aus.stglabs.ibm.com (unknown [9.3.84.19]) by smtpav05.wdc07v.mail.ibm.com (Postfix) with ESMTP; Fri, 1 Nov 2024 18:58:02 +0000 (GMT) From: dan tan To: qemu-devel@nongnu.org Cc: qemu-ppc@nongnu.org, stefanb@linux.vnet.ibm.com, pbonzini@redhat.com, farosas@suse.de, lvivier@redhat.com, clg@kaod.org Subject: [PATCH v3 2/5] tpm/tpm_tis_spi: activation for the PowerNV machines Date: Fri, 1 Nov 2024 13:57:15 -0500 Message-Id: <20241101185718.5847-3-dantan@linux.vnet.ibm.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241101185718.5847-1-dantan@linux.vnet.ibm.com> References: <20241101185718.5847-1-dantan@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: bm6tnX_kTZROYnddjg-Y6TznnQvkU-MG X-Proofpoint-GUID: bm6tnX_kTZROYnddjg-Y6TznnQvkU-MG X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1051,Hydra:6.0.680,FMLib:17.12.62.30 definitions=2024-10-15_01,2024-10-11_01,2024-09-30_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 impostorscore=0 mlxlogscore=823 spamscore=0 clxscore=1015 malwarescore=0 phishscore=0 priorityscore=1501 lowpriorityscore=0 mlxscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2409260000 definitions=main-2411010134 Received-SPF: none client-ip=148.163.158.5; envelope-from=dantan@linux.vnet.ibm.com; helo=mx0b-001b2d01.pphosted.com X-Spam_score_int: -26 X-Spam_score: -2.7 X-Spam_bar: -- X-Spam_report: (-2.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-ppc@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org The addition to ppc/Kconfig is for building this into the qemu-system-ppc64 binary. The enablement requires the following command line argument: -device tpm-tis-spi,tpmdev=tpm0,bus=pnv-spi-bus.4 Signed-off-by: dan tan --- hw/ppc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/ppc/Kconfig b/hw/ppc/Kconfig index b44d91bebb..56dcf5902e 100644 --- a/hw/ppc/Kconfig +++ b/hw/ppc/Kconfig @@ -39,6 +39,7 @@ config POWERNV select PCI_POWERNV select PCA9552 select PCA9554 + select TPM_TIS_SPI select SERIAL_ISA select SSI select SSI_M25P80 From patchwork Fri Nov 1 18:57:16 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: dan tan X-Patchwork-Id: 2005270 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=TQQjjIHR; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Xg9C24nr1z1xxJ for ; Sat, 2 Nov 2024 05:59:26 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1t6wrA-0000N7-QY; Fri, 01 Nov 2024 14:58:49 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1t6wqi-0008ML-77; Fri, 01 Nov 2024 14:58:22 -0400 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1t6wqe-0000h2-IO; Fri, 01 Nov 2024 14:58:19 -0400 Received: from pps.filterd (m0353725.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4A19n8To002392; Fri, 1 Nov 2024 18:58:07 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=+qUm+KvOHdSEsGOvt IBehCgKqVeoxJXOusPusMzEhCg=; b=TQQjjIHRxwDo+iEP7j6vmmBtuGPGaP7oC Wh5Qeo3/em97t+n1Q7OREGZGh1LzxOx/njmA0esZ4yrQrt/VubfLAWzpd3LGRUy8 O7P4uJEmoz6a4JJJ65BiRr5ThQ9aiXXEdNrDzUel7IJl6Q4UWeYekEhBap9Oefsh RPSAItQ2TWMFvY8mQVqtEwFAcaXbzQtLyXO1gybcxztySKBwJwN28hMOUx1nd2GM 7WNUbE4oUj7cMaziHYD6kjPyQ6QSH3A0n61RgPyllQvC4D6AEyB6SfzgJv0Icdkp K0rSuVOZdKPhd1fBPFgS4OaxCRIPQlr9aqhxNfEb1v78Kbm/wbVhg== Received: from ppma11.dal12v.mail.ibm.com (db.9e.1632.ip4.static.sl-reverse.com [50.22.158.219]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 42mvp221du-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 01 Nov 2024 18:58:06 +0000 (GMT) Received: from pps.filterd (ppma11.dal12v.mail.ibm.com [127.0.0.1]) by ppma11.dal12v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 4A1I9vO9015843; Fri, 1 Nov 2024 18:58:05 GMT Received: from smtprelay07.wdc07v.mail.ibm.com ([172.16.1.74]) by ppma11.dal12v.mail.ibm.com (PPS) with ESMTPS id 42hdf1tq3f-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 01 Nov 2024 18:58:05 +0000 Received: from smtpav05.wdc07v.mail.ibm.com (smtpav05.wdc07v.mail.ibm.com [10.39.53.232]) by smtprelay07.wdc07v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 4A1Iw54W29753922 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 1 Nov 2024 18:58:05 GMT Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 1F7F658059; Fri, 1 Nov 2024 18:58:05 +0000 (GMT) Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8795658053; Fri, 1 Nov 2024 18:58:04 +0000 (GMT) Received: from gfwa829.aus.stglabs.ibm.com (unknown [9.3.84.19]) by smtpav05.wdc07v.mail.ibm.com (Postfix) with ESMTP; Fri, 1 Nov 2024 18:58:04 +0000 (GMT) From: dan tan To: qemu-devel@nongnu.org Cc: qemu-ppc@nongnu.org, stefanb@linux.vnet.ibm.com, pbonzini@redhat.com, farosas@suse.de, lvivier@redhat.com, clg@kaod.org Subject: [PATCH v3 3/5] tests/qtest/tpm: add unit test to tis-spi Date: Fri, 1 Nov 2024 13:57:16 -0500 Message-Id: <20241101185718.5847-4-dantan@linux.vnet.ibm.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241101185718.5847-1-dantan@linux.vnet.ibm.com> References: <20241101185718.5847-1-dantan@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: uJkf76i9pCvuAwZo8swfNkec7rL310w3 X-Proofpoint-GUID: uJkf76i9pCvuAwZo8swfNkec7rL310w3 X-Proofpoint-UnRewURL: 0 URL was un-rewritten MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1051,Hydra:6.0.680,FMLib:17.12.62.30 definitions=2024-10-15_01,2024-10-11_01,2024-09-30_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 impostorscore=0 mlxlogscore=999 spamscore=0 clxscore=1015 malwarescore=0 phishscore=0 priorityscore=1501 lowpriorityscore=0 mlxscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2409260000 definitions=main-2411010134 Received-SPF: none client-ip=148.163.158.5; envelope-from=dantan@linux.vnet.ibm.com; helo=mx0b-001b2d01.pphosted.com X-Spam_score_int: -26 X-Spam_score: -2.7 X-Spam_bar: -- X-Spam_report: (-2.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-ppc@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org Add qtest cases to exercise main TPM locality functionality The TPM device emulation is provided by swtpm, which is TCG TPM 2.0, and TCG TPM TIS compliant. See https://trustedcomputinggroup.org/wp-content/uploads/TCG_PC_Client_Platform_TPM_Profile_PTP_2.0_r1.03_v22.pdf https://trustedcomputinggroup.org/wp-content/uploads/TCG_PCClientTPMInterfaceSpecification_TIS__1-3_27_03212013.pdf The SPI registers are specific to the PowerNV platform architecture Signed-off-by: dan tan --- hw/tpm/tpm_tis_spi.c | 2 +- tests/qtest/tpm-tis-spi-pnv-test.c | 700 +++++++++++++++++++++++++++++ tests/qtest/meson.build | 3 +- 3 files changed, 703 insertions(+), 2 deletions(-) create mode 100644 tests/qtest/tpm-tis-spi-pnv-test.c diff --git a/hw/tpm/tpm_tis_spi.c b/hw/tpm/tpm_tis_spi.c index 5aacae8467..f8a78a5cfb 100644 --- a/hw/tpm/tpm_tis_spi.c +++ b/hw/tpm/tpm_tis_spi.c @@ -302,7 +302,7 @@ static void tpm_tis_spi_class_init(ObjectClass *klass, void *data) device_class_set_props(dc, tpm_tis_spi_properties); set_bit(DEVICE_CATEGORY_MISC, dc->categories); - dc->desc = "PowerNV SPI TPM"; + dc->desc = "SPI TPM"; tc->model = TPM_MODEL_TPM_TIS; tc->request_completed = tpm_tis_spi_request_completed; diff --git a/tests/qtest/tpm-tis-spi-pnv-test.c b/tests/qtest/tpm-tis-spi-pnv-test.c new file mode 100644 index 0000000000..a367564dda --- /dev/null +++ b/tests/qtest/tpm-tis-spi-pnv-test.c @@ -0,0 +1,700 @@ +/* + * QTest testcase for a Nuvoton NPCT75x TPM SPI device + * running on the PowerNV machine. + * + * Copyright (c) 2024, IBM Corporation. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ +#include "qemu/osdep.h" +#include +#include "libqtest-single.h" +#include "hw/acpi/tpm.h" +#include "hw/pci/pci_ids.h" +#include "qtest_aspeed.h" +#include "tpm-emu.h" +#include "hw/ssi/pnv_spi_regs.h" +#include "pnv-xscom.h" + +#define SPI_TPM_BASE 0xc0080 +#define SPI_SHIFT_COUNTER_N1 0x30000000 +#define SPI_SHIFT_COUNTER_N2 0x40000000 + +#define CFG_COUNT_COMPARE_1 0x0000000200000000 +#define MM_REG_RDR_MATCH 0x00000000ff01ff00 +#define SEQ_OP_REG_BASIC 0x1134416200100000 + +#define TPM_TIS_8BITS_MASK 0xff +#define SPI_TPM_TIS_ADDR 0xd40000 +#define TPM_WRITE_OP 0x0 +#define TPM_READ_OP 0x80 + +#define SHORT_MAX_RETRIES 5 +#define LONG_MAX_RETRIES 10 + +static const uint8_t TPM_CMD[12] = + "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"; + +#define DPRINTF(fmt, ...) do { \ + if (DEBUG_TIS_TEST) { \ + printf(fmt, ## __VA_ARGS__); \ + } \ +} while (0) + +#define DEBUG_TIS_TEST 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 uint64_t pnv_spi_tpm_read(const PnvChip *chip, uint32_t reg); +static void pnv_spi_tpm_write(const PnvChip *chip, uint32_t reg, uint64_t val); +static uint64_t spi_read_reg(const PnvChip *chip); +static void spi_write_reg(const PnvChip *chip, uint64_t val); +static void spi_access_start(const PnvChip *chip, bool n2, uint8_t bytes, + uint8_t tpm_op, uint32_t tpm_reg); + +static inline void tpm_reg_writeb(const PnvChip *c, + int locl, + uint8_t reg, + uint8_t val) +{ + uint32_t tpm_reg_locl = SPI_TPM_TIS_ADDR | (locl << TPM_TIS_LOCALITY_SHIFT); + + spi_access_start(c, false, 1, TPM_WRITE_OP, tpm_reg_locl | reg); + spi_write_reg(c, bswap64(val)); +} + +static inline uint8_t tpm_reg_readb(const PnvChip *c, int locl, uint8_t reg) +{ + uint32_t tpm_reg_locl = SPI_TPM_TIS_ADDR | (locl << TPM_TIS_LOCALITY_SHIFT); + + spi_access_start(c, true, 1, TPM_READ_OP, tpm_reg_locl | reg); + return spi_read_reg(c); +} + +static inline void tpm_reg_writew(const PnvChip *c, + int locl, + uint8_t reg, + uint32_t val) +{ + int i; + + for (i = 0; i < 4; i++) { + tpm_reg_writeb(c, locl, reg + i, ((val >> (8 * i)) & 0xff)); + } +} + +static inline uint32_t tpm_reg_readw(const PnvChip *c, int locl, uint8_t reg) +{ + uint32_t val = 0; + int i; + + for (i = 0; i < 4; i++) { + val |= tpm_reg_readb(c, locl, reg + i) << (8 * i); + } + return val; +} + +static void pnv_spi_tpm_write(const PnvChip *chip, + uint32_t reg, + uint64_t val) +{ + uint32_t pcba = SPI_TPM_BASE + reg; + qtest_writeq(global_qtest, pnv_xscom_addr(chip, pcba), val); +} + +static uint64_t pnv_spi_tpm_read(const PnvChip *chip, uint32_t reg) +{ + uint32_t pcba = SPI_TPM_BASE + reg; + return qtest_readq(global_qtest, pnv_xscom_addr(chip, pcba)); +} + +static void spi_access_start(const PnvChip *chip, + bool n2, + uint8_t bytes, + uint8_t tpm_op, + uint32_t tpm_reg) +{ + uint64_t cfg_reg; + uint64_t reg_op; + uint64_t seq_op = SEQ_OP_REG_BASIC; + + cfg_reg = pnv_spi_tpm_read(chip, SPI_CLK_CFG_REG); + if (cfg_reg != CFG_COUNT_COMPARE_1) { + pnv_spi_tpm_write(chip, SPI_CLK_CFG_REG, CFG_COUNT_COMPARE_1); + } + /* bytes - sequencer operation register bits 24:31 */ + if (n2) { + seq_op |= SPI_SHIFT_COUNTER_N2 | (bytes << 0x18); + } else { + seq_op |= SPI_SHIFT_COUNTER_N1 | (bytes << 0x18); + } + pnv_spi_tpm_write(chip, SPI_SEQ_OP_REG, seq_op); + pnv_spi_tpm_write(chip, SPI_MM_REG, MM_REG_RDR_MATCH); + pnv_spi_tpm_write(chip, SPI_CTR_CFG_REG, (uint64_t)0); + reg_op = bswap64(tpm_op) | ((uint64_t)tpm_reg << 0x20); + pnv_spi_tpm_write(chip, SPI_XMIT_DATA_REG, reg_op); +} + +static void spi_op_complete(const PnvChip *chip) +{ + uint64_t cfg_reg; + + cfg_reg = pnv_spi_tpm_read(chip, SPI_CLK_CFG_REG); + g_assert_cmpuint(CFG_COUNT_COMPARE_1, ==, cfg_reg); + pnv_spi_tpm_write(chip, SPI_CLK_CFG_REG, 0); +} + +static void spi_write_reg(const PnvChip *chip, uint64_t val) +{ + int i; + uint64_t spi_sts; + + for (i = 0; i < LONG_MAX_RETRIES; i++) { + spi_sts = pnv_spi_tpm_read(chip, SPI_STS_REG); + if (GETFIELD(SPI_STS_TDR_FULL, spi_sts) == 1) { + sleep(0.5); + } else { + break; + } + } + /* cannot write if SPI_STS_TDR_FULL bit is still set */ + g_assert_cmpuint(0, ==, GETFIELD(SPI_STS_TDR_FULL, spi_sts)); + pnv_spi_tpm_write(chip, SPI_XMIT_DATA_REG, val); + + for (i = 0; i < SHORT_MAX_RETRIES; i++) { + spi_sts = pnv_spi_tpm_read(chip, SPI_STS_REG); + if (GETFIELD(SPI_STS_SHIFTER_FSM, spi_sts) & FSM_DONE) { + break; + } else { + sleep(0.1); + } + } + /* it should be done given the amount of time */ + g_assert_cmpuint(0, ==, GETFIELD(SPI_STS_SHIFTER_FSM, spi_sts) & FSM_DONE); + spi_op_complete(chip); +} + +static uint64_t spi_read_reg(const PnvChip *chip) +{ + int i; + uint64_t spi_sts, val = 0; + + for (i = 0; i < LONG_MAX_RETRIES; i++) { + spi_sts = pnv_spi_tpm_read(chip, SPI_STS_REG); + if (GETFIELD(SPI_STS_RDR_FULL, spi_sts) == 1) { + val = pnv_spi_tpm_read(chip, SPI_RCV_DATA_REG); + break; + } + sleep(0.5); + } + for (i = 0; i < SHORT_MAX_RETRIES; i++) { + spi_sts = pnv_spi_tpm_read(chip, SPI_STS_REG); + if (GETFIELD(SPI_STS_RDR_FULL, spi_sts) == 1) { + sleep(0.1); + } else { + break; + } + } + /* SPI_STS_RDR_FULL bit should be reset after read */ + g_assert_cmpuint(0, ==, GETFIELD(SPI_STS_RDR_FULL, spi_sts)); + spi_op_complete(chip); + return val; +} + +static void tpm_set_verify_loc(const PnvChip *chip, uint8_t loc) +{ + uint8_t access; + uint32_t tpm_sts; + + g_test_message("TPM locality %d tests:", loc); + access = tpm_reg_readb(chip, loc, TPM_TIS_REG_ACCESS); + g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | + TPM_TIS_ACCESS_TPM_ESTABLISHMENT); + + tpm_reg_writeb(chip, loc, TPM_TIS_REG_ACCESS, TPM_TIS_ACCESS_SEIZE); + tpm_reg_writeb(chip, loc, TPM_TIS_REG_ACCESS, TPM_TIS_ACCESS_REQUEST_USE); + + access = tpm_reg_readb(chip, loc, 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); + g_test_message("\tACCESS REG = 0x%x checked", access); + + /* test tpm status register */ + tpm_sts = tpm_reg_readw(chip, loc, TPM_TIS_REG_STS); + g_assert_cmpuint((tpm_sts & TPM_TIS_8BITS_MASK), ==, 0); + g_test_message("\tTPM STATUS: 0x%x, verified", tpm_sts); + + /* release access */ + tpm_reg_writeb(chip, loc, TPM_TIS_REG_ACCESS, + TPM_TIS_ACCESS_ACTIVE_LOCALITY); + access = tpm_reg_readb(chip, loc, TPM_TIS_REG_ACCESS); + g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | + TPM_TIS_ACCESS_TPM_ESTABLISHMENT); + g_test_message("\tRELEASED ACCESS: 0x%x, checked", access); +} + +static void test_spi_tpm_basic(const void *data) +{ + const PnvChip *chip = data; + uint32_t didvid, tpm_sts, en_int; + uint8_t access; + + g_test_message("TPM TIS SPI interface basic tests:"); + /* vendor ID and device ID ... check against the known value*/ + spi_access_start(chip, true, 4, 0x83, + SPI_TPM_TIS_ADDR | TPM_TIS_REG_DID_VID); + didvid = spi_read_reg(chip); + g_assert_cmpint((didvid >> 16), ==, bswap16(TPM_TIS_TPM_VID)); + g_assert_cmpint((didvid & 0xffff), ==, bswap16(TPM_TIS_TPM_DID)); + g_test_message("\tDID_VID = 0x%x, verified", didvid); + + /* access register, default see TCG TIS Spec (v1.3) table-14 */ + access = tpm_reg_readb(chip, 0, TPM_TIS_REG_ACCESS); + g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | + TPM_TIS_ACCESS_TPM_ESTABLISHMENT); + g_test_message("\tACCESS REG = 0x%x, checked", access); + + /* interrupt enable register, default see TCG TIS Spec (v1.3) table-19 */ + en_int = tpm_reg_readw(chip, 0, TPM_TIS_REG_INT_ENABLE); + g_assert_cmpuint(en_int, ==, TPM_TIS_INT_POLARITY_LOW_LEVEL); + g_test_message("\tINT ENABLE REG: 0x%x, verified", en_int); + + /* status register, default see TCG TIS Spec (v1.3) table-15 */ + tpm_sts = tpm_reg_readw(chip, 0, TPM_TIS_REG_STS); + /* for no active locality */ + g_assert_cmpuint(tpm_sts, ==, 0xffffffff); + g_test_message("\tTPM STATUS: 0x%x, verified", tpm_sts); +} + +static void test_spi_tpm_locality(const void *data) +{ + const PnvChip *chip = data; + uint8_t locality; + + /* Locality 4 has special security restrictions, testing 0-3 */ + for (locality = 0; locality < TPM_TIS_NUM_LOCALITIES - 1; locality++) { + tpm_set_verify_loc(chip, locality); + } +} + +/* + * Test case for seizing access by a higher number locality + */ +static void test_spi_tpm_access_seize_test(const void *data) +{ + const PnvChip *chip = data; + int locty, l; + uint8_t access; + uint8_t pending_request_flag; + + g_test_message("TPM TIS SPI access seize tests:"); + /* do not test locality 4 (hw only) */ + for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { + pending_request_flag = 0; + + access = tpm_reg_readb(chip, 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 */ + tpm_reg_writeb(chip, locty, TPM_TIS_REG_ACCESS, + TPM_TIS_ACCESS_REQUEST_USE); + + access = tpm_reg_readb(chip, 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 = tpm_reg_readb(chip, 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' */ + tpm_reg_writeb(chip, 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 = tpm_reg_readb(chip, 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 = tpm_reg_readb(chip, 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' */ + tpm_reg_writeb(chip, l, TPM_TIS_REG_ACCESS, TPM_TIS_ACCESS_SEIZE); + /* seize from 'l' was not possible */ + access = tpm_reg_readb(chip, 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 = tpm_reg_readb(chip, 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' */ + tpm_reg_writeb(chip, 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 = tpm_reg_readb(chip, 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 = tpm_reg_readb(chip, 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' */ + tpm_reg_writeb(chip, l, TPM_TIS_REG_ACCESS, TPM_TIS_ACCESS_SEIZE); + + /* seize from 'l' was possible */ + access = tpm_reg_readb(chip, 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 = tpm_reg_readb(chip, 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 */ + tpm_reg_writeb(chip, l - 1, TPM_TIS_REG_ACCESS, + TPM_TIS_ACCESS_BEEN_SEIZED); + + access = tpm_reg_readb(chip, 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 = tpm_reg_readb(chip, l, TPM_TIS_REG_ACCESS); + DPRINTF_ACCESS; + + DPRINTF("%s: %d: relinquishing control on l = %d\n", + __func__, __LINE__, l); + tpm_reg_writeb(chip, l, TPM_TIS_REG_ACCESS, + TPM_TIS_ACCESS_ACTIVE_LOCALITY); + + access = tpm_reg_readb(chip, 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 = tpm_reg_readb(chip, 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 */ + tpm_reg_writeb(chip, 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 = tpm_reg_readb(chip, l, TPM_TIS_REG_ACCESS); + DPRINTF_ACCESS; + g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | + TPM_TIS_ACCESS_TPM_ESTABLISHMENT); + } + g_test_message("\tTPM locality %d seize tests: passed", locty); + } +} + +/* + * Test case for getting access when higher number locality relinquishes access + */ +static void test_spi_tpm_access_release_test(const void *data) +{ + const PnvChip *chip = data; + int locty, l; + uint8_t access; + uint8_t pending_request_flag; + + g_test_message("TPM TIS SPI access release tests:"); + /* do not test locality 4 (hw only) */ + for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) { + pending_request_flag = 0; + + access = tpm_reg_readb(chip, 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 */ + tpm_reg_writeb(chip, locty, TPM_TIS_REG_ACCESS, + TPM_TIS_ACCESS_REQUEST_USE); + access = tpm_reg_readb(chip, 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 + */ + tpm_reg_writeb(chip, l, TPM_TIS_REG_ACCESS, + TPM_TIS_ACCESS_REQUEST_USE); + access = tpm_reg_readb(chip, 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' */ + tpm_reg_writeb(chip, locty, TPM_TIS_REG_ACCESS, + TPM_TIS_ACCESS_ACTIVE_LOCALITY); + /* + * highest locality should now be active; release it and make sure the + * next highest locality is active afterwards + */ + for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) { + if (l == locty) { + continue; + } + /* 'l' should be active now */ + access = tpm_reg_readb(chip, 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 */ + tpm_reg_writeb(chip, l, TPM_TIS_REG_ACCESS, + TPM_TIS_ACCESS_ACTIVE_LOCALITY); + access = tpm_reg_readb(chip, 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); + } + g_test_message("\tTPM locality %d seize tests: passed", locty); + } +} + +/* + * Test case for transmitting packets + */ +static void test_spi_tpm_transmit_test(const void *data) +{ + const PnvChip *chip = data; + uint16_t bcount; + uint8_t access; + uint32_t sts; + int i; + + g_test_message("TPM TIS SPI transmit tests:"); + /* request use of locality 0 */ + tpm_reg_writeb(chip, 0, TPM_TIS_REG_ACCESS, TPM_TIS_ACCESS_REQUEST_USE); + access = tpm_reg_readb(chip, 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 = tpm_reg_readw(chip, 0, TPM_TIS_REG_STS); + DPRINTF_STS; + + g_assert_cmpint(sts & 0xff, ==, 0); + + bcount = (sts >> 8) & 0xffff; + g_test_message("\t\tbcount: %x, sts: %x", bcount, sts); + g_assert_cmpint(bcount, >=, 128); + + tpm_reg_writew(chip, 0, TPM_TIS_REG_STS, TPM_TIS_STS_COMMAND_READY); + sts = tpm_reg_readw(chip, 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++) { + tpm_reg_writeb(chip, 0, TPM_TIS_REG_DATA_FIFO, TPM_CMD[i]); + sts = tpm_reg_readw(chip, 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_test_message("\ttransmit tests, check TPM_TIS_STS_EXPECT"); + + /* start processing */ + tpm_reg_writew(chip, 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 = tpm_reg_readw(chip, 0, TPM_TIS_REG_STS); + if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) { + break; + } + } while (g_get_monotonic_time() < end_time); + + sts = tpm_reg_readw(chip, 0, TPM_TIS_REG_STS); + DPRINTF_STS; + g_assert_cmpint(sts & 0xff, == , TPM_TIS_STS_VALID | + TPM_TIS_STS_DATA_AVAILABLE); + /* TCG TIS Spec (v1.3) table-15 */ + g_test_message("\ttransmit tests, check tpmGo (w) & dataAvail (r)"); + 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] = tpm_reg_readb(chip, 0, TPM_TIS_REG_DATA_FIFO); + sts = tpm_reg_readw(chip, 0, TPM_TIS_REG_STS); + DPRINTF_STS; + if (sts & TPM_TIS_STS_DATA_AVAILABLE) { + g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); + } + } + g_test_message("\treceive tests, passed"); + /* relinquish use of locality 0 */ + tpm_reg_writeb(chip, 0, TPM_TIS_REG_ACCESS, TPM_TIS_ACCESS_ACTIVE_LOCALITY); + access = tpm_reg_readb(chip, 0, TPM_TIS_REG_ACCESS); +} + +int main(int argc, char **argv) +{ + int ret; + char *args; + GThread *thread; + TPMTestState test; + g_autofree char *tmp_path = g_dir_make_tmp("qemu-tpm-tis-spi-test.XXXXXX", + NULL); + + 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; + test.tpm_version = TPM_VERSION_2_0; + + thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test); + tpm_emu_test_wait_cond(&test); + + args = g_strdup_printf("-m 2G -machine powernv10 -smp 2,cores=2," + "threads=1 -accel tcg,thread=single -nographic " + "-chardev socket,id=chrtpm,path=%s " + "-tpmdev emulator,id=tpm0,chardev=chrtpm " + "-device tpm-tis-spi,tpmdev=tpm0,bus=pnv-spi-bus.4", + test.addr->u.q_unix.path); + qtest_start(args); + qtest_add_data_func("pnv-xscom/tpm-tis-spi/basic_test", + &pnv_chips[3], test_spi_tpm_basic); + qtest_add_data_func("pnv-xscom/tpm-tis-spi/locality_test", + &pnv_chips[3], test_spi_tpm_locality); + qtest_add_data_func("pnv-xscom/tpm-tis-spi/access_seize_test", + &pnv_chips[3], test_spi_tpm_access_seize_test); + qtest_add_data_func("pnv-xscom/tpm-tis-spi/access_release_test", + &pnv_chips[3], test_spi_tpm_access_release_test); + qtest_add_data_func("pnv-xscom/tpm-tis-spi/data_transmit_test", + &pnv_chips[3], test_spi_tpm_transmit_test); + 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(args); + return ret; +} + diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index e8be8b3942..6b1aed929e 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -4,7 +4,6 @@ slow_qtests = { 'bios-tables-test' : 910, 'cdrom-test' : 610, 'device-introspect-test' : 720, - 'ide-test' : 120, 'migration-test' : 480, 'npcm7xx_pwm-test': 300, 'npcm7xx_watchdog_timer-test': 120, @@ -177,6 +176,7 @@ qtests_ppc64 = \ (config_all_devices.has_key('CONFIG_PSERIES') ? ['device-plug-test'] : []) + \ (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-xscom-test'] : []) + \ (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-spi-seeprom-test'] : []) + \ + (config_all_devices.has_key('CONFIG_POWERNV') ? ['tpm-tis-spi-pnv-test'] : []) + \ (config_all_devices.has_key('CONFIG_POWERNV') ? ['pnv-host-i2c-test'] : []) + \ (config_all_devices.has_key('CONFIG_PSERIES') ? ['numa-test'] : []) + \ (config_all_devices.has_key('CONFIG_PSERIES') ? ['rtas-test'] : []) + \ @@ -348,6 +348,7 @@ qtests = { 'tpm-tis-i2c-test': [io, tpmemu_files, 'qtest_aspeed.c'], 'tpm-tis-device-swtpm-test': [io, tpmemu_files, 'tpm-tis-util.c'], 'tpm-tis-device-test': [io, tpmemu_files, 'tpm-tis-util.c'], + 'tpm-tis-spi-pnv-test': [io, tpmemu_files], 'virtio-net-failover': files('migration-helpers.c'), 'vmgenid-test': files('boot-sector.c', 'acpi-utils.c'), 'netdev-socket': files('netdev-socket.c', '../unit/socket-helpers.c'), From patchwork Fri Nov 1 18:57:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: dan tan X-Patchwork-Id: 2005267 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=afgAPF1L; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Xg9Bt1VBkz1xxJ for ; Sat, 2 Nov 2024 05:59:18 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1t6wr9-0000Ge-AJ; Fri, 01 Nov 2024 14:58:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1t6wqk-0008MQ-D7; Fri, 01 Nov 2024 14:58:22 -0400 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1t6wqf-0000h8-Gl; Fri, 01 Nov 2024 14:58:20 -0400 Received: from pps.filterd (m0353725.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4A1EDBA5009800; Fri, 1 Nov 2024 18:58:08 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=/Ire+iRT6u4Xu8Mox /MonYXMU7+liJcoBxBsK6HtmsY=; b=afgAPF1LixpbSLcODafMJNW6wsQo9ZmWk oauqh9wAAf1k3YSmLV7eekkQj89Mpy0VZ7FsYNDffiW1+2/paWMhLGKB+8Y72Yj3 fkF1s7tAorv8MUVdqJUON1x/Jme+163ZWx0lwyHg0aBlo505FSRUMst58rR0nMUQ BKXk6INGSkXAJAxxjD//2pXah0VomAWCMis568UU8k7IGnI86DOaL6Fl2oYipHP8 FUy6J1bevIVJA5ILNiXqToizIee23CaUH0vVqxHeVDg1M+UmFJWjrxwW54Cd8XvO aBWld8qd7IpJxzd2XmPU76xP1kgGZG86JRY4WcsCszHlJzW/M1G7g== Received: from ppma11.dal12v.mail.ibm.com (db.9e.1632.ip4.static.sl-reverse.com [50.22.158.219]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 42mvp221e2-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 01 Nov 2024 18:58:08 +0000 (GMT) Received: from pps.filterd (ppma11.dal12v.mail.ibm.com [127.0.0.1]) by ppma11.dal12v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 4A1H7ogL015807; Fri, 1 Nov 2024 18:58:07 GMT Received: from smtprelay03.dal12v.mail.ibm.com ([172.16.1.5]) by ppma11.dal12v.mail.ibm.com (PPS) with ESMTPS id 42hdf1tq3k-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 01 Nov 2024 18:58:07 +0000 Received: from smtpav05.wdc07v.mail.ibm.com (smtpav05.wdc07v.mail.ibm.com [10.39.53.232]) by smtprelay03.dal12v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 4A1Iw7jX46727528 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 1 Nov 2024 18:58:07 GMT Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 122E458043; Fri, 1 Nov 2024 18:58:07 +0000 (GMT) Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 97D4958059; Fri, 1 Nov 2024 18:58:06 +0000 (GMT) Received: from gfwa829.aus.stglabs.ibm.com (unknown [9.3.84.19]) by smtpav05.wdc07v.mail.ibm.com (Postfix) with ESMTP; Fri, 1 Nov 2024 18:58:06 +0000 (GMT) From: dan tan To: qemu-devel@nongnu.org Cc: qemu-ppc@nongnu.org, stefanb@linux.vnet.ibm.com, pbonzini@redhat.com, farosas@suse.de, lvivier@redhat.com, clg@kaod.org Subject: [PATCH v3 4/5] tpm/tpm_tis_spi: Support TPM for SPI (rev 3) Date: Fri, 1 Nov 2024 13:57:17 -0500 Message-Id: <20241101185718.5847-5-dantan@linux.vnet.ibm.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241101185718.5847-1-dantan@linux.vnet.ibm.com> References: <20241101185718.5847-1-dantan@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: DK9MwrArQ6Mmmrg0WHpc5XfZCNb1eXqz X-Proofpoint-GUID: DK9MwrArQ6Mmmrg0WHpc5XfZCNb1eXqz X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1051,Hydra:6.0.680,FMLib:17.12.62.30 definitions=2024-10-15_01,2024-10-11_01,2024-09-30_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 impostorscore=0 mlxlogscore=999 spamscore=0 clxscore=1015 malwarescore=0 phishscore=0 priorityscore=1501 lowpriorityscore=0 mlxscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2409260000 definitions=main-2411010134 Received-SPF: none client-ip=148.163.158.5; envelope-from=dantan@linux.vnet.ibm.com; helo=mx0b-001b2d01.pphosted.com X-Spam_score_int: -26 X-Spam_score: -2.7 X-Spam_bar: -- X-Spam_report: (-2.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-ppc@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org - moved variable tis_addr from TPMStateSPI struct to local - added the VM suspend/resume support: - added vmstate_tpm_tis_spi declaration - added tpm_tis_spi_pre_save() function - fixed trace formatting string Signed-off-by: dan tan --- hw/tpm/tpm_tis_spi.c | 50 ++++++++++++++++++++++++++++++++++++-------- hw/tpm/trace-events | 8 +++---- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/hw/tpm/tpm_tis_spi.c b/hw/tpm/tpm_tis_spi.c index f8a78a5cfb..4aee1c6d6c 100644 --- a/hw/tpm/tpm_tis_spi.c +++ b/hw/tpm/tpm_tis_spi.c @@ -17,6 +17,7 @@ #include "trace.h" #include "tpm_tis.h" #include "hw/ssi/ssi.h" +#include "migration/vmstate.h" typedef struct TPMStateSPI { /*< private >*/ @@ -26,7 +27,6 @@ typedef struct TPMStateSPI { uint8_t wait_state_cnt; /* wait state counter */ uint8_t xfer_size; /* data size of transfer */ uint32_t reg_addr; /* register address of transfer */ - uint32_t tis_addr; /* tis address including locty */ uint8_t spi_state; /* READ / WRITE / IDLE */ #define SPI_STATE_IDLE 0 @@ -46,14 +46,47 @@ typedef struct TPMStateSPI { DECLARE_INSTANCE_CHECKER(TPMStateSPI, TPM_TIS_SPI, TYPE_TPM_TIS_SPI) +static int tpm_tis_spi_pre_save(void *opaque) +{ + TPMStateSPI *spist = opaque; + + return tpm_tis_pre_save(&spist->tpm_state); +} + +static const VMStateDescription vmstate_tpm_tis_spi = { + .name = "tpm-tis-spi", + .version_id = 0, + .pre_save = tpm_tis_spi_pre_save, + .fields = (const VMStateField[]) { + VMSTATE_BUFFER(tpm_state.buffer, TPMStateSPI), + VMSTATE_UINT16(tpm_state.rw_offset, TPMStateSPI), + VMSTATE_UINT8(tpm_state.active_locty, TPMStateSPI), + VMSTATE_UINT8(tpm_state.aborting_locty, TPMStateSPI), + VMSTATE_UINT8(tpm_state.next_locty, TPMStateSPI), + + VMSTATE_STRUCT_ARRAY(tpm_state.loc, TPMStateSPI, + TPM_TIS_NUM_LOCALITIES, 0, + vmstate_locty, TPMLocality), + + /* spi specifics */ + VMSTATE_UINT8(byte_offset, TPMStateSPI), + VMSTATE_UINT8(wait_state_cnt, TPMStateSPI), + VMSTATE_UINT8(xfer_size, TPMStateSPI), + VMSTATE_UINT32(reg_addr, TPMStateSPI), + VMSTATE_UINT8(spi_state, TPMStateSPI), + VMSTATE_BOOL(command, TPMStateSPI), + + VMSTATE_END_OF_LIST() + } +}; + static inline void tpm_tis_spi_clear_data(TPMStateSPI *spist) { - spist->spi_state = 0; + spist->spi_state = SPI_STATE_IDLE; spist->byte_offset = 0; spist->wait_state_cnt = 0; spist->xfer_size = 0; spist->reg_addr = 0; - spist->tis_addr = 0xffffffff; return; } @@ -126,6 +159,7 @@ static uint32_t tpm_transfer(SSIPeripheral *ss, uint32_t tx) uint8_t byte; /* reversed byte value */ uint8_t offset = 0; /* offset of byte in payload */ uint8_t index; /* index of data byte in transfer */ + uint32_t tis_addr; /* tis address including locty */ /* new transfer or not */ if (spist->command) { /* new transfer start */ @@ -230,11 +264,11 @@ static uint32_t tpm_transfer(SSIPeripheral *ss, uint32_t tx) trace_tpm_tis_spi_transfer_event("index exceeds xfer_size"); return rx; } - spist->tis_addr = spist->reg_addr + (index % 4); + tis_addr = spist->reg_addr + (index % 4); if (spist->spi_state == SPI_STATE_WRITE) { - tpm_tis_spi_write(spist, spist->tis_addr, byte); + tpm_tis_spi_write(spist, tis_addr, byte); } else { - byte = tpm_tis_spi_read(spist, spist->tis_addr); + byte = tpm_tis_spi_read(spist, tis_addr); rx = rx | (byte << (24 - offset * 8)); trace_tpm_tis_spi_transfer_data("byte added to response", byte); @@ -271,9 +305,6 @@ static void tpm_realize(SSIPeripheral *dev, Error **errp) TPMStateSPI *spist = TPM_TIS_SPI(dev); TPMState *s = &spist->tpm_state; - spist->command = true; - spist->spi_state = SPI_STATE_IDLE; - if (!tpm_find()) { error_setg(errp, "at most one TPM device is permitted"); return; @@ -303,6 +334,7 @@ static void tpm_tis_spi_class_init(ObjectClass *klass, void *data) set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->desc = "SPI TPM"; + dc->vmsd = &vmstate_tpm_tis_spi; tc->model = TPM_MODEL_TPM_TIS; tc->request_completed = tpm_tis_spi_request_completed; diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events index 4b39be13e2..0324ceb6d0 100644 --- a/hw/tpm/trace-events +++ b/hw/tpm/trace-events @@ -44,8 +44,8 @@ tpm_tis_i2c_event(const char *event) "TPM I2C event: %s" tpm_tis_i2c_send_reg(const char *name, int reg) "TPM I2C write register: %s(0x%X)" # tpm_tis_spi.c -tpm_tis_spi_write(uint32_t addr, uint8_t val) "TPM SPI write - addr:0x%X 0x%x" -tpm_tis_spi_read(uint32_t addr, uint8_t val) "TPM SPI read - addr:0x%X 0x%x" +tpm_tis_spi_write(uint32_t addr, uint8_t val) "TPM SPI write - addr:0x%08X 0x%02x" +tpm_tis_spi_read(uint32_t addr, uint8_t val) "TPM SPI read - addr:0x%08X 0x%02x" tpm_tis_spi_transfer_event(const char *event) "TPM SPI XFER event: %s" -tpm_tis_spi_transfer_data(const char *name, uint8_t val) "TPM SPI XFER: %s = 0x%x" -tpm_tis_spi_transfer_addr(const char *name, uint8_t val) "TPM SPI XFER: %s = 0x%08x" +tpm_tis_spi_transfer_data(const char *name, uint8_t val) "TPM SPI XFER: %s = 0x%02x" +tpm_tis_spi_transfer_addr(const char *name, uint32_t addr) "TPM SPI XFER: %s = 0x%08x" From patchwork Fri Nov 1 18:57:18 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: dan tan X-Patchwork-Id: 2005261 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=J9WK/x12; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=nongnu.org (client-ip=209.51.188.17; helo=lists.gnu.org; envelope-from=qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=patchwork.ozlabs.org) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4Xg9BS5B8cz1xxJ for ; Sat, 2 Nov 2024 05:58:56 +1100 (AEDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1t6wr9-0000J3-Qj; Fri, 01 Nov 2024 14:58:47 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1t6wqn-0008Nk-VR; Fri, 01 Nov 2024 14:58:30 -0400 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1t6wqk-0000hS-F8; Fri, 01 Nov 2024 14:58:24 -0400 Received: from pps.filterd (m0353725.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.2/8.18.1.2) with ESMTP id 4A1ADeBq020395; Fri, 1 Nov 2024 18:58:13 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=Pv72VnSejRlgiFSQY 1UG+jF1ibI3kQUHGKtfcEkpqEQ=; b=J9WK/x12GbGxMSPKV2b/qM+Uhci128Vkb XUceNF53ynEA6laLWd7X6Y1zaAuj0wa7quUpwgmBve/x8nke0EwW9C9tgUv/Mh8A tztTZqG5pU5gBL/DzsNjacmSBWqvJJgbcrbYGrmpoxrjFK8EnN1m88lIbcvhWtqi cCXD8wHL6q0zT3lIRlXCynRgS8XwOdRy8gn1SKWvi22bsxzt7JPGF2jQxoyXVE1R 2aMcjgZqUcZHpGKJh524xW3ODSeoC9BLmhavGM11/6/CXuweqVfhbMRP3wKNV8Wv 0wzzm6pG4ZwEwf/7khe+aHVQuZoxBpZrElp7DkuxszRivTIs4IdiA== Received: from ppma13.dal12v.mail.ibm.com (dd.9e.1632.ip4.static.sl-reverse.com [50.22.158.221]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 42mvp221e8-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 01 Nov 2024 18:58:12 +0000 (GMT) Received: from pps.filterd (ppma13.dal12v.mail.ibm.com [127.0.0.1]) by ppma13.dal12v.mail.ibm.com (8.18.1.2/8.18.1.2) with ESMTP id 4A1HeNvk024554; Fri, 1 Nov 2024 18:58:12 GMT Received: from smtprelay07.dal12v.mail.ibm.com ([172.16.1.9]) by ppma13.dal12v.mail.ibm.com (PPS) with ESMTPS id 42hcyjtsx6-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 01 Nov 2024 18:58:12 +0000 Received: from smtpav05.wdc07v.mail.ibm.com (smtpav05.wdc07v.mail.ibm.com [10.39.53.232]) by smtprelay07.dal12v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 4A1IwBkG41222580 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 1 Nov 2024 18:58:11 GMT Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 69CA758053; Fri, 1 Nov 2024 18:58:11 +0000 (GMT) Received: from smtpav05.wdc07v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 0374D58043; Fri, 1 Nov 2024 18:58:11 +0000 (GMT) Received: from gfwa829.aus.stglabs.ibm.com (unknown [9.3.84.19]) by smtpav05.wdc07v.mail.ibm.com (Postfix) with ESMTP; Fri, 1 Nov 2024 18:58:10 +0000 (GMT) From: dan tan To: qemu-devel@nongnu.org Cc: qemu-ppc@nongnu.org, stefanb@linux.vnet.ibm.com, pbonzini@redhat.com, farosas@suse.de, lvivier@redhat.com, clg@kaod.org Subject: [PATCH v3 5/5] tests/qtest/tpm: add unit test to tis-spi (rev 3) Date: Fri, 1 Nov 2024 13:57:18 -0500 Message-Id: <20241101185718.5847-6-dantan@linux.vnet.ibm.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20241101185718.5847-1-dantan@linux.vnet.ibm.com> References: <20241101185718.5847-1-dantan@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-ORIG-GUID: l8KHWzL8Gff07GQEjc7CBSe0I1Y-hbmF X-Proofpoint-GUID: l8KHWzL8Gff07GQEjc7CBSe0I1Y-hbmF X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1051,Hydra:6.0.680,FMLib:17.12.62.30 definitions=2024-10-15_01,2024-10-11_01,2024-09-30_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 suspectscore=0 impostorscore=0 mlxlogscore=999 spamscore=0 clxscore=1015 malwarescore=0 phishscore=0 priorityscore=1501 lowpriorityscore=0 mlxscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.19.0-2409260000 definitions=main-2411010134 Received-SPF: none client-ip=148.163.158.5; envelope-from=dantan@linux.vnet.ibm.com; helo=mx0b-001b2d01.pphosted.com X-Spam_score_int: -26 X-Spam_score: -2.7 X-Spam_bar: -- X-Spam_report: (-2.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H3=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_NONE=0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-ppc@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-ppc-bounces+incoming=patchwork.ozlabs.org@nongnu.org - removed the function prototypes declaration - fixed code format to comply with convention - changed function names and variable names to be the same as the tpm-tis-i2c test. - change hard coded numbers to #define's with meaningful names that are identifiable with spec documentation Signed-off-by: dan tan --- tests/qtest/tpm-tis-spi-pnv-test.c | 220 +++++++++++++++-------------- tests/qtest/meson.build | 1 + 2 files changed, 116 insertions(+), 105 deletions(-) diff --git a/tests/qtest/tpm-tis-spi-pnv-test.c b/tests/qtest/tpm-tis-spi-pnv-test.c index a367564dda..2d6e1186cf 100644 --- a/tests/qtest/tpm-tis-spi-pnv-test.c +++ b/tests/qtest/tpm-tis-spi-pnv-test.c @@ -19,6 +19,9 @@ #define SPI_TPM_BASE 0xc0080 #define SPI_SHIFT_COUNTER_N1 0x30000000 #define SPI_SHIFT_COUNTER_N2 0x40000000 +#define SPI_RWX_OPCODE_SHIFT 56 +#define SPI_RWX_ADDR_SHIFT 32 +#define SPI_CMD_DATA_SHIFT 56 #define CFG_COUNT_COMPARE_1 0x0000000200000000 #define MM_REG_RDR_MATCH 0x00000000ff01ff00 @@ -26,6 +29,7 @@ #define TPM_TIS_8BITS_MASK 0xff #define SPI_TPM_TIS_ADDR 0xd40000 +#define SPI_EXTEND 0x03 #define TPM_WRITE_OP 0x0 #define TPM_READ_OP 0x80 @@ -50,53 +54,11 @@ static const uint8_t TPM_CMD[12] = #define DPRINTF_STS \ DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts) -static uint64_t pnv_spi_tpm_read(const PnvChip *chip, uint32_t reg); -static void pnv_spi_tpm_write(const PnvChip *chip, uint32_t reg, uint64_t val); -static uint64_t spi_read_reg(const PnvChip *chip); -static void spi_write_reg(const PnvChip *chip, uint64_t val); -static void spi_access_start(const PnvChip *chip, bool n2, uint8_t bytes, - uint8_t tpm_op, uint32_t tpm_reg); - -static inline void tpm_reg_writeb(const PnvChip *c, - int locl, - uint8_t reg, - uint8_t val) -{ - uint32_t tpm_reg_locl = SPI_TPM_TIS_ADDR | (locl << TPM_TIS_LOCALITY_SHIFT); - - spi_access_start(c, false, 1, TPM_WRITE_OP, tpm_reg_locl | reg); - spi_write_reg(c, bswap64(val)); -} - -static inline uint8_t tpm_reg_readb(const PnvChip *c, int locl, uint8_t reg) -{ - uint32_t tpm_reg_locl = SPI_TPM_TIS_ADDR | (locl << TPM_TIS_LOCALITY_SHIFT); - - spi_access_start(c, true, 1, TPM_READ_OP, tpm_reg_locl | reg); - return spi_read_reg(c); -} - -static inline void tpm_reg_writew(const PnvChip *c, - int locl, - uint8_t reg, - uint32_t val) -{ - int i; - - for (i = 0; i < 4; i++) { - tpm_reg_writeb(c, locl, reg + i, ((val >> (8 * i)) & 0xff)); - } -} - -static inline uint32_t tpm_reg_readw(const PnvChip *c, int locl, uint8_t reg) +static uint64_t pnv_spi_tpm_read(const PnvChip *chip, uint32_t reg) { - uint32_t val = 0; - int i; + uint32_t pcba = SPI_TPM_BASE + reg; - for (i = 0; i < 4; i++) { - val |= tpm_reg_readb(c, locl, reg + i) << (8 * i); - } - return val; + return qtest_readq(global_qtest, pnv_xscom_addr(chip, pcba)); } static void pnv_spi_tpm_write(const PnvChip *chip, @@ -104,40 +66,8 @@ static void pnv_spi_tpm_write(const PnvChip *chip, uint64_t val) { uint32_t pcba = SPI_TPM_BASE + reg; - qtest_writeq(global_qtest, pnv_xscom_addr(chip, pcba), val); -} -static uint64_t pnv_spi_tpm_read(const PnvChip *chip, uint32_t reg) -{ - uint32_t pcba = SPI_TPM_BASE + reg; - return qtest_readq(global_qtest, pnv_xscom_addr(chip, pcba)); -} - -static void spi_access_start(const PnvChip *chip, - bool n2, - uint8_t bytes, - uint8_t tpm_op, - uint32_t tpm_reg) -{ - uint64_t cfg_reg; - uint64_t reg_op; - uint64_t seq_op = SEQ_OP_REG_BASIC; - - cfg_reg = pnv_spi_tpm_read(chip, SPI_CLK_CFG_REG); - if (cfg_reg != CFG_COUNT_COMPARE_1) { - pnv_spi_tpm_write(chip, SPI_CLK_CFG_REG, CFG_COUNT_COMPARE_1); - } - /* bytes - sequencer operation register bits 24:31 */ - if (n2) { - seq_op |= SPI_SHIFT_COUNTER_N2 | (bytes << 0x18); - } else { - seq_op |= SPI_SHIFT_COUNTER_N1 | (bytes << 0x18); - } - pnv_spi_tpm_write(chip, SPI_SEQ_OP_REG, seq_op); - pnv_spi_tpm_write(chip, SPI_MM_REG, MM_REG_RDR_MATCH); - pnv_spi_tpm_write(chip, SPI_CTR_CFG_REG, (uint64_t)0); - reg_op = bswap64(tpm_op) | ((uint64_t)tpm_reg << 0x20); - pnv_spi_tpm_write(chip, SPI_XMIT_DATA_REG, reg_op); + qtest_writeq(global_qtest, pnv_xscom_addr(chip, pcba), val); } static void spi_op_complete(const PnvChip *chip) @@ -206,6 +136,89 @@ static uint64_t spi_read_reg(const PnvChip *chip) return val; } +static void spi_access_start(const PnvChip *chip, + bool n2, + uint8_t bytes, + uint8_t tpm_op, + uint32_t tpm_reg) +{ + uint64_t cfg_reg; + uint64_t reg_op; + uint64_t seq_op = SEQ_OP_REG_BASIC; + + cfg_reg = pnv_spi_tpm_read(chip, SPI_CLK_CFG_REG); + if (cfg_reg != CFG_COUNT_COMPARE_1) { + pnv_spi_tpm_write(chip, SPI_CLK_CFG_REG, CFG_COUNT_COMPARE_1); + } + /* bytes - sequencer operation register bits 24:31 */ + if (n2) { + seq_op |= SPI_SHIFT_COUNTER_N2 | (bytes << 0x18); + } else { + seq_op |= SPI_SHIFT_COUNTER_N1 | (bytes << 0x18); + } + pnv_spi_tpm_write(chip, SPI_SEQ_OP_REG, seq_op); + pnv_spi_tpm_write(chip, SPI_MM_REG, MM_REG_RDR_MATCH); + pnv_spi_tpm_write(chip, SPI_CTR_CFG_REG, (uint64_t)0); + reg_op = ((uint64_t)tpm_op << SPI_RWX_OPCODE_SHIFT) | + ((uint64_t)tpm_reg << SPI_RWX_ADDR_SHIFT); + pnv_spi_tpm_write(chip, SPI_XMIT_DATA_REG, reg_op); +} + +static inline void tpm_reg_writeb(const PnvChip *c, + uint8_t locty, + uint8_t reg, + uint8_t val) +{ + uint32_t tpm_reg_locty = SPI_TPM_TIS_ADDR | + (locty << TPM_TIS_LOCALITY_SHIFT); + + spi_access_start(c, false, 1, TPM_WRITE_OP, tpm_reg_locty | reg); + spi_write_reg(c, (uint64_t) val << SPI_CMD_DATA_SHIFT); +} + +static inline uint8_t tpm_reg_readb(const PnvChip *c, + uint8_t locty, + uint8_t reg) +{ + uint32_t tpm_reg_locty = SPI_TPM_TIS_ADDR | + (locty << TPM_TIS_LOCALITY_SHIFT); + + spi_access_start(c, true, 1, TPM_READ_OP, tpm_reg_locty | reg); + return spi_read_reg(c); +} + +static inline void tpm_reg_writel(const PnvChip *c, + uint8_t locty, + uint16_t reg, + uint32_t val) +{ + int i; + + for (i = 0; i < 4; i++) { + tpm_reg_writeb(c, locty, reg + i, ((val >> (8 * i)) & 0xff)); + } +} + +static inline uint32_t tpm_reg_readl(const PnvChip *c, + uint8_t locty, + uint16_t reg) +{ + uint32_t val = 0; + int i; + + /* special case for SPI xmit data reg set RWX bits */ + if (reg == TPM_TIS_REG_DID_VID) { + spi_access_start(c, true, 4, TPM_READ_OP | SPI_EXTEND, + locty | TPM_TIS_REG_DID_VID); + val = bswap32(spi_read_reg(c)); + } else { + for (i = 0; i < 4; i++) { + val |= tpm_reg_readb(c, locty, reg + i) << (8 * i); + } + } + return val; +} + static void tpm_set_verify_loc(const PnvChip *chip, uint8_t loc) { uint8_t access; @@ -226,7 +239,7 @@ static void tpm_set_verify_loc(const PnvChip *chip, uint8_t loc) g_test_message("\tACCESS REG = 0x%x checked", access); /* test tpm status register */ - tpm_sts = tpm_reg_readw(chip, loc, TPM_TIS_REG_STS); + tpm_sts = tpm_reg_readl(chip, loc, TPM_TIS_REG_STS); g_assert_cmpuint((tpm_sts & TPM_TIS_8BITS_MASK), ==, 0); g_test_message("\tTPM STATUS: 0x%x, verified", tpm_sts); @@ -239,6 +252,17 @@ static void tpm_set_verify_loc(const PnvChip *chip, uint8_t loc) g_test_message("\tRELEASED ACCESS: 0x%x, checked", access); } +static void test_spi_tpm_locality(const void *data) +{ + const PnvChip *chip = data; + uint8_t locality; + + /* Locality 4 has special security restrictions, testing 0-3 */ + for (locality = 0; locality < TPM_TIS_NUM_LOCALITIES - 1; locality++) { + tpm_set_verify_loc(chip, locality); + } +} + static void test_spi_tpm_basic(const void *data) { const PnvChip *chip = data; @@ -247,11 +271,8 @@ static void test_spi_tpm_basic(const void *data) g_test_message("TPM TIS SPI interface basic tests:"); /* vendor ID and device ID ... check against the known value*/ - spi_access_start(chip, true, 4, 0x83, - SPI_TPM_TIS_ADDR | TPM_TIS_REG_DID_VID); - didvid = spi_read_reg(chip); - g_assert_cmpint((didvid >> 16), ==, bswap16(TPM_TIS_TPM_VID)); - g_assert_cmpint((didvid & 0xffff), ==, bswap16(TPM_TIS_TPM_DID)); + didvid = tpm_reg_readl(chip, 0, TPM_TIS_REG_DID_VID); + g_assert_cmpint(didvid, ==, (1 << 16) | PCI_VENDOR_ID_IBM); g_test_message("\tDID_VID = 0x%x, verified", didvid); /* access register, default see TCG TIS Spec (v1.3) table-14 */ @@ -261,28 +282,17 @@ static void test_spi_tpm_basic(const void *data) g_test_message("\tACCESS REG = 0x%x, checked", access); /* interrupt enable register, default see TCG TIS Spec (v1.3) table-19 */ - en_int = tpm_reg_readw(chip, 0, TPM_TIS_REG_INT_ENABLE); + en_int = tpm_reg_readl(chip, 0, TPM_TIS_REG_INT_ENABLE); g_assert_cmpuint(en_int, ==, TPM_TIS_INT_POLARITY_LOW_LEVEL); g_test_message("\tINT ENABLE REG: 0x%x, verified", en_int); /* status register, default see TCG TIS Spec (v1.3) table-15 */ - tpm_sts = tpm_reg_readw(chip, 0, TPM_TIS_REG_STS); + tpm_sts = tpm_reg_readl(chip, 0, TPM_TIS_REG_STS); /* for no active locality */ g_assert_cmpuint(tpm_sts, ==, 0xffffffff); g_test_message("\tTPM STATUS: 0x%x, verified", tpm_sts); } -static void test_spi_tpm_locality(const void *data) -{ - const PnvChip *chip = data; - uint8_t locality; - - /* Locality 4 has special security restrictions, testing 0-3 */ - for (locality = 0; locality < TPM_TIS_NUM_LOCALITIES - 1; locality++) { - tpm_set_verify_loc(chip, locality); - } -} - /* * Test case for seizing access by a higher number locality */ @@ -582,7 +592,7 @@ static void test_spi_tpm_transmit_test(const void *data) TPM_TIS_ACCESS_ACTIVE_LOCALITY | TPM_TIS_ACCESS_TPM_ESTABLISHMENT); - sts = tpm_reg_readw(chip, 0, TPM_TIS_REG_STS); + sts = tpm_reg_readl(chip, 0, TPM_TIS_REG_STS); DPRINTF_STS; g_assert_cmpint(sts & 0xff, ==, 0); @@ -591,15 +601,15 @@ static void test_spi_tpm_transmit_test(const void *data) g_test_message("\t\tbcount: %x, sts: %x", bcount, sts); g_assert_cmpint(bcount, >=, 128); - tpm_reg_writew(chip, 0, TPM_TIS_REG_STS, TPM_TIS_STS_COMMAND_READY); - sts = tpm_reg_readw(chip, 0, TPM_TIS_REG_STS); + tpm_reg_writel(chip, 0, TPM_TIS_REG_STS, TPM_TIS_STS_COMMAND_READY); + sts = tpm_reg_readl(chip, 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++) { tpm_reg_writeb(chip, 0, TPM_TIS_REG_DATA_FIFO, TPM_CMD[i]); - sts = tpm_reg_readw(chip, 0, TPM_TIS_REG_STS); + sts = tpm_reg_readl(chip, 0, TPM_TIS_REG_STS); DPRINTF_STS; if (i < sizeof(TPM_CMD) - 1) { g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_EXPECT | @@ -611,17 +621,17 @@ static void test_spi_tpm_transmit_test(const void *data) g_test_message("\ttransmit tests, check TPM_TIS_STS_EXPECT"); /* start processing */ - tpm_reg_writew(chip, 0, TPM_TIS_REG_STS, TPM_TIS_STS_TPM_GO); + tpm_reg_writel(chip, 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 = tpm_reg_readw(chip, 0, TPM_TIS_REG_STS); + sts = tpm_reg_readl(chip, 0, TPM_TIS_REG_STS); if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) { break; } } while (g_get_monotonic_time() < end_time); - sts = tpm_reg_readw(chip, 0, TPM_TIS_REG_STS); + sts = tpm_reg_readl(chip, 0, TPM_TIS_REG_STS); DPRINTF_STS; g_assert_cmpint(sts & 0xff, == , TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); @@ -635,7 +645,7 @@ static void test_spi_tpm_transmit_test(const void *data) for (i = 0; i < sizeof(tpm_msg); i++) { tpm_msg[i] = tpm_reg_readb(chip, 0, TPM_TIS_REG_DATA_FIFO); - sts = tpm_reg_readw(chip, 0, TPM_TIS_REG_STS); + sts = tpm_reg_readl(chip, 0, TPM_TIS_REG_STS); DPRINTF_STS; if (sts & TPM_TIS_STS_DATA_AVAILABLE) { g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index 6b1aed929e..74aa9f57e0 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -4,6 +4,7 @@ slow_qtests = { 'bios-tables-test' : 910, 'cdrom-test' : 610, 'device-introspect-test' : 720, + 'ide-test' : 120, 'migration-test' : 480, 'npcm7xx_pwm-test': 300, 'npcm7xx_watchdog_timer-test': 120,