All of lore.kernel.org
 help / color / mirror / Atom feed
From: Iris Chen <irischenlj@gmail.com>
Cc: irischenlj@fb.com, peter@pjd.dev, pdel@fb.com,
	qemu-devel@nongnu.org, qemu-arm@nongnu.org, clg@kaod.org,
	patrick@stwcx.xyz, alistair@alistair23.me, kwolf@redhat.com,
	hreitz@redhat.com, peter.maydell@linaro.org, andrew@aj.id.au,
	joel@jms.id.au, thuth@redhat.com, lvivier@redhat.com,
	pbonzini@redhat.com, qemu-block@nongnu.org, dz4list@gmail.com
Subject: [RFC 1/1] hw: tpmtisspi: add SPI support to QEMU TPM implementation
Date: Tue,  2 Aug 2022 19:32:41 -0700	[thread overview]
Message-ID: <20220803023241.63739-2-irischenlj@gmail.com> (raw)
In-Reply-To: <20220803023241.63739-1-irischenlj@gmail.com>

From: Iris Chen <irischenlj@fb.com>

Signed-off-by: Iris Chen <irischenlj@fb.com>
---
 configs/devices/arm-softmmu/default.mak |   1 +
 hw/arm/Kconfig                          |   5 +
 hw/tpm/Kconfig                          |   5 +
 hw/tpm/meson.build                      |   1 +
 hw/tpm/tpm_tis_spi.c                    | 311 ++++++++++++++++++++++++
 include/sysemu/tpm.h                    |   3 +
 6 files changed, 326 insertions(+)
 create mode 100644 hw/tpm/tpm_tis_spi.c

diff --git a/configs/devices/arm-softmmu/default.mak b/configs/devices/arm-softmmu/default.mak
index 6985a25377..80d2841568 100644
--- a/configs/devices/arm-softmmu/default.mak
+++ b/configs/devices/arm-softmmu/default.mak
@@ -42,3 +42,4 @@ CONFIG_FSL_IMX6UL=y
 CONFIG_SEMIHOSTING=y
 CONFIG_ARM_COMPATIBLE_SEMIHOSTING=y
 CONFIG_ALLWINNER_H3=y
+CONFIG_FBOBMC_AST=y
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 15fa79afd3..193decaec1 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -458,6 +458,11 @@ config ASPEED_SOC
     select PMBUS
     select MAX31785
 
+config FBOBMC_AST
+    bool
+    select ASPEED_SOC
+    select TPM_TIS_SPI
+
 config MPS2
     bool
     imply I2C_DEVICES
diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig
index 29e82f3c92..370a43f045 100644
--- a/hw/tpm/Kconfig
+++ b/hw/tpm/Kconfig
@@ -8,6 +8,11 @@ config TPM_TIS_SYSBUS
     depends on TPM
     select TPM_TIS
 
+config TPM_TIS_SPI
+    bool
+    depends on TPM
+    select TPM_TIS
+
 config TPM_TIS
     bool
     depends on TPM
diff --git a/hw/tpm/meson.build b/hw/tpm/meson.build
index 1c68d81d6a..1a057f4e36 100644
--- a/hw/tpm/meson.build
+++ b/hw/tpm/meson.build
@@ -2,6 +2,7 @@ softmmu_ss.add(when: 'CONFIG_TPM_TIS', if_true: files('tpm_tis_common.c'))
 softmmu_ss.add(when: 'CONFIG_TPM_TIS_ISA', if_true: files('tpm_tis_isa.c'))
 softmmu_ss.add(when: 'CONFIG_TPM_TIS_SYSBUS', if_true: files('tpm_tis_sysbus.c'))
 softmmu_ss.add(when: 'CONFIG_TPM_CRB', if_true: files('tpm_crb.c'))
+softmmu_ss.add(when: 'CONFIG_TPM_TIS_SPI', if_true: files('tpm_tis_spi.c'))
 
 specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TPM_TIS'], if_true: files('tpm_ppi.c'))
 specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TPM_CRB'], if_true: files('tpm_ppi.c'))
diff --git a/hw/tpm/tpm_tis_spi.c b/hw/tpm/tpm_tis_spi.c
new file mode 100644
index 0000000000..c98ddcfddb
--- /dev/null
+++ b/hw/tpm/tpm_tis_spi.c
@@ -0,0 +1,311 @@
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "migration/vmstate.h"
+#include "hw/acpi/tpm.h"
+#include "tpm_prop.h"
+#include "tpm_tis.h"
+#include "qom/object.h"
+#include "hw/ssi/ssi.h"
+#include "hw/ssi/spi_gpio.h"
+
+#define TPM_TIS_SPI_ADDR_BYTES 3
+#define SPI_WRITE 0
+
+typedef enum {
+    TIS_SPI_PKT_STATE_DEACTIVATED = 0,
+    TIS_SPI_PKT_STATE_START,
+    TIS_SPI_PKT_STATE_ADDRESS,
+    TIS_SPI_PKT_STATE_DATA_WR,
+    TIS_SPI_PKT_STATE_DATA_RD,
+    TIS_SPI_PKT_STATE_DONE,
+} TpmTisSpiPktState;
+
+union TpmTisRWSizeByte {
+    uint8_t byte;
+    struct {
+        uint8_t data_expected_size:6;
+        uint8_t resv:1;
+        uint8_t rwflag:1;
+    };
+};
+
+union TpmTisSpiHwAddr {
+    hwaddr addr;
+    uint8_t bytes[sizeof(hwaddr)];
+};
+
+union TpmTisSpiData {
+    uint32_t data;
+    uint8_t bytes[64];
+};
+
+struct TpmTisSpiState {
+    /*< private >*/
+    SSIPeripheral parent_obj;
+
+    /*< public >*/
+    TPMState tpm_state; /* not a QOM object */
+    TpmTisSpiPktState tpm_tis_spi_state;
+
+    union TpmTisRWSizeByte first_byte;
+    union TpmTisSpiHwAddr addr;
+    union TpmTisSpiData data;
+
+    uint32_t data_size;
+    uint8_t data_idx;
+    uint8_t addr_idx;
+};
+
+struct TpmTisSpiClass {
+    SSIPeripheralClass parent_class;
+};
+
+OBJECT_DECLARE_TYPE(TpmTisSpiState, TpmTisSpiClass, TPM_TIS_SPI)
+
+static void tpm_tis_spi_mmio_read(TpmTisSpiState *tts)
+{
+    uint16_t offset = tts->addr.addr & 0xffc;
+
+    switch (offset) {
+    case TPM_TIS_REG_DATA_FIFO:
+        for (uint8_t i = 0; i < tts->data_size; i++) {
+            tts->data.bytes[i] = (uint8_t)tpm_tis_memory_ops.read(
+                                          &tts->tpm_state,
+                                          tts->addr.addr,
+                                          1);
+        }
+        break;
+    default:
+        tts->data.data = (uint32_t)tpm_tis_memory_ops.read(
+                                   &tts->tpm_state,
+                                   tts->addr.addr,
+                                   tts->data_size);
+    }
+}
+
+static void tpm_tis_spi_mmio_write(TpmTisSpiState *tts)
+{
+    uint16_t offset = tts->addr.addr & 0xffc;
+
+    switch (offset) {
+    case TPM_TIS_REG_DATA_FIFO:
+        for (uint8_t i = 0; i < tts->data_size; i++) {
+            tpm_tis_memory_ops.write(&tts->tpm_state,
+                                     tts->addr.addr,
+                                     tts->data.bytes[i],
+                                     1);
+        }
+        break;
+    default:
+        tpm_tis_memory_ops.write(&tts->tpm_state,
+                                 tts->addr.addr,
+                                 tts->data.data,
+                                 tts->data_size);
+        }
+}
+
+static uint32_t tpm_tis_spi_transfer8(SSIPeripheral *ss, uint32_t tx)
+{
+    TpmTisSpiState *tts = TPM_TIS_SPI(ss);
+    uint32_t r = 1;
+
+    switch (tts->tpm_tis_spi_state) {
+    case TIS_SPI_PKT_STATE_START:
+        tts->first_byte.byte = (uint8_t)tx;
+        tts->data_size = tts->first_byte.data_expected_size + 1;
+        tts->data_idx = 0;
+        tts->addr_idx = TPM_TIS_SPI_ADDR_BYTES;
+        tts->tpm_tis_spi_state = TIS_SPI_PKT_STATE_ADDRESS;
+        break;
+    case TIS_SPI_PKT_STATE_ADDRESS:
+        assert(tts->addr_idx > 0);
+        tts->addr.bytes[--tts->addr_idx] = (uint8_t)tx;
+
+        if (tts->addr_idx == 0) {
+            if (tts->first_byte.rwflag == SPI_WRITE) {
+                tts->tpm_tis_spi_state = TIS_SPI_PKT_STATE_DATA_WR;
+            } else { /* read and get the data ready */
+                tpm_tis_spi_mmio_read(tts);
+                tts->tpm_tis_spi_state = TIS_SPI_PKT_STATE_DATA_RD;
+            }
+        }
+        break;
+    case TIS_SPI_PKT_STATE_DATA_WR:
+        tts->data.bytes[tts->data_idx++] = (uint8_t)tx;
+        if (tts->data_idx == tts->data_size) {
+            tpm_tis_spi_mmio_write(tts);
+            tts->tpm_tis_spi_state = TIS_SPI_PKT_STATE_DONE;
+        }
+        break;
+    case TIS_SPI_PKT_STATE_DATA_RD:
+        r = tts->data.bytes[tts->data_idx++];
+        if (tts->data_idx == tts->data_size) {
+            tts->tpm_tis_spi_state = TIS_SPI_PKT_STATE_DONE;
+        }
+        break;
+    default:
+        tts->tpm_tis_spi_state = TIS_SPI_PKT_STATE_DEACTIVATED;
+        r = (uint32_t) -1;
+    }
+
+    return r;
+}
+
+/*
+ * Pre-reading logic for transfer:
+ * This is to fix the transaction between reading and writing.
+ * The first byte is arbitrarily inserted so we need to
+ * shift the all the output bytes (timeline) one byte right.
+ */
+static uint32_t tpm_tis_spi_transfer8_ex(SSIPeripheral *ss, uint32_t tx)
+{
+    TpmTisSpiState *tts = TPM_TIS_SPI(ss);
+    SSIBus *ssibus = (SSIBus *)qdev_get_parent_bus(DEVICE(tts));
+
+    TpmTisSpiPktState prev_state = tts->tpm_tis_spi_state;
+    uint32_t r = tpm_tis_spi_transfer8(ss, tx);
+    TpmTisSpiPktState curr_state = tts->tpm_tis_spi_state;
+
+    if (ssibus->preread &&
+       /* cmd state has changed into DATA reading state */
+       prev_state != TIS_SPI_PKT_STATE_DATA_RD &&
+       curr_state == TIS_SPI_PKT_STATE_DATA_RD) {
+        r = tpm_tis_spi_transfer8(ss, 0xFF);
+    }
+
+    return r;
+}
+
+static int tpm_tis_spi_cs(SSIPeripheral *ss, bool select)
+{
+    TpmTisSpiState *tts = TPM_TIS_SPI(ss);
+
+    if (select) { /* cs de-assert */
+        tts->tpm_tis_spi_state = TIS_SPI_PKT_STATE_DEACTIVATED;
+    } else {
+        tts->tpm_tis_spi_state = TIS_SPI_PKT_STATE_START;
+        tts->first_byte.byte = 0;
+        tts->addr.addr = 0;
+        tts->data.data = 0;
+    }
+
+    return 0;
+}
+
+static int tpm_tis_pre_save_spi(void *opaque)
+{
+    TpmTisSpiState *sbdev = opaque;
+
+    return tpm_tis_pre_save(&sbdev->tpm_state);
+}
+
+static const VMStateDescription vmstate_tpm_tis_spi = {
+    .name = "tpm-tis-spi",
+    .version_id = 0,
+    .pre_save  = tpm_tis_pre_save_spi,
+    .fields = (VMStateField[]) {
+        VMSTATE_BUFFER(tpm_state.buffer, TpmTisSpiState),
+        VMSTATE_UINT16(tpm_state.rw_offset, TpmTisSpiState),
+        VMSTATE_UINT8(tpm_state.active_locty, TpmTisSpiState),
+        VMSTATE_UINT8(tpm_state.aborting_locty, TpmTisSpiState),
+        VMSTATE_UINT8(tpm_state.next_locty, TpmTisSpiState),
+
+        VMSTATE_STRUCT_ARRAY(tpm_state.loc, TpmTisSpiState, TPM_TIS_NUM_LOCALITIES,
+                             0, vmstate_locty, TPMLocality),
+
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void tpm_tis_spi_request_completed(TPMIf *ti, int ret)
+{
+    TpmTisSpiState *sbdev = TPM_TIS_SPI(ti);
+    TPMState *s = &sbdev->tpm_state;
+
+    tpm_tis_request_completed(s, ret);
+}
+
+static enum TPMVersion tpm_tis_spi_get_tpm_version(TPMIf *ti)
+{
+    TpmTisSpiState *sbdev = TPM_TIS_SPI(ti);
+    TPMState *s = &sbdev->tpm_state;
+
+    return tpm_tis_get_tpm_version(s);
+}
+
+static void tpm_tis_spi_reset(DeviceState *dev)
+{
+    TpmTisSpiState *sbdev = TPM_TIS_SPI(dev);
+    TPMState *s = &sbdev->tpm_state;
+
+    return tpm_tis_reset(s);
+}
+
+static Property tpm_tis_spi_properties[] = {
+    DEFINE_PROP_UINT32("irq", TpmTisSpiState, tpm_state.irq_num, TPM_TIS_IRQ),
+    DEFINE_PROP_TPMBE("tpmdev", TpmTisSpiState, tpm_state.be_driver),
+    DEFINE_PROP_BOOL("ppi", TpmTisSpiState, tpm_state.ppi_enabled, false),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void tpm_tis_spi_realizefn(SSIPeripheral *ss, Error **errp)
+{
+    TpmTisSpiState *sbdev = TPM_TIS_SPI(ss);
+
+    if (!tpm_find()) {
+        error_setg(errp, "at most one TPM device is permitted");
+        return;
+    }
+
+    if (!sbdev->tpm_state.be_driver) {
+        error_setg(errp, "'tpmdev' property is required");
+        return;
+    }
+
+    DeviceState *spi_gpio = qdev_find_recursive(sysbus_get_default(),
+                                                TYPE_SPI_GPIO);
+    qdev_connect_gpio_out_named(spi_gpio,
+                                "SPI_CS_out", 0,
+                                qdev_get_gpio_in_named(DEVICE(ss),
+                                SSI_GPIO_CS, 0));
+}
+
+static void tpm_tis_spi_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SSIPeripheralClass *k = SSI_PERIPHERAL_CLASS(klass);
+    TPMIfClass *tc = TPM_IF_CLASS(klass);
+
+    device_class_set_props(dc, tpm_tis_spi_properties);
+    k->realize = tpm_tis_spi_realizefn;
+    k->transfer = tpm_tis_spi_transfer8_ex;
+    k->set_cs = tpm_tis_spi_cs;
+    k->cs_polarity = SSI_CS_LOW;
+
+    dc->vmsd  = &vmstate_tpm_tis_spi;
+    tc->model = TPM_MODEL_TPM_TIS;
+    dc->user_creatable = true;
+    dc->reset = tpm_tis_spi_reset;
+    tc->request_completed = tpm_tis_spi_request_completed;
+    tc->get_version = tpm_tis_spi_get_tpm_version;
+    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
+}
+
+static const TypeInfo tpm_tis_spi_info = {
+    .name = TYPE_TPM_TIS_SPI,
+    .parent = TYPE_SSI_PERIPHERAL,
+    .instance_size = sizeof(TpmTisSpiState),
+    .class_size = sizeof(TpmTisSpiClass),
+    .class_init  = tpm_tis_spi_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { TYPE_TPM_IF },
+        { }
+    }
+};
+
+static void tpm_tis_spi_register(void)
+{
+    type_register_static(&tpm_tis_spi_info);
+}
+
+type_init(tpm_tis_spi_register)
diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h
index fb40e30ff6..6a6b311e47 100644
--- a/include/sysemu/tpm.h
+++ b/include/sysemu/tpm.h
@@ -46,6 +46,7 @@ struct TPMIfClass {
 
 #define TYPE_TPM_TIS_ISA            "tpm-tis"
 #define TYPE_TPM_TIS_SYSBUS         "tpm-tis-device"
+#define TYPE_TPM_TIS_SPI            "tpm-tis-spi-device"
 #define TYPE_TPM_CRB                "tpm-crb"
 #define TYPE_TPM_SPAPR              "tpm-spapr"
 
@@ -53,6 +54,8 @@ struct TPMIfClass {
     object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS_ISA)
 #define TPM_IS_TIS_SYSBUS(chr)                      \
     object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS_SYSBUS)
+#define TPM_IS_TIS_SPI(chr)                      \
+    object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS_SPI)
 #define TPM_IS_CRB(chr)                             \
     object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB)
 #define TPM_IS_SPAPR(chr)                           \
-- 
2.30.2



  reply	other threads:[~2022-08-03  7:21 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-03  2:32 [RFC 0/1] SPI support in QEMU TPM Iris Chen
2022-08-03  2:32 ` Iris Chen [this message]
2022-08-03  8:52   ` [RFC 1/1] hw: tpmtisspi: add SPI support to QEMU TPM implementation Cédric Le Goater
2022-08-03 17:30     ` Peter Delevoryas
2022-08-04 18:07       ` Dan Zhang
2022-08-04 23:21         ` Peter Delevoryas
2022-08-05  5:05           ` Dan Zhang
2022-08-10 13:57     ` Stefan Berger
2022-08-10 14:38     ` Stefan Berger
2023-12-13 14:39   ` Guenter Roeck
2023-12-15  2:43     ` Iris Chen
2022-08-03  8:32 ` [RFC 0/1] SPI support in QEMU TPM Cédric Le Goater

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220803023241.63739-2-irischenlj@gmail.com \
    --to=irischenlj@gmail.com \
    --cc=alistair@alistair23.me \
    --cc=andrew@aj.id.au \
    --cc=clg@kaod.org \
    --cc=dz4list@gmail.com \
    --cc=hreitz@redhat.com \
    --cc=irischenlj@fb.com \
    --cc=joel@jms.id.au \
    --cc=kwolf@redhat.com \
    --cc=lvivier@redhat.com \
    --cc=patrick@stwcx.xyz \
    --cc=pbonzini@redhat.com \
    --cc=pdel@fb.com \
    --cc=peter.maydell@linaro.org \
    --cc=peter@pjd.dev \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=thuth@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.