All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 0/4] Add support for TPM Physical Presence interface
@ 2018-05-15 12:14 Marc-André Lureau
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 1/4] tpm: implement virtual memory device for TPM PPI Marc-André Lureau
                   ` (4 more replies)
  0 siblings, 5 replies; 40+ messages in thread
From: Marc-André Lureau @ 2018-05-15 12:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: Paolo Bonzini, stefanb, Marcel Apfelbaum, Eduardo Habkost,
	Igor Mammedov, Michael S. Tsirkin, Richard Henderson,
	Marc-André Lureau

Hi,

The following patches implement the TPM Physical Presence Interface
that allows a user to set a command via ACPI (sysfs entry in Linux)
that, upon the next reboot, the firmware looks for and acts upon by
sending sequences of commands to the TPM.

A dedicated memory region is added to the TPM CRB & TIS devices, at
address/size 0xFED45000/0x400. A new "etc/tpm/config" fw_cfg entry
holds the location for that PPI region and some version details, to
allow for future flexibility.

With the associated edk2/ovmf firmware, the Windows HLK "PPI 1.3" test
now runs successfully.

It is based on previous work from Stefan Berger ("[PATCH v2 0/4]
Implement Physical Presence interface for TPM 1.2 and 2")

Git branches:
https://github.com/elmarco/qemu tpm-ppi
https://github.com/elmarco/edk2 tpm-ppi

Marc-André Lureau (1):
  tpm: add a fake ACPI memory clear interface

Stefan Berger (3):
  tpm: implement virtual memory device for TPM PPI
  acpi: add fw_cfg file for TPM and PPI virtual memory device
  acpi: build TPM Physical Presence interface

 hw/tpm/tpm_ppi.h      |  26 ++++
 include/hw/acpi/tpm.h |  30 ++++
 hw/i386/acpi-build.c  | 318 ++++++++++++++++++++++++++++++++++++++++++
 hw/tpm/tpm_crb.c      |   5 +
 hw/tpm/tpm_ppi.c      |  56 ++++++++
 hw/tpm/tpm_tis.c      |   5 +
 docs/specs/tpm.txt    |  20 +++
 hw/tpm/Makefile.objs  |   2 +-
 hw/tpm/trace-events   |   4 +
 9 files changed, 465 insertions(+), 1 deletion(-)
 create mode 100644 hw/tpm/tpm_ppi.h
 create mode 100644 hw/tpm/tpm_ppi.c

-- 
2.17.0.253.g3dd125b46d

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 1/4] tpm: implement virtual memory device for TPM PPI
  2018-05-15 12:14 [Qemu-devel] [PATCH v3 0/4] Add support for TPM Physical Presence interface Marc-André Lureau
@ 2018-05-15 12:14 ` Marc-André Lureau
  2018-05-15 14:19   ` Stefan Berger
  2018-06-21  9:49   ` Igor Mammedov
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 2/4] acpi: add fw_cfg file for TPM and PPI virtual memory device Marc-André Lureau
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 40+ messages in thread
From: Marc-André Lureau @ 2018-05-15 12:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: Paolo Bonzini, stefanb, Marcel Apfelbaum, Eduardo Habkost,
	Igor Mammedov, Michael S. Tsirkin, Richard Henderson,
	Marc-André Lureau

From: Stefan Berger <stefanb@linux.vnet.ibm.com>

Implement a virtual memory device for the TPM Physical Presence interface.
The memory is located at 0xfffef000 and used by ACPI to send messages to the
firmware (BIOS) and by the firmware to provide parameters for each one of
the supported codes.

This device should be used by all TPM interfaces on x86 and can be added
by calling tpm_ppi_init_io().

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>

---

v3 (Marc-André):
 - merge CRB support
 - use trace events instead of DEBUG printf
 - headers inclusion simplification

v2:
 - moved to byte access since an infrequently used device;
   this simplifies code
 - increase size of device to 0x400
 - move device to 0xfffef000 since SeaBIOS has some code at 0xffff0000:
   'On the emulators, the bios at 0xf0000 is also at 0xffff0000'
---
 hw/tpm/tpm_ppi.h      | 26 ++++++++++++++++++++
 include/hw/acpi/tpm.h |  6 +++++
 hw/tpm/tpm_crb.c      |  5 ++++
 hw/tpm/tpm_ppi.c      | 56 +++++++++++++++++++++++++++++++++++++++++++
 hw/tpm/tpm_tis.c      |  5 ++++
 hw/tpm/Makefile.objs  |  2 +-
 hw/tpm/trace-events   |  4 ++++
 7 files changed, 103 insertions(+), 1 deletion(-)
 create mode 100644 hw/tpm/tpm_ppi.h
 create mode 100644 hw/tpm/tpm_ppi.c

diff --git a/hw/tpm/tpm_ppi.h b/hw/tpm/tpm_ppi.h
new file mode 100644
index 0000000000..17030bd989
--- /dev/null
+++ b/hw/tpm/tpm_ppi.h
@@ -0,0 +1,26 @@
+/*
+ * TPM Physical Presence Interface
+ *
+ * Copyright (C) 2018 IBM Corporation
+ *
+ * Authors:
+ *  Stefan Berger    <stefanb@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef TPM_TPM_PPI_H
+#define TPM_TPM_PPI_H
+
+#include "hw/acpi/tpm.h"
+#include "exec/address-spaces.h"
+
+typedef struct TPMPPI {
+    MemoryRegion mmio;
+
+    uint8_t ram[TPM_PPI_ADDR_SIZE];
+} TPMPPI;
+
+void tpm_ppi_init_io(TPMPPI *tpmppi, struct MemoryRegion *m, Object *obj);
+
+#endif /* TPM_TPM_PPI_H */
diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
index 46ac4dc581..c082df7d1d 100644
--- a/include/hw/acpi/tpm.h
+++ b/include/hw/acpi/tpm.h
@@ -187,4 +187,10 @@ REG32(CRB_DATA_BUFFER, 0x80)
 #define TPM2_START_METHOD_MMIO      6
 #define TPM2_START_METHOD_CRB       7
 
+/*
+ * Physical Presence Interface
+ */
+#define TPM_PPI_ADDR_SIZE           0x400
+#define TPM_PPI_ADDR_BASE           0xFED45000
+
 #endif /* HW_ACPI_TPM_H */
diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
index a92dd50437..4f585564d9 100644
--- a/hw/tpm/tpm_crb.c
+++ b/hw/tpm/tpm_crb.c
@@ -29,6 +29,7 @@
 #include "sysemu/reset.h"
 #include "tpm_int.h"
 #include "tpm_util.h"
+#include "tpm_ppi.h"
 #include "trace.h"
 
 typedef struct CRBState {
@@ -41,6 +42,8 @@ typedef struct CRBState {
     MemoryRegion cmdmem;
 
     size_t be_buffer_size;
+
+    TPMPPI ppi;
 } CRBState;
 
 #define CRB(obj) OBJECT_CHECK(CRBState, (obj), TYPE_TPM_CRB)
@@ -291,6 +294,8 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp)
     memory_region_add_subregion(get_system_memory(),
         TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem);
 
+    tpm_ppi_init_io(&s->ppi, get_system_memory(), OBJECT(s));
+
     qemu_register_reset(tpm_crb_reset, dev);
 }
 
diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c
new file mode 100644
index 0000000000..0019c3e6fc
--- /dev/null
+++ b/hw/tpm/tpm_ppi.c
@@ -0,0 +1,56 @@
+/*
+ * tpm_ppi.c - TPM Physical Presence Interface
+ *
+ * Copyright (C) 2018 IBM Corporation
+ *
+ * Authors:
+ *  Stefan Berger <stefanb@us.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "tpm_ppi.h"
+#include "trace.h"
+
+static uint64_t tpm_ppi_mmio_read(void *opaque, hwaddr addr,
+                                  unsigned size)
+{
+    TPMPPI *s = opaque;
+
+    trace_tpm_ppi_mmio_read(addr, size, s->ram[addr]);
+
+    return s->ram[addr];
+}
+
+static void tpm_ppi_mmio_write(void *opaque, hwaddr addr,
+                               uint64_t val, unsigned size)
+{
+    TPMPPI *s = opaque;
+
+    trace_tpm_ppi_mmio_write(addr, size, val);
+
+    s->ram[addr] = val;
+}
+
+static const MemoryRegionOps tpm_ppi_memory_ops = {
+    .read = tpm_ppi_mmio_read,
+    .write = tpm_ppi_mmio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+void tpm_ppi_init_io(TPMPPI *tpmppi, struct MemoryRegion *m, Object *obj)
+{
+    memory_region_init_io(&tpmppi->mmio, obj, &tpm_ppi_memory_ops,
+                          tpmppi, "tpm-ppi-mmio",
+                          TPM_PPI_ADDR_SIZE);
+
+    memory_region_add_subregion(m, TPM_PPI_ADDR_BASE, &tpmppi->mmio);
+}
diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
index 12f5c9a759..9a2fec455a 100644
--- a/hw/tpm/tpm_tis.c
+++ b/hw/tpm/tpm_tis.c
@@ -31,6 +31,7 @@
 #include "sysemu/tpm_backend.h"
 #include "tpm_int.h"
 #include "tpm_util.h"
+#include "tpm_ppi.h"
 #include "trace.h"
 
 #define TPM_TIS_NUM_LOCALITIES      5     /* per spec */
@@ -81,6 +82,8 @@ typedef struct TPMState {
     TPMVersion be_tpm_version;
 
     size_t be_buffer_size;
+
+    TPMPPI ppi;
 } TPMState;
 
 #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
@@ -976,6 +979,8 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
 
     memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
                                 TPM_TIS_ADDR_BASE, &s->mmio);
+
+    tpm_ppi_init_io(&s->ppi, isa_address_space(ISA_DEVICE(dev)), OBJECT(s));
 }
 
 static void tpm_tis_initfn(Object *obj)
diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index 1dc9f8bf2c..eedd8b6858 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,4 +1,4 @@
-common-obj-y += tpm_util.o
+common-obj-y += tpm_util.o tpm_ppi.o
 common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
 common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o
 common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events
index 25bee0cecf..81f9923401 100644
--- a/hw/tpm/trace-events
+++ b/hw/tpm/trace-events
@@ -8,6 +8,10 @@ tpm_crb_mmio_write(uint64_t addr, unsigned size, uint32_t val) "CRB write 0x" TA
 tpm_passthrough_handle_request(void *cmd) "processing command %p"
 tpm_passthrough_reset(void) "reset"
 
+# hw/tpm/tpm_ppi.c
+tpm_ppi_mmio_read(uint64_t addr, unsigned size, uint32_t val) "PPI read 0x" TARGET_FMT_plx " len:%u val: 0x%" PRIx32
+tpm_ppi_mmio_write(uint64_t addr, unsigned size, uint32_t val) "PPI write 0x" TARGET_FMT_plx " len:%u val: 0x%" PRIx32
+
 # hw/tpm/tpm_util.c
 tpm_util_get_buffer_size_hdr_len(uint32_t len, size_t expected) "tpm_resp->hdr.len = %u, expected = %zu"
 tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, expected = %zu"
-- 
2.17.0.253.g3dd125b46d

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 2/4] acpi: add fw_cfg file for TPM and PPI virtual memory device
  2018-05-15 12:14 [Qemu-devel] [PATCH v3 0/4] Add support for TPM Physical Presence interface Marc-André Lureau
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 1/4] tpm: implement virtual memory device for TPM PPI Marc-André Lureau
@ 2018-05-15 12:14 ` Marc-André Lureau
  2018-06-21 10:00   ` Igor Mammedov
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface Marc-André Lureau
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 40+ messages in thread
From: Marc-André Lureau @ 2018-05-15 12:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: Paolo Bonzini, stefanb, Marcel Apfelbaum, Eduardo Habkost,
	Igor Mammedov, Michael S. Tsirkin, Richard Henderson,
	Marc-André Lureau

From: Stefan Berger <stefanb@linux.vnet.ibm.com>

To avoid having to hard code the base address of the PPI virtual
memory device we introduce a fw_cfg file etc/tpm/config that holds the
base address of the PPI device, the version of the PPI interface and
the version of the attached TPM.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
[ Marc-André: renamed to etc/tpm/config, made it static, document it ]
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 include/hw/acpi/tpm.h |  3 +++
 hw/i386/acpi-build.c  | 17 +++++++++++++++++
 docs/specs/tpm.txt    | 20 ++++++++++++++++++++
 3 files changed, 40 insertions(+)

diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
index c082df7d1d..f79d68a77a 100644
--- a/include/hw/acpi/tpm.h
+++ b/include/hw/acpi/tpm.h
@@ -193,4 +193,7 @@ REG32(CRB_DATA_BUFFER, 0x80)
 #define TPM_PPI_ADDR_SIZE           0x400
 #define TPM_PPI_ADDR_BASE           0xFED45000
 
+#define TPM_PPI_VERSION_NONE        0
+#define TPM_PPI_VERSION_1_30        1
+
 #endif /* HW_ACPI_TPM_H */
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 9bc6d97ea1..f6d447f03a 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -119,6 +119,12 @@ typedef struct AcpiBuildPciBusHotplugState {
     bool pcihp_bridge_en;
 } AcpiBuildPciBusHotplugState;
 
+typedef struct FWCfgTPMConfig {
+    uint32_t tpmppi_address;
+    uint8_t tpm_version;
+    uint8_t tpmppi_version;
+} QEMU_PACKED FWCfgTPMConfig;
+
 static void init_common_fadt_data(Object *o, AcpiFadtData *data)
 {
     uint32_t io = object_property_get_uint(o, ACPI_PM_PROP_PM_IO_BASE, NULL);
@@ -2873,6 +2879,7 @@ void acpi_setup(void)
     AcpiBuildTables tables;
     AcpiBuildState *build_state;
     Object *vmgenid_dev;
+    static FWCfgTPMConfig tpm_config;
 
     if (!pcms->fw_cfg) {
         ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
@@ -2907,6 +2914,16 @@ void acpi_setup(void)
     fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
                     tables.tcpalog->data, acpi_data_len(tables.tcpalog));
 
+    if (tpm_find()) {
+        tpm_config = (FWCfgTPMConfig) {
+            .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE),
+            .tpm_version = cpu_to_le32(tpm_get_version(tpm_find())),
+            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_NONE)
+        };
+        fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config",
+                        &tpm_config, sizeof tpm_config);
+    }
+
     vmgenid_dev = find_vmgenid_dev();
     if (vmgenid_dev) {
         vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), pcms->fw_cfg,
diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt
index c230c4c93e..2ddb768084 100644
--- a/docs/specs/tpm.txt
+++ b/docs/specs/tpm.txt
@@ -20,6 +20,26 @@ QEMU files related to TPM TIS interface:
  - hw/tpm/tpm_tis.h
 
 
+= fw_cfg interface =
+
+The bios/firmware may use the "etc/tpm/config" fw_cfg entry for
+configuring the guest appropriately.
+
+The entry of 6 bytes has the following content, in little-endian:
+
+    #define TPM_VERSION_UNSPEC          0
+    #define TPM_VERSION_1_2             1
+    #define TPM_VERSION_2_0             2
+
+    #define TPM_PPI_VERSION_NONE        0
+    #define TPM_PPI_VERSION_1_30        1
+
+    struct FWCfgTPMConfig {
+        uint32_t tpmppi_address;         /* PPI memory location */
+        uint8_t tpm_version;             /* TPM version */
+        uint8_t tpmppi_version;          /* PPI version */
+    };
+
 = ACPI Interface =
 
 The TPM device is defined with ACPI ID "PNP0C31". QEMU builds a SSDT and passes
-- 
2.17.0.253.g3dd125b46d

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-05-15 12:14 [Qemu-devel] [PATCH v3 0/4] Add support for TPM Physical Presence interface Marc-André Lureau
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 1/4] tpm: implement virtual memory device for TPM PPI Marc-André Lureau
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 2/4] acpi: add fw_cfg file for TPM and PPI virtual memory device Marc-André Lureau
@ 2018-05-15 12:14 ` Marc-André Lureau
  2018-06-20 14:08   ` Michael S. Tsirkin
  2018-06-21 12:54   ` Igor Mammedov
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 4/4] tpm: add a fake ACPI memory clear interface Marc-André Lureau
  2018-06-20 13:11 ` [Qemu-devel] [PATCH v3 0/4] Add support for TPM Physical Presence interface Marc-André Lureau
  4 siblings, 2 replies; 40+ messages in thread
From: Marc-André Lureau @ 2018-05-15 12:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: Paolo Bonzini, stefanb, Marcel Apfelbaum, Eduardo Habkost,
	Igor Mammedov, Michael S. Tsirkin, Richard Henderson

From: Stefan Berger <stefanb@linux.vnet.ibm.com>

The TPM Physical Presence interface consists of an ACPI part, a shared
memory part, and code in the firmware. Users can send messages to the
firmware by writing a code into the shared memory through invoking the
ACPI code. When a reboot happens, the firmware looks for the code and
acts on it by sending sequences of commands to the TPM.

This patch adds the ACPI code. It is similar to the one in EDK2 but doesn't
assume that SMIs are necessary to use. It uses a similar datastructure for
the shared memory as EDK2 does so that EDK2 and SeaBIOS could both make use
of it. I extended the shared memory data structure with an array of 256
bytes, one for each code that could be implemented. The array contains
flags describing the individual codes. This decouples the ACPI implementation
from the firmware implementation.

The underlying TCG specification is accessible from the following page.

https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/

This patch implements version 1.30.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>

---

v4 (Marc-André):
 - replace 'DerefOf (FUNC [N])' with a function, to fix Windows ACPI
    handling.
 - replace 'return Package (..) {} ' with scoped variables, to fix
   Windows ACPI handling.

v3:
 - add support for PPI to CRB
 - split up OperationRegion TPPI into two parts, one containing
   the registers (TPP1) and the other one the flags (TPP2); switched
   the order of the flags versus registers in the code
 - adapted ACPI code to small changes to the array of flags where
   previous flag 0 was removed and now shifting right wasn't always
   necessary anymore

v2:
 - get rid of FAIL variable; function 5 was using it and always
   returns 0; the value is related to the ACPI function call not
   a possible failure of the TPM function call.
 - extend shared memory data structure with per-opcode entries
   holding flags and use those flags to determine what to return
   to caller
 - implement interface version 1.3
---
 include/hw/acpi/tpm.h |  21 +++
 hw/i386/acpi-build.c  | 294 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 314 insertions(+), 1 deletion(-)

diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
index f79d68a77a..fc53f08827 100644
--- a/include/hw/acpi/tpm.h
+++ b/include/hw/acpi/tpm.h
@@ -196,4 +196,25 @@ REG32(CRB_DATA_BUFFER, 0x80)
 #define TPM_PPI_VERSION_NONE        0
 #define TPM_PPI_VERSION_1_30        1
 
+struct tpm_ppi {
+    uint8_t  func[256];      /* 0x000: per TPM function implementation flags;
+                                       set by BIOS */
+/* whether function is blocked by BIOS settings; bits 0, 1, 2 */
+#define TPM_PPI_FUNC_NOT_IMPLEMENTED     (0 << 0)
+#define TPM_PPI_FUNC_BIOS_ONLY           (1 << 0)
+#define TPM_PPI_FUNC_BLOCKED             (2 << 0)
+#define TPM_PPI_FUNC_ALLOWED_USR_REQ     (3 << 0)
+#define TPM_PPI_FUNC_ALLOWED_USR_NOT_REQ (4 << 0)
+#define TPM_PPI_FUNC_MASK                (7 << 0)
+    uint8_t ppin;            /* 0x100 : set by BIOS */
+    uint32_t ppip;           /* 0x101 : set by ACPI; not used */
+    uint32_t pprp;           /* 0x105 : response from TPM; set by BIOS */
+    uint32_t pprq;           /* 0x109 : opcode; set by ACPI */
+    uint32_t pprm;           /* 0x10d : parameter for opcode; set by ACPI */
+    uint32_t lppr;           /* 0x111 : last opcode; set by BIOS */
+    uint32_t fret;           /* 0x115 : set by ACPI; not used */
+    uint8_t res1[0x40];      /* 0x119 : reserved for future use */
+    uint8_t next_step;       /* 0x159 : next step after reboot; set by BIOS */
+} QEMU_PACKED;
+
 #endif /* HW_ACPI_TPM_H */
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index f6d447f03a..95be4f0710 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -43,6 +43,7 @@
 #include "hw/acpi/memory_hotplug.h"
 #include "sysemu/tpm.h"
 #include "hw/acpi/tpm.h"
+#include "hw/tpm/tpm_ppi.h"
 #include "hw/acpi/vmgenid.h"
 #include "sysemu/tpm_backend.h"
 #include "hw/timer/mc146818rtc_regs.h"
@@ -1789,6 +1790,292 @@ static Aml *build_q35_osc_method(void)
     return method;
 }
 
+static void
+build_tpm_ppi(Aml *dev)
+{
+    Aml *method, *name, *field, *ifctx, *ifctx2, *ifctx3, *pak;
+    struct tpm_ppi *tpm_ppi = NULL;
+    int i;
+
+    /*
+     * TPP1 is for the flags that indicate which PPI operations
+     * are supported by the firmware. The firmware is expected to
+     * write these flags.
+     */
+    aml_append(dev,
+               aml_operation_region("TPP1", AML_SYSTEM_MEMORY,
+                                    aml_int(TPM_PPI_ADDR_BASE),
+                                    sizeof(tpm_ppi->func)));
+    field = aml_field("TPP1", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
+    for (i = 0; i < sizeof(tpm_ppi->func); i++) {
+        char *tmp = g_strdup_printf("FN%02X", i);
+        aml_append(field, aml_named_field(tmp, BITS_PER_BYTE));
+        g_free(tmp);
+    }
+    aml_append(dev, field);
+
+    /*
+     * TPP2 is for the registers that ACPI code used to pass
+     * the PPI code and parameter (PPRQ, PPRM) to the firmware.
+     */
+    aml_append(dev,
+               aml_operation_region("TPP2", AML_SYSTEM_MEMORY,
+                                    aml_int(TPM_PPI_ADDR_BASE +
+                                            offsetof(struct tpm_ppi, ppin)),
+                                    sizeof(struct tpm_ppi) -
+                                        sizeof(tpm_ppi->func)));
+    field = aml_field("TPP2", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
+    aml_append(field, aml_named_field("PPIN",
+               sizeof(uint8_t) * BITS_PER_BYTE));
+    aml_append(field, aml_named_field("PPIP",
+               sizeof(uint32_t) * BITS_PER_BYTE));
+    aml_append(field, aml_named_field("PPRP",
+               sizeof(uint32_t) * BITS_PER_BYTE));
+    aml_append(field, aml_named_field("PPRQ",
+               sizeof(uint32_t) * BITS_PER_BYTE));
+    aml_append(field, aml_named_field("PPRM",
+               sizeof(uint32_t) * BITS_PER_BYTE));
+    aml_append(field, aml_named_field("LPPR",
+               sizeof(uint32_t) * BITS_PER_BYTE));
+    aml_append(dev, field);
+
+    method = aml_method("TPFN", 1, AML_SERIALIZED);
+    {
+        for (i = 0; i < sizeof(tpm_ppi->func); i++) {
+            ifctx = aml_if(aml_equal(aml_int(i), aml_arg(0)));
+            {
+                aml_append(ifctx, aml_return(aml_name("FN%02X", i)));
+            }
+            aml_append(method, ifctx);
+        }
+        aml_append(method, aml_return(aml_int(0)));
+    }
+    aml_append(dev, method);
+
+    pak = aml_package(2);
+    aml_append(pak, aml_int(0));
+    aml_append(pak, aml_int(0));
+    name = aml_name_decl("TPM2", pak);
+    aml_append(dev, name);
+
+    pak = aml_package(3);
+    aml_append(pak, aml_int(0));
+    aml_append(pak, aml_int(0));
+    aml_append(pak, aml_int(0));
+    name = aml_name_decl("TPM3", pak);
+    aml_append(dev, name);
+
+    method = aml_method("_DSM", 4, AML_SERIALIZED);
+    {
+        uint8_t zerobyte[1] = { 0 };
+
+        ifctx = aml_if(
+            aml_equal(aml_arg(0),
+                      aml_touuid("3DDDFAA6-361B-4EB4-A424-8D10089D1653")));
+        {
+            aml_append(ifctx,
+                       aml_store(aml_to_integer(aml_arg(2)), aml_local(0)));
+
+            /* standard DSM query function */
+            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(0)));
+            {
+                uint8_t byte_list[2] = { 0xff, 0x01 };
+                aml_append(ifctx2, aml_return(aml_buffer(2, byte_list)));
+            }
+            aml_append(ifctx, ifctx2);
+
+            /* interface version: 1.3 */
+            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(1)));
+            {
+                aml_append(ifctx2, aml_return(aml_string("1.3")));
+            }
+            aml_append(ifctx, ifctx2);
+
+            /* submit TPM operation */
+            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(2)));
+            {
+                /* get opcode */
+                aml_append(ifctx2,
+                           aml_store(aml_derefof(aml_index(aml_arg(3),
+                                                           aml_int(0))),
+                                     aml_local(0)));
+                /* get opcode flags */
+                aml_append(ifctx2,
+                           aml_store(aml_call1("TPFN", aml_local(0)),
+                                     aml_local(1)));
+                ifctx3 = aml_if(
+                    aml_equal(
+                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
+                        aml_int(TPM_PPI_FUNC_NOT_IMPLEMENTED)));
+                {
+                    /* 1: not implemented */
+                    aml_append(ifctx3, aml_return(aml_int(1)));
+                }
+                aml_append(ifctx2, ifctx3);
+                aml_append(ifctx2, aml_store(aml_local(0), aml_name("PPRQ")));
+                aml_append(ifctx2, aml_store(aml_int(0), aml_name("PPRM")));
+                /* 0: success */
+                aml_append(ifctx2, aml_return(aml_int(0)));
+            }
+            aml_append(ifctx, ifctx2);
+
+            /* get pending TPM operation */
+            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(3)));
+            {
+                /* revision to integer */
+                aml_append(ifctx2,
+                           aml_store(
+                               aml_to_integer(aml_arg(1)),
+                               aml_local(1)));
+                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(1)));
+                {
+                    aml_append(ifctx3,
+                               aml_store(
+                                   aml_name("PPRQ"),
+                                   aml_index(aml_name("TPM2"), aml_int(1))));
+                    aml_append(ifctx3, aml_return(aml_name("TPM2")));
+                }
+                aml_append(ifctx2, ifctx3);
+
+                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(2)));
+                {
+                    aml_append(ifctx3,
+                               aml_store(
+                                   aml_name("PPRQ"),
+                                   aml_index(aml_name("TPM3"), aml_int(1))));
+                    aml_append(ifctx3,
+                               aml_store(
+                                   aml_name("PPRM"),
+                                   aml_index(aml_name("TPM3"), aml_int(2))));
+                    aml_append(ifctx3, aml_return(aml_name("TPM3")));
+                }
+                aml_append(ifctx2, ifctx3);
+            }
+            aml_append(ifctx, ifctx2);
+
+            /* get platform-specific action to transition to pre-OS env. */
+            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(4)));
+            {
+                /* reboot */
+                aml_append(ifctx2, aml_return(aml_int(2)));
+            }
+            aml_append(ifctx, ifctx2);
+
+            /* get TPM operation response */
+            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(5)));
+            {
+                aml_append(ifctx2,
+                           aml_store(
+                               aml_name("LPPR"),
+                               aml_index(aml_name("TPM3"), aml_int(1))));
+                aml_append(ifctx2,
+                           aml_store(
+                               aml_name("PPRP"),
+                               aml_index(aml_name("TPM3"), aml_int(2))));
+                aml_append(ifctx2, aml_return(aml_name("TPM3")));
+            }
+            aml_append(ifctx, ifctx2);
+
+            /* submit preferred user language */
+            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(6)));
+            {
+                /* 3 = not implemented */
+                aml_append(ifctx2, aml_return(aml_int(3)));
+            }
+            aml_append(ifctx, ifctx2);
+
+            /* submit TPM operation v2 */
+            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(7)));
+            {
+                /* get opcode */
+                aml_append(ifctx2,
+                           aml_store(aml_derefof(aml_index(aml_arg(3),
+                                                           aml_int(0))),
+                                     aml_local(0)));
+                /* get opcode flags */
+                aml_append(ifctx2,
+                           aml_store(aml_call1("TPFN", aml_local(0)),
+                                     aml_local(1)));
+                ifctx3 = aml_if(
+                    aml_equal(
+                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
+                        aml_int(TPM_PPI_FUNC_NOT_IMPLEMENTED)));
+                {
+                    /* 1: not implemented */
+                    aml_append(ifctx3, aml_return(aml_int(1)));
+                }
+                aml_append(ifctx2, ifctx3);
+
+                ifctx3 = aml_if(
+                    aml_equal(
+                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
+                        aml_int(TPM_PPI_FUNC_BLOCKED)));
+                {
+                    /* 3: blocked by firmware */
+                    aml_append(ifctx3, aml_return(aml_int(3)));
+                }
+                aml_append(ifctx2, ifctx3);
+
+                /* revision to integer */
+                aml_append(ifctx2,
+                           aml_store(
+                               aml_to_integer(aml_arg(1)),
+                               aml_local(1)));
+
+                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(1)));
+                {
+                    /* revision 1 */
+                    aml_append(ifctx3, aml_store(aml_local(0),
+                                                 aml_name("PPRQ")));
+                    aml_append(ifctx3, aml_store(aml_int(0),
+                                                 aml_name("PPRM")));
+                }
+                aml_append(ifctx2, ifctx3);
+
+                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(2)));
+                {
+                    /* revision 2 */
+                    aml_append(ifctx3,
+                               aml_store(aml_local(0), aml_name("PPRQ")));
+                    aml_append(ifctx3,
+                               aml_store(
+                                   aml_derefof(aml_index(aml_arg(3),
+                                                         aml_int(1))),
+                                   aml_name("PPRM")));
+                }
+                aml_append(ifctx2, ifctx3);
+                /* 0: success */
+                aml_append(ifctx2, aml_return(aml_int(0)));
+            }
+            aml_append(ifctx, ifctx2);
+
+            /* get user confirmation status for operation */
+            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(8)));
+            {
+                /* get opcode */
+                aml_append(ifctx2,
+                           aml_store(aml_derefof(aml_index(aml_arg(3),
+                                                           aml_int(0))),
+                                     aml_local(0)));
+                /* get opcode flags */
+                aml_append(ifctx2,
+                           aml_store(aml_call1("TPFN", aml_local(0)),
+                                     aml_local(1)));
+                /* return confirmation status code */
+                aml_append(ifctx2,
+                           aml_return(
+                               aml_and(aml_local(1),
+                                       aml_int(TPM_PPI_FUNC_MASK), NULL)));
+            }
+            aml_append(ifctx, ifctx2);
+
+            aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
+        }
+        aml_append(method, ifctx);
+    }
+    aml_append(dev, method);
+}
+
 static void
 build_dsdt(GArray *table_data, BIOSLinker *linker,
            AcpiPmInfo *pm, AcpiMiscInfo *misc,
@@ -2153,6 +2440,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
                  */
                 /* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
                 aml_append(dev, aml_name_decl("_CRS", crs));
+
+                build_tpm_ppi(dev);
+
                 aml_append(scope, dev);
             }
 
@@ -2172,6 +2462,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
         aml_append(method, aml_return(aml_int(0x0f)));
         aml_append(dev, method);
 
+        build_tpm_ppi(dev);
+
         aml_append(sb_scope, dev);
     }
 
@@ -2918,7 +3210,7 @@ void acpi_setup(void)
         tpm_config = (FWCfgTPMConfig) {
             .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE),
             .tpm_version = cpu_to_le32(tpm_get_version(tpm_find())),
-            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_NONE)
+            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_1_30)
         };
         fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config",
                         &tpm_config, sizeof tpm_config);
-- 
2.17.0.253.g3dd125b46d

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Qemu-devel] [PATCH v3 4/4] tpm: add a fake ACPI memory clear interface
  2018-05-15 12:14 [Qemu-devel] [PATCH v3 0/4] Add support for TPM Physical Presence interface Marc-André Lureau
                   ` (2 preceding siblings ...)
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface Marc-André Lureau
@ 2018-05-15 12:14 ` Marc-André Lureau
  2018-06-21 13:02   ` Igor Mammedov
  2018-06-20 13:11 ` [Qemu-devel] [PATCH v3 0/4] Add support for TPM Physical Presence interface Marc-André Lureau
  4 siblings, 1 reply; 40+ messages in thread
From: Marc-André Lureau @ 2018-05-15 12:14 UTC (permalink / raw)
  To: qemu-devel
  Cc: Paolo Bonzini, stefanb, Marcel Apfelbaum, Eduardo Habkost,
	Igor Mammedov, Michael S. Tsirkin, Richard Henderson,
	Marc-André Lureau

This allows to pass the last failing test from the Windows HLK TPM 2.0
TCG PPI 1.3 tests.

The interface is described in the "TCG Platform Reset Attack
Mitigation Specification", chapter 6 "ACPI _DSM Function". Whether or
not we should have a real implementation remains an open question to me.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 hw/i386/acpi-build.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index 95be4f0710..392a1e50bd 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -2072,6 +2072,15 @@ build_tpm_ppi(Aml *dev)
             aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
         }
         aml_append(method, ifctx);
+
+       /* dummy MOR Memory Clear for the sake of WLK PPI test */
+        ifctx = aml_if(
+            aml_equal(aml_arg(0),
+                      aml_touuid("376054ED-CC13-4675-901C-4756D7F2D45D")));
+        {
+            aml_append(ifctx, aml_return(aml_int(0)));
+        }
+        aml_append(method, ifctx);
     }
     aml_append(dev, method);
 }
-- 
2.17.0.253.g3dd125b46d

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 1/4] tpm: implement virtual memory device for TPM PPI
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 1/4] tpm: implement virtual memory device for TPM PPI Marc-André Lureau
@ 2018-05-15 14:19   ` Stefan Berger
  2018-06-21  9:49   ` Igor Mammedov
  1 sibling, 0 replies; 40+ messages in thread
From: Stefan Berger @ 2018-05-15 14:19 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel
  Cc: Paolo Bonzini, Marcel Apfelbaum, Eduardo Habkost, Igor Mammedov,
	Michael S. Tsirkin, Richard Henderson

On 05/15/2018 08:14 AM, Marc-André Lureau wrote:
> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
>
> Implement a virtual memory device for the TPM Physical Presence interface.
> The memory is located at 0xfffef000 and used by ACPI to send messages to the

It's now located at 0xFED45000. I changed that without changing the 
commit text... Rest looks good :-)


> firmware (BIOS) and by the firmware to provide parameters for each one of
> the supported codes.
>
> This device should be used by all TPM interfaces on x86 and can be added
> by calling tpm_ppi_init_io().
>
> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>
> ---
>
> v3 (Marc-André):
>   - merge CRB support
>   - use trace events instead of DEBUG printf
>   - headers inclusion simplification
>
> v2:
>   - moved to byte access since an infrequently used device;
>     this simplifies code
>   - increase size of device to 0x400
>   - move device to 0xfffef000 since SeaBIOS has some code at 0xffff0000:
>     'On the emulators, the bios at 0xf0000 is also at 0xffff0000'
> ---
>   hw/tpm/tpm_ppi.h      | 26 ++++++++++++++++++++
>   include/hw/acpi/tpm.h |  6 +++++
>   hw/tpm/tpm_crb.c      |  5 ++++
>   hw/tpm/tpm_ppi.c      | 56 +++++++++++++++++++++++++++++++++++++++++++
>   hw/tpm/tpm_tis.c      |  5 ++++
>   hw/tpm/Makefile.objs  |  2 +-
>   hw/tpm/trace-events   |  4 ++++
>   7 files changed, 103 insertions(+), 1 deletion(-)
>   create mode 100644 hw/tpm/tpm_ppi.h
>   create mode 100644 hw/tpm/tpm_ppi.c
>
> diff --git a/hw/tpm/tpm_ppi.h b/hw/tpm/tpm_ppi.h
> new file mode 100644
> index 0000000000..17030bd989
> --- /dev/null
> +++ b/hw/tpm/tpm_ppi.h
> @@ -0,0 +1,26 @@
> +/*
> + * TPM Physical Presence Interface
> + *
> + * Copyright (C) 2018 IBM Corporation
> + *
> + * Authors:
> + *  Stefan Berger    <stefanb@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +#ifndef TPM_TPM_PPI_H
> +#define TPM_TPM_PPI_H
> +
> +#include "hw/acpi/tpm.h"
> +#include "exec/address-spaces.h"
> +
> +typedef struct TPMPPI {
> +    MemoryRegion mmio;
> +
> +    uint8_t ram[TPM_PPI_ADDR_SIZE];
> +} TPMPPI;
> +
> +void tpm_ppi_init_io(TPMPPI *tpmppi, struct MemoryRegion *m, Object *obj);
> +
> +#endif /* TPM_TPM_PPI_H */
> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
> index 46ac4dc581..c082df7d1d 100644
> --- a/include/hw/acpi/tpm.h
> +++ b/include/hw/acpi/tpm.h
> @@ -187,4 +187,10 @@ REG32(CRB_DATA_BUFFER, 0x80)
>   #define TPM2_START_METHOD_MMIO      6
>   #define TPM2_START_METHOD_CRB       7
>
> +/*
> + * Physical Presence Interface
> + */
> +#define TPM_PPI_ADDR_SIZE           0x400
> +#define TPM_PPI_ADDR_BASE           0xFED45000
> +
>   #endif /* HW_ACPI_TPM_H */
> diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
> index a92dd50437..4f585564d9 100644
> --- a/hw/tpm/tpm_crb.c
> +++ b/hw/tpm/tpm_crb.c
> @@ -29,6 +29,7 @@
>   #include "sysemu/reset.h"
>   #include "tpm_int.h"
>   #include "tpm_util.h"
> +#include "tpm_ppi.h"
>   #include "trace.h"
>
>   typedef struct CRBState {
> @@ -41,6 +42,8 @@ typedef struct CRBState {
>       MemoryRegion cmdmem;
>
>       size_t be_buffer_size;
> +
> +    TPMPPI ppi;
>   } CRBState;
>
>   #define CRB(obj) OBJECT_CHECK(CRBState, (obj), TYPE_TPM_CRB)
> @@ -291,6 +294,8 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp)
>       memory_region_add_subregion(get_system_memory(),
>           TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem);
>
> +    tpm_ppi_init_io(&s->ppi, get_system_memory(), OBJECT(s));
> +
>       qemu_register_reset(tpm_crb_reset, dev);
>   }
>
> diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c
> new file mode 100644
> index 0000000000..0019c3e6fc
> --- /dev/null
> +++ b/hw/tpm/tpm_ppi.c
> @@ -0,0 +1,56 @@
> +/*
> + * tpm_ppi.c - TPM Physical Presence Interface
> + *
> + * Copyright (C) 2018 IBM Corporation
> + *
> + * Authors:
> + *  Stefan Berger <stefanb@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +
> +#include "tpm_ppi.h"
> +#include "trace.h"
> +
> +static uint64_t tpm_ppi_mmio_read(void *opaque, hwaddr addr,
> +                                  unsigned size)
> +{
> +    TPMPPI *s = opaque;
> +
> +    trace_tpm_ppi_mmio_read(addr, size, s->ram[addr]);
> +
> +    return s->ram[addr];
> +}
> +
> +static void tpm_ppi_mmio_write(void *opaque, hwaddr addr,
> +                               uint64_t val, unsigned size)
> +{
> +    TPMPPI *s = opaque;
> +
> +    trace_tpm_ppi_mmio_write(addr, size, val);
> +
> +    s->ram[addr] = val;
> +}
> +
> +static const MemoryRegionOps tpm_ppi_memory_ops = {
> +    .read = tpm_ppi_mmio_read,
> +    .write = tpm_ppi_mmio_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +void tpm_ppi_init_io(TPMPPI *tpmppi, struct MemoryRegion *m, Object *obj)
> +{
> +    memory_region_init_io(&tpmppi->mmio, obj, &tpm_ppi_memory_ops,
> +                          tpmppi, "tpm-ppi-mmio",
> +                          TPM_PPI_ADDR_SIZE);
> +
> +    memory_region_add_subregion(m, TPM_PPI_ADDR_BASE, &tpmppi->mmio);
> +}
> diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
> index 12f5c9a759..9a2fec455a 100644
> --- a/hw/tpm/tpm_tis.c
> +++ b/hw/tpm/tpm_tis.c
> @@ -31,6 +31,7 @@
>   #include "sysemu/tpm_backend.h"
>   #include "tpm_int.h"
>   #include "tpm_util.h"
> +#include "tpm_ppi.h"
>   #include "trace.h"
>
>   #define TPM_TIS_NUM_LOCALITIES      5     /* per spec */
> @@ -81,6 +82,8 @@ typedef struct TPMState {
>       TPMVersion be_tpm_version;
>
>       size_t be_buffer_size;
> +
> +    TPMPPI ppi;
>   } TPMState;
>
>   #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
> @@ -976,6 +979,8 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
>
>       memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
>                                   TPM_TIS_ADDR_BASE, &s->mmio);
> +
> +    tpm_ppi_init_io(&s->ppi, isa_address_space(ISA_DEVICE(dev)), OBJECT(s));
>   }
>
>   static void tpm_tis_initfn(Object *obj)
> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
> index 1dc9f8bf2c..eedd8b6858 100644
> --- a/hw/tpm/Makefile.objs
> +++ b/hw/tpm/Makefile.objs
> @@ -1,4 +1,4 @@
> -common-obj-y += tpm_util.o
> +common-obj-y += tpm_util.o tpm_ppi.o
>   common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
>   common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o
>   common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events
> index 25bee0cecf..81f9923401 100644
> --- a/hw/tpm/trace-events
> +++ b/hw/tpm/trace-events
> @@ -8,6 +8,10 @@ tpm_crb_mmio_write(uint64_t addr, unsigned size, uint32_t val) "CRB write 0x" TA
>   tpm_passthrough_handle_request(void *cmd) "processing command %p"
>   tpm_passthrough_reset(void) "reset"
>
> +# hw/tpm/tpm_ppi.c
> +tpm_ppi_mmio_read(uint64_t addr, unsigned size, uint32_t val) "PPI read 0x" TARGET_FMT_plx " len:%u val: 0x%" PRIx32
> +tpm_ppi_mmio_write(uint64_t addr, unsigned size, uint32_t val) "PPI write 0x" TARGET_FMT_plx " len:%u val: 0x%" PRIx32
> +
>   # hw/tpm/tpm_util.c
>   tpm_util_get_buffer_size_hdr_len(uint32_t len, size_t expected) "tpm_resp->hdr.len = %u, expected = %zu"
>   tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, expected = %zu"

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/4] Add support for TPM Physical Presence interface
  2018-05-15 12:14 [Qemu-devel] [PATCH v3 0/4] Add support for TPM Physical Presence interface Marc-André Lureau
                   ` (3 preceding siblings ...)
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 4/4] tpm: add a fake ACPI memory clear interface Marc-André Lureau
@ 2018-06-20 13:11 ` Marc-André Lureau
  4 siblings, 0 replies; 40+ messages in thread
From: Marc-André Lureau @ 2018-06-20 13:11 UTC (permalink / raw)
  To: QEMU
  Cc: Eduardo Habkost, Michael S. Tsirkin, Stefan Berger,
	Marc-André Lureau, Igor Mammedov, Paolo Bonzini,
	Richard Henderson

On Tue, May 15, 2018 at 2:14 PM, Marc-André Lureau
<marcandre.lureau@redhat.com> wrote:
> Hi,
>
> The following patches implement the TPM Physical Presence Interface
> that allows a user to set a command via ACPI (sysfs entry in Linux)
> that, upon the next reboot, the firmware looks for and acts upon by
> sending sequences of commands to the TPM.
>
> A dedicated memory region is added to the TPM CRB & TIS devices, at
> address/size 0xFED45000/0x400. A new "etc/tpm/config" fw_cfg entry
> holds the location for that PPI region and some version details, to
> allow for future flexibility.
>
> With the associated edk2/ovmf firmware, the Windows HLK "PPI 1.3" test
> now runs successfully.
>
> It is based on previous work from Stefan Berger ("[PATCH v2 0/4]
> Implement Physical Presence interface for TPM 1.2 and 2")
>
> Git branches:
> https://github.com/elmarco/qemu tpm-ppi
> https://github.com/elmarco/edk2 tpm-ppi
>
> Marc-André Lureau (1):
>   tpm: add a fake ACPI memory clear interface
>
> Stefan Berger (3):
>   tpm: implement virtual memory device for TPM PPI
>   acpi: add fw_cfg file for TPM and PPI virtual memory device
>   acpi: build TPM Physical Presence interface

ping

>
>  hw/tpm/tpm_ppi.h      |  26 ++++
>  include/hw/acpi/tpm.h |  30 ++++
>  hw/i386/acpi-build.c  | 318 ++++++++++++++++++++++++++++++++++++++++++
>  hw/tpm/tpm_crb.c      |   5 +
>  hw/tpm/tpm_ppi.c      |  56 ++++++++
>  hw/tpm/tpm_tis.c      |   5 +
>  docs/specs/tpm.txt    |  20 +++
>  hw/tpm/Makefile.objs  |   2 +-
>  hw/tpm/trace-events   |   4 +
>  9 files changed, 465 insertions(+), 1 deletion(-)
>  create mode 100644 hw/tpm/tpm_ppi.h
>  create mode 100644 hw/tpm/tpm_ppi.c
>
> --
> 2.17.0.253.g3dd125b46d
>
>



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface Marc-André Lureau
@ 2018-06-20 14:08   ` Michael S. Tsirkin
  2018-06-20 14:35     ` Marc-André Lureau
  2018-06-21 12:54   ` Igor Mammedov
  1 sibling, 1 reply; 40+ messages in thread
From: Michael S. Tsirkin @ 2018-06-20 14:08 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Paolo Bonzini, stefanb, Marcel Apfelbaum,
	Eduardo Habkost, Igor Mammedov, Richard Henderson

On Tue, May 15, 2018 at 02:14:32PM +0200, Marc-André Lureau wrote:
> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
> 
> The TPM Physical Presence interface consists of an ACPI part, a shared
> memory part, and code in the firmware. Users can send messages to the
> firmware by writing a code into the shared memory through invoking the
> ACPI code. When a reboot happens, the firmware looks for the code and
> acts on it by sending sequences of commands to the TPM.
> 
> This patch adds the ACPI code. It is similar to the one in EDK2 but doesn't
> assume that SMIs are necessary to use. It uses a similar datastructure for
> the shared memory as EDK2 does so that EDK2 and SeaBIOS could both make use
> of it. I extended the shared memory data structure with an array of 256
> bytes, one for each code that could be implemented. The array contains
> flags describing the individual codes. This decouples the ACPI implementation
> from the firmware implementation.
> 
> The underlying TCG specification is accessible from the following page.
> 
> https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/
> 
> This patch implements version 1.30.
> 
> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> 
> ---
> 
> v4 (Marc-André):
>  - replace 'DerefOf (FUNC [N])' with a function, to fix Windows ACPI
>     handling.
>  - replace 'return Package (..) {} ' with scoped variables, to fix
>    Windows ACPI handling.
> 
> v3:
>  - add support for PPI to CRB
>  - split up OperationRegion TPPI into two parts, one containing
>    the registers (TPP1) and the other one the flags (TPP2); switched
>    the order of the flags versus registers in the code
>  - adapted ACPI code to small changes to the array of flags where
>    previous flag 0 was removed and now shifting right wasn't always
>    necessary anymore
> 
> v2:
>  - get rid of FAIL variable; function 5 was using it and always
>    returns 0; the value is related to the ACPI function call not
>    a possible failure of the TPM function call.
>  - extend shared memory data structure with per-opcode entries
>    holding flags and use those flags to determine what to return
>    to caller
>  - implement interface version 1.3
> ---
>  include/hw/acpi/tpm.h |  21 +++
>  hw/i386/acpi-build.c  | 294 +++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 314 insertions(+), 1 deletion(-)
> 
> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
> index f79d68a77a..fc53f08827 100644
> --- a/include/hw/acpi/tpm.h
> +++ b/include/hw/acpi/tpm.h
> @@ -196,4 +196,25 @@ REG32(CRB_DATA_BUFFER, 0x80)
>  #define TPM_PPI_VERSION_NONE        0
>  #define TPM_PPI_VERSION_1_30        1
>  
> +struct tpm_ppi {

The name violate the coding style.


> +    uint8_t  func[256];      /* 0x000: per TPM function implementation flags;
> +                                       set by BIOS */
> +/* whether function is blocked by BIOS settings; bits 0, 1, 2 */
> +#define TPM_PPI_FUNC_NOT_IMPLEMENTED     (0 << 0)
> +#define TPM_PPI_FUNC_BIOS_ONLY           (1 << 0)
> +#define TPM_PPI_FUNC_BLOCKED             (2 << 0)
> +#define TPM_PPI_FUNC_ALLOWED_USR_REQ     (3 << 0)
> +#define TPM_PPI_FUNC_ALLOWED_USR_NOT_REQ (4 << 0)
> +#define TPM_PPI_FUNC_MASK                (7 << 0)
> +    uint8_t ppin;            /* 0x100 : set by BIOS */

Are you sure it's right? Below ints will all end up misaligned ...

> +    uint32_t ppip;           /* 0x101 : set by ACPI; not used */
> +    uint32_t pprp;           /* 0x105 : response from TPM; set by BIOS */
> +    uint32_t pprq;           /* 0x109 : opcode; set by ACPI */
> +    uint32_t pprm;           /* 0x10d : parameter for opcode; set by ACPI */
> +    uint32_t lppr;           /* 0x111 : last opcode; set by BIOS */
> +    uint32_t fret;           /* 0x115 : set by ACPI; not used */
> +    uint8_t res1[0x40];      /* 0x119 : reserved for future use */
> +    uint8_t next_step;       /* 0x159 : next step after reboot; set by BIOS */
> +} QEMU_PACKED;
> +
>  #endif /* HW_ACPI_TPM_H */

Igor could you pls take a quick look at the rest?

-- 
MST

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-06-20 14:08   ` Michael S. Tsirkin
@ 2018-06-20 14:35     ` Marc-André Lureau
  2018-06-20 15:08       ` Laszlo Ersek
                         ` (2 more replies)
  0 siblings, 3 replies; 40+ messages in thread
From: Marc-André Lureau @ 2018-06-20 14:35 UTC (permalink / raw)
  To: Michael S. Tsirkin, Laszlo Ersek
  Cc: Eduardo Habkost, Stefan Berger, QEMU, Igor Mammedov,
	Paolo Bonzini, Richard Henderson

Hi

On Wed, Jun 20, 2018 at 4:08 PM, Michael S. Tsirkin <mst@redhat.com> wrote:
> On Tue, May 15, 2018 at 02:14:32PM +0200, Marc-André Lureau wrote:
>> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>
>> The TPM Physical Presence interface consists of an ACPI part, a shared
>> memory part, and code in the firmware. Users can send messages to the
>> firmware by writing a code into the shared memory through invoking the
>> ACPI code. When a reboot happens, the firmware looks for the code and
>> acts on it by sending sequences of commands to the TPM.
>>
>> This patch adds the ACPI code. It is similar to the one in EDK2 but doesn't
>> assume that SMIs are necessary to use. It uses a similar datastructure for
>> the shared memory as EDK2 does so that EDK2 and SeaBIOS could both make use
>> of it. I extended the shared memory data structure with an array of 256
>> bytes, one for each code that could be implemented. The array contains
>> flags describing the individual codes. This decouples the ACPI implementation
>> from the firmware implementation.
>>
>> The underlying TCG specification is accessible from the following page.
>>
>> https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/
>>
>> This patch implements version 1.30.
>>
>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>
>> ---
>>
>> v4 (Marc-André):
>>  - replace 'DerefOf (FUNC [N])' with a function, to fix Windows ACPI
>>     handling.
>>  - replace 'return Package (..) {} ' with scoped variables, to fix
>>    Windows ACPI handling.
>>
>> v3:
>>  - add support for PPI to CRB
>>  - split up OperationRegion TPPI into two parts, one containing
>>    the registers (TPP1) and the other one the flags (TPP2); switched
>>    the order of the flags versus registers in the code
>>  - adapted ACPI code to small changes to the array of flags where
>>    previous flag 0 was removed and now shifting right wasn't always
>>    necessary anymore
>>
>> v2:
>>  - get rid of FAIL variable; function 5 was using it and always
>>    returns 0; the value is related to the ACPI function call not
>>    a possible failure of the TPM function call.
>>  - extend shared memory data structure with per-opcode entries
>>    holding flags and use those flags to determine what to return
>>    to caller
>>  - implement interface version 1.3
>> ---
>>  include/hw/acpi/tpm.h |  21 +++
>>  hw/i386/acpi-build.c  | 294 +++++++++++++++++++++++++++++++++++++++++-
>>  2 files changed, 314 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
>> index f79d68a77a..fc53f08827 100644
>> --- a/include/hw/acpi/tpm.h
>> +++ b/include/hw/acpi/tpm.h
>> @@ -196,4 +196,25 @@ REG32(CRB_DATA_BUFFER, 0x80)
>>  #define TPM_PPI_VERSION_NONE        0
>>  #define TPM_PPI_VERSION_1_30        1
>>
>> +struct tpm_ppi {
>
> The name violate the coding style.

That's easy to change. Stefan could do it on commit if the rest of the
patch is unchanged.
>
>
>> +    uint8_t  func[256];      /* 0x000: per TPM function implementation flags;
>> +                                       set by BIOS */
>> +/* whether function is blocked by BIOS settings; bits 0, 1, 2 */
>> +#define TPM_PPI_FUNC_NOT_IMPLEMENTED     (0 << 0)
>> +#define TPM_PPI_FUNC_BIOS_ONLY           (1 << 0)
>> +#define TPM_PPI_FUNC_BLOCKED             (2 << 0)
>> +#define TPM_PPI_FUNC_ALLOWED_USR_REQ     (3 << 0)
>> +#define TPM_PPI_FUNC_ALLOWED_USR_NOT_REQ (4 << 0)
>> +#define TPM_PPI_FUNC_MASK                (7 << 0)
>> +    uint8_t ppin;            /* 0x100 : set by BIOS */
>
> Are you sure it's right? Below ints will all end up misaligned ...

Hmm. Sadly, we didn't noticed when doing the edk2 part either. If we
change it in qemu, we will have to change it in edk2 as well

>> +    uint32_t ppip;           /* 0x101 : set by ACPI; not used */
>> +    uint32_t pprp;           /* 0x105 : response from TPM; set by BIOS */
>> +    uint32_t pprq;           /* 0x109 : opcode; set by ACPI */
>> +    uint32_t pprm;           /* 0x10d : parameter for opcode; set by ACPI */
>> +    uint32_t lppr;           /* 0x111 : last opcode; set by BIOS */
>> +    uint32_t fret;           /* 0x115 : set by ACPI; not used */
>> +    uint8_t res1[0x40];      /* 0x119 : reserved for future use */
>> +    uint8_t next_step;       /* 0x159 : next step after reboot; set by BIOS */
>> +} QEMU_PACKED;
>> +
>>  #endif /* HW_ACPI_TPM_H */
>
> Igor could you pls take a quick look at the rest?
>
> --
> MST
>

thanks


-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-06-20 14:35     ` Marc-André Lureau
@ 2018-06-20 15:08       ` Laszlo Ersek
  2018-06-20 15:31       ` Michael S. Tsirkin
  2018-06-20 16:37       ` Stefan Berger
  2 siblings, 0 replies; 40+ messages in thread
From: Laszlo Ersek @ 2018-06-20 15:08 UTC (permalink / raw)
  To: Marc-André Lureau, Michael S. Tsirkin
  Cc: Eduardo Habkost, Stefan Berger, QEMU, Igor Mammedov,
	Paolo Bonzini, Richard Henderson

On 06/20/18 16:35, Marc-André Lureau wrote:
> Hi
> 
> On Wed, Jun 20, 2018 at 4:08 PM, Michael S. Tsirkin <mst@redhat.com> wrote:
>> On Tue, May 15, 2018 at 02:14:32PM +0200, Marc-André Lureau wrote:
>>> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>
>>> The TPM Physical Presence interface consists of an ACPI part, a shared
>>> memory part, and code in the firmware. Users can send messages to the
>>> firmware by writing a code into the shared memory through invoking the
>>> ACPI code. When a reboot happens, the firmware looks for the code and
>>> acts on it by sending sequences of commands to the TPM.
>>>
>>> This patch adds the ACPI code. It is similar to the one in EDK2 but doesn't
>>> assume that SMIs are necessary to use. It uses a similar datastructure for
>>> the shared memory as EDK2 does so that EDK2 and SeaBIOS could both make use
>>> of it. I extended the shared memory data structure with an array of 256
>>> bytes, one for each code that could be implemented. The array contains
>>> flags describing the individual codes. This decouples the ACPI implementation
>>> from the firmware implementation.
>>>
>>> The underlying TCG specification is accessible from the following page.
>>>
>>> https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/
>>>
>>> This patch implements version 1.30.
>>>
>>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>
>>> ---
>>>
>>> v4 (Marc-André):
>>>  - replace 'DerefOf (FUNC [N])' with a function, to fix Windows ACPI
>>>     handling.
>>>  - replace 'return Package (..) {} ' with scoped variables, to fix
>>>    Windows ACPI handling.
>>>
>>> v3:
>>>  - add support for PPI to CRB
>>>  - split up OperationRegion TPPI into two parts, one containing
>>>    the registers (TPP1) and the other one the flags (TPP2); switched
>>>    the order of the flags versus registers in the code
>>>  - adapted ACPI code to small changes to the array of flags where
>>>    previous flag 0 was removed and now shifting right wasn't always
>>>    necessary anymore
>>>
>>> v2:
>>>  - get rid of FAIL variable; function 5 was using it and always
>>>    returns 0; the value is related to the ACPI function call not
>>>    a possible failure of the TPM function call.
>>>  - extend shared memory data structure with per-opcode entries
>>>    holding flags and use those flags to determine what to return
>>>    to caller
>>>  - implement interface version 1.3
>>> ---
>>>  include/hw/acpi/tpm.h |  21 +++
>>>  hw/i386/acpi-build.c  | 294 +++++++++++++++++++++++++++++++++++++++++-
>>>  2 files changed, 314 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
>>> index f79d68a77a..fc53f08827 100644
>>> --- a/include/hw/acpi/tpm.h
>>> +++ b/include/hw/acpi/tpm.h
>>> @@ -196,4 +196,25 @@ REG32(CRB_DATA_BUFFER, 0x80)
>>>  #define TPM_PPI_VERSION_NONE        0
>>>  #define TPM_PPI_VERSION_1_30        1
>>>
>>> +struct tpm_ppi {
>>
>> The name violate the coding style.
> 
> That's easy to change. Stefan could do it on commit if the rest of the
> patch is unchanged.
>>
>>
>>> +    uint8_t  func[256];      /* 0x000: per TPM function implementation flags;
>>> +                                       set by BIOS */
>>> +/* whether function is blocked by BIOS settings; bits 0, 1, 2 */
>>> +#define TPM_PPI_FUNC_NOT_IMPLEMENTED     (0 << 0)
>>> +#define TPM_PPI_FUNC_BIOS_ONLY           (1 << 0)
>>> +#define TPM_PPI_FUNC_BLOCKED             (2 << 0)
>>> +#define TPM_PPI_FUNC_ALLOWED_USR_REQ     (3 << 0)
>>> +#define TPM_PPI_FUNC_ALLOWED_USR_NOT_REQ (4 << 0)
>>> +#define TPM_PPI_FUNC_MASK                (7 << 0)
>>> +    uint8_t ppin;            /* 0x100 : set by BIOS */
>>
>> Are you sure it's right? Below ints will all end up misaligned ...
> 
> Hmm. Sadly, we didn't noticed when doing the edk2 part either. If we
> change it in qemu, we will have to change it in edk2 as well

I don't see why the misalignment is a problem. AIUI functionally it
shouldn't be an issue, and performance is not critical.

We did make sure the struct was packed in edk2 too.

Thanks,
Laszlo

> 
>>> +    uint32_t ppip;           /* 0x101 : set by ACPI; not used */
>>> +    uint32_t pprp;           /* 0x105 : response from TPM; set by BIOS */
>>> +    uint32_t pprq;           /* 0x109 : opcode; set by ACPI */
>>> +    uint32_t pprm;           /* 0x10d : parameter for opcode; set by ACPI */
>>> +    uint32_t lppr;           /* 0x111 : last opcode; set by BIOS */
>>> +    uint32_t fret;           /* 0x115 : set by ACPI; not used */
>>> +    uint8_t res1[0x40];      /* 0x119 : reserved for future use */
>>> +    uint8_t next_step;       /* 0x159 : next step after reboot; set by BIOS */
>>> +} QEMU_PACKED;
>>> +
>>>  #endif /* HW_ACPI_TPM_H */
>>
>> Igor could you pls take a quick look at the rest?
>>
>> --
>> MST
>>
> 
> thanks
> 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-06-20 14:35     ` Marc-André Lureau
  2018-06-20 15:08       ` Laszlo Ersek
@ 2018-06-20 15:31       ` Michael S. Tsirkin
  2018-06-20 16:37       ` Stefan Berger
  2 siblings, 0 replies; 40+ messages in thread
From: Michael S. Tsirkin @ 2018-06-20 15:31 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Laszlo Ersek, Eduardo Habkost, Stefan Berger, QEMU,
	Igor Mammedov, Paolo Bonzini, Richard Henderson

On Wed, Jun 20, 2018 at 04:35:23PM +0200, Marc-André Lureau wrote:
> Hi
> 
> On Wed, Jun 20, 2018 at 4:08 PM, Michael S. Tsirkin <mst@redhat.com> wrote:
> > On Tue, May 15, 2018 at 02:14:32PM +0200, Marc-André Lureau wrote:
> >> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
> >>
> >> The TPM Physical Presence interface consists of an ACPI part, a shared
> >> memory part, and code in the firmware. Users can send messages to the
> >> firmware by writing a code into the shared memory through invoking the
> >> ACPI code. When a reboot happens, the firmware looks for the code and
> >> acts on it by sending sequences of commands to the TPM.
> >>
> >> This patch adds the ACPI code. It is similar to the one in EDK2 but doesn't
> >> assume that SMIs are necessary to use. It uses a similar datastructure for
> >> the shared memory as EDK2 does so that EDK2 and SeaBIOS could both make use
> >> of it. I extended the shared memory data structure with an array of 256
> >> bytes, one for each code that could be implemented. The array contains
> >> flags describing the individual codes. This decouples the ACPI implementation
> >> from the firmware implementation.
> >>
> >> The underlying TCG specification is accessible from the following page.
> >>
> >> https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/
> >>
> >> This patch implements version 1.30.
> >>
> >> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> >>
> >> ---
> >>
> >> v4 (Marc-André):
> >>  - replace 'DerefOf (FUNC [N])' with a function, to fix Windows ACPI
> >>     handling.
> >>  - replace 'return Package (..) {} ' with scoped variables, to fix
> >>    Windows ACPI handling.
> >>
> >> v3:
> >>  - add support for PPI to CRB
> >>  - split up OperationRegion TPPI into two parts, one containing
> >>    the registers (TPP1) and the other one the flags (TPP2); switched
> >>    the order of the flags versus registers in the code
> >>  - adapted ACPI code to small changes to the array of flags where
> >>    previous flag 0 was removed and now shifting right wasn't always
> >>    necessary anymore
> >>
> >> v2:
> >>  - get rid of FAIL variable; function 5 was using it and always
> >>    returns 0; the value is related to the ACPI function call not
> >>    a possible failure of the TPM function call.
> >>  - extend shared memory data structure with per-opcode entries
> >>    holding flags and use those flags to determine what to return
> >>    to caller
> >>  - implement interface version 1.3
> >> ---
> >>  include/hw/acpi/tpm.h |  21 +++
> >>  hw/i386/acpi-build.c  | 294 +++++++++++++++++++++++++++++++++++++++++-
> >>  2 files changed, 314 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
> >> index f79d68a77a..fc53f08827 100644
> >> --- a/include/hw/acpi/tpm.h
> >> +++ b/include/hw/acpi/tpm.h
> >> @@ -196,4 +196,25 @@ REG32(CRB_DATA_BUFFER, 0x80)
> >>  #define TPM_PPI_VERSION_NONE        0
> >>  #define TPM_PPI_VERSION_1_30        1
> >>
> >> +struct tpm_ppi {
> >
> > The name violate the coding style.
> 
> That's easy to change. Stefan could do it on commit if the rest of the
> patch is unchanged.
> >
> >
> >> +    uint8_t  func[256];      /* 0x000: per TPM function implementation flags;
> >> +                                       set by BIOS */
> >> +/* whether function is blocked by BIOS settings; bits 0, 1, 2 */
> >> +#define TPM_PPI_FUNC_NOT_IMPLEMENTED     (0 << 0)
> >> +#define TPM_PPI_FUNC_BIOS_ONLY           (1 << 0)
> >> +#define TPM_PPI_FUNC_BLOCKED             (2 << 0)
> >> +#define TPM_PPI_FUNC_ALLOWED_USR_REQ     (3 << 0)
> >> +#define TPM_PPI_FUNC_ALLOWED_USR_NOT_REQ (4 << 0)
> >> +#define TPM_PPI_FUNC_MASK                (7 << 0)
> >> +    uint8_t ppin;            /* 0x100 : set by BIOS */
> >
> > Are you sure it's right? Below ints will all end up misaligned ...
> 
> Hmm. Sadly, we didn't noticed when doing the edk2 part either. If we
> change it in qemu, we will have to change it in edk2 as well

Might be worth it, it's often very slow to access unaligned fields.

> >> +    uint32_t ppip;           /* 0x101 : set by ACPI; not used */
> >> +    uint32_t pprp;           /* 0x105 : response from TPM; set by BIOS */
> >> +    uint32_t pprq;           /* 0x109 : opcode; set by ACPI */
> >> +    uint32_t pprm;           /* 0x10d : parameter for opcode; set by ACPI */
> >> +    uint32_t lppr;           /* 0x111 : last opcode; set by BIOS */
> >> +    uint32_t fret;           /* 0x115 : set by ACPI; not used */
> >> +    uint8_t res1[0x40];      /* 0x119 : reserved for future use */
> >> +    uint8_t next_step;       /* 0x159 : next step after reboot; set by BIOS */
> >> +} QEMU_PACKED;
> >> +
> >>  #endif /* HW_ACPI_TPM_H */
> >
> > Igor could you pls take a quick look at the rest?
> >
> > --
> > MST
> >
> 
> thanks
> 
> 
> -- 
> Marc-André Lureau

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-06-20 14:35     ` Marc-André Lureau
  2018-06-20 15:08       ` Laszlo Ersek
  2018-06-20 15:31       ` Michael S. Tsirkin
@ 2018-06-20 16:37       ` Stefan Berger
  2 siblings, 0 replies; 40+ messages in thread
From: Stefan Berger @ 2018-06-20 16:37 UTC (permalink / raw)
  To: Marc-André Lureau, Michael S. Tsirkin, Laszlo Ersek
  Cc: Eduardo Habkost, QEMU, Igor Mammedov, Paolo Bonzini, Richard Henderson

On 06/20/2018 10:35 AM, Marc-André Lureau wrote:
> Hi
>
> On Wed, Jun 20, 2018 at 4:08 PM, Michael S. Tsirkin <mst@redhat.com> wrote:
>> On Tue, May 15, 2018 at 02:14:32PM +0200, Marc-André Lureau wrote:
>>> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>
>>> The TPM Physical Presence interface consists of an ACPI part, a shared
>>> memory part, and code in the firmware. Users can send messages to the
>>> firmware by writing a code into the shared memory through invoking the
>>> ACPI code. When a reboot happens, the firmware looks for the code and
>>> acts on it by sending sequences of commands to the TPM.
>>>
>>> This patch adds the ACPI code. It is similar to the one in EDK2 but doesn't
>>> assume that SMIs are necessary to use. It uses a similar datastructure for
>>> the shared memory as EDK2 does so that EDK2 and SeaBIOS could both make use
>>> of it. I extended the shared memory data structure with an array of 256
>>> bytes, one for each code that could be implemented. The array contains
>>> flags describing the individual codes. This decouples the ACPI implementation
>>> from the firmware implementation.
>>>
>>> The underlying TCG specification is accessible from the following page.
>>>
>>> https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/
>>>
>>> This patch implements version 1.30.
>>>
>>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>
>>> ---
>>>
>>> v4 (Marc-André):
>>>   - replace 'DerefOf (FUNC [N])' with a function, to fix Windows ACPI
>>>      handling.
>>>   - replace 'return Package (..) {} ' with scoped variables, to fix
>>>     Windows ACPI handling.
>>>
>>> v3:
>>>   - add support for PPI to CRB
>>>   - split up OperationRegion TPPI into two parts, one containing
>>>     the registers (TPP1) and the other one the flags (TPP2); switched
>>>     the order of the flags versus registers in the code
>>>   - adapted ACPI code to small changes to the array of flags where
>>>     previous flag 0 was removed and now shifting right wasn't always
>>>     necessary anymore
>>>
>>> v2:
>>>   - get rid of FAIL variable; function 5 was using it and always
>>>     returns 0; the value is related to the ACPI function call not
>>>     a possible failure of the TPM function call.
>>>   - extend shared memory data structure with per-opcode entries
>>>     holding flags and use those flags to determine what to return
>>>     to caller
>>>   - implement interface version 1.3
>>> ---
>>>   include/hw/acpi/tpm.h |  21 +++
>>>   hw/i386/acpi-build.c  | 294 +++++++++++++++++++++++++++++++++++++++++-
>>>   2 files changed, 314 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
>>> index f79d68a77a..fc53f08827 100644
>>> --- a/include/hw/acpi/tpm.h
>>> +++ b/include/hw/acpi/tpm.h
>>> @@ -196,4 +196,25 @@ REG32(CRB_DATA_BUFFER, 0x80)
>>>   #define TPM_PPI_VERSION_NONE        0
>>>   #define TPM_PPI_VERSION_1_30        1
>>>
>>> +struct tpm_ppi {
>> The name violate the coding style.
> That's easy to change. Stefan could do it on commit if the rest of the
> patch is unchanged.

Call it TPMPPIData?

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 1/4] tpm: implement virtual memory device for TPM PPI
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 1/4] tpm: implement virtual memory device for TPM PPI Marc-André Lureau
  2018-05-15 14:19   ` Stefan Berger
@ 2018-06-21  9:49   ` Igor Mammedov
  2018-06-21 10:51     ` Marc-André Lureau
  1 sibling, 1 reply; 40+ messages in thread
From: Igor Mammedov @ 2018-06-21  9:49 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Paolo Bonzini, stefanb, Marcel Apfelbaum,
	Eduardo Habkost, Michael S. Tsirkin, Richard Henderson

On Tue, 15 May 2018 14:14:30 +0200
Marc-André Lureau <marcandre.lureau@redhat.com> wrote:

> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
> 
> Implement a virtual memory device for the TPM Physical Presence interface.
> The memory is located at 0xfffef000 and used by ACPI to send messages to the
> firmware (BIOS) and by the firmware to provide parameters for each one of
> the supported codes.
> 
> This device should be used by all TPM interfaces on x86 and can be added
> by calling tpm_ppi_init_io().
> 
> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> ---
> 
> v3 (Marc-André):
>  - merge CRB support
>  - use trace events instead of DEBUG printf
>  - headers inclusion simplification
> 
> v2:
>  - moved to byte access since an infrequently used device;
>    this simplifies code
>  - increase size of device to 0x400
>  - move device to 0xfffef000 since SeaBIOS has some code at 0xffff0000:
>    'On the emulators, the bios at 0xf0000 is also at 0xffff0000'
> ---
>  hw/tpm/tpm_ppi.h      | 26 ++++++++++++++++++++
>  include/hw/acpi/tpm.h |  6 +++++
>  hw/tpm/tpm_crb.c      |  5 ++++
>  hw/tpm/tpm_ppi.c      | 56 +++++++++++++++++++++++++++++++++++++++++++
>  hw/tpm/tpm_tis.c      |  5 ++++
>  hw/tpm/Makefile.objs  |  2 +-
>  hw/tpm/trace-events   |  4 ++++
>  7 files changed, 103 insertions(+), 1 deletion(-)
>  create mode 100644 hw/tpm/tpm_ppi.h
>  create mode 100644 hw/tpm/tpm_ppi.c
> 
> diff --git a/hw/tpm/tpm_ppi.h b/hw/tpm/tpm_ppi.h
> new file mode 100644
> index 0000000000..17030bd989
> --- /dev/null
> +++ b/hw/tpm/tpm_ppi.h
> @@ -0,0 +1,26 @@
> +/*
> + * TPM Physical Presence Interface
> + *
> + * Copyright (C) 2018 IBM Corporation
> + *
> + * Authors:
> + *  Stefan Berger    <stefanb@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +#ifndef TPM_TPM_PPI_H
> +#define TPM_TPM_PPI_H
> +
> +#include "hw/acpi/tpm.h"
> +#include "exec/address-spaces.h"
> +
> +typedef struct TPMPPI {
> +    MemoryRegion mmio;
> +
> +    uint8_t ram[TPM_PPI_ADDR_SIZE];
> +} TPMPPI;
> +
> +void tpm_ppi_init_io(TPMPPI *tpmppi, struct MemoryRegion *m, Object *obj);
> +
> +#endif /* TPM_TPM_PPI_H */
> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
> index 46ac4dc581..c082df7d1d 100644
> --- a/include/hw/acpi/tpm.h
> +++ b/include/hw/acpi/tpm.h
> @@ -187,4 +187,10 @@ REG32(CRB_DATA_BUFFER, 0x80)
>  #define TPM2_START_METHOD_MMIO      6
>  #define TPM2_START_METHOD_CRB       7
>  
> +/*
> + * Physical Presence Interface
> + */
> +#define TPM_PPI_ADDR_SIZE           0x400
> +#define TPM_PPI_ADDR_BASE           0xFED45000
> +
>  #endif /* HW_ACPI_TPM_H */
> diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
> index a92dd50437..4f585564d9 100644
> --- a/hw/tpm/tpm_crb.c
> +++ b/hw/tpm/tpm_crb.c
> @@ -29,6 +29,7 @@
>  #include "sysemu/reset.h"
>  #include "tpm_int.h"
>  #include "tpm_util.h"
> +#include "tpm_ppi.h"
>  #include "trace.h"
>  
>  typedef struct CRBState {
> @@ -41,6 +42,8 @@ typedef struct CRBState {
>      MemoryRegion cmdmem;
>  
>      size_t be_buffer_size;
> +
> +    TPMPPI ppi;
>  } CRBState;
>  
>  #define CRB(obj) OBJECT_CHECK(CRBState, (obj), TYPE_TPM_CRB)
> @@ -291,6 +294,8 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp)
>      memory_region_add_subregion(get_system_memory(),
>          TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem);
>  
> +    tpm_ppi_init_io(&s->ppi, get_system_memory(), OBJECT(s));
> +
>      qemu_register_reset(tpm_crb_reset, dev);
>  }
>  
> diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c
> new file mode 100644
> index 0000000000..0019c3e6fc
> --- /dev/null
> +++ b/hw/tpm/tpm_ppi.c
> @@ -0,0 +1,56 @@
> +/*
> + * tpm_ppi.c - TPM Physical Presence Interface
> + *
> + * Copyright (C) 2018 IBM Corporation
> + *
> + * Authors:
> + *  Stefan Berger <stefanb@us.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include "qemu/osdep.h"
> +
> +#include "tpm_ppi.h"
> +#include "trace.h"
> +
> +static uint64_t tpm_ppi_mmio_read(void *opaque, hwaddr addr,
> +                                  unsigned size)
> +{
> +    TPMPPI *s = opaque;
> +
> +    trace_tpm_ppi_mmio_read(addr, size, s->ram[addr]);
> +
> +    return s->ram[addr];
> +}
> +
> +static void tpm_ppi_mmio_write(void *opaque, hwaddr addr,
> +                               uint64_t val, unsigned size)
> +{
> +    TPMPPI *s = opaque;
> +
> +    trace_tpm_ppi_mmio_write(addr, size, val);
> +
> +    s->ram[addr] = val;
> +}
> +
> +static const MemoryRegionOps tpm_ppi_memory_ops = {
> +    .read = tpm_ppi_mmio_read,
> +    .write = tpm_ppi_mmio_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .valid = {
> +        .min_access_size = 1,
> +        .max_access_size = 1,
> +    },
> +};
> +
> +void tpm_ppi_init_io(TPMPPI *tpmppi, struct MemoryRegion *m, Object *obj)
> +{
> +    memory_region_init_io(&tpmppi->mmio, obj, &tpm_ppi_memory_ops,
> +                          tpmppi, "tpm-ppi-mmio",
> +                          TPM_PPI_ADDR_SIZE);
> +
> +    memory_region_add_subregion(m, TPM_PPI_ADDR_BASE, &tpmppi->mmio);
I'd push TPM_PPI_ADDR_BASE up to the stack so it would be obvious
at tpm_ppi_init_io() call site wrt which region the offset is applied

also maybe s/TPM_PPI_ADDR_BASE/TPM_PPI_ADDR_OFFSET/?

> +}
> diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
> index 12f5c9a759..9a2fec455a 100644
> --- a/hw/tpm/tpm_tis.c
> +++ b/hw/tpm/tpm_tis.c
> @@ -31,6 +31,7 @@
>  #include "sysemu/tpm_backend.h"
>  #include "tpm_int.h"
>  #include "tpm_util.h"
> +#include "tpm_ppi.h"
>  #include "trace.h"
>  
>  #define TPM_TIS_NUM_LOCALITIES      5     /* per spec */
> @@ -81,6 +82,8 @@ typedef struct TPMState {
>      TPMVersion be_tpm_version;
>  
>      size_t be_buffer_size;
> +
> +    TPMPPI ppi;
>  } TPMState;
>  
>  #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
> @@ -976,6 +979,8 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
>  
>      memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
>                                  TPM_TIS_ADDR_BASE, &s->mmio);
> +
> +    tpm_ppi_init_io(&s->ppi, isa_address_space(ISA_DEVICE(dev)), OBJECT(s));
what address space it would get here and  at what offset address space is mapped?

>  }
>  
>  static void tpm_tis_initfn(Object *obj)
> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
> index 1dc9f8bf2c..eedd8b6858 100644
> --- a/hw/tpm/Makefile.objs
> +++ b/hw/tpm/Makefile.objs
> @@ -1,4 +1,4 @@
> -common-obj-y += tpm_util.o
> +common-obj-y += tpm_util.o tpm_ppi.o
>  common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
>  common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o
>  common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events
> index 25bee0cecf..81f9923401 100644
> --- a/hw/tpm/trace-events
> +++ b/hw/tpm/trace-events
> @@ -8,6 +8,10 @@ tpm_crb_mmio_write(uint64_t addr, unsigned size, uint32_t val) "CRB write 0x" TA
>  tpm_passthrough_handle_request(void *cmd) "processing command %p"
>  tpm_passthrough_reset(void) "reset"
>  
> +# hw/tpm/tpm_ppi.c
> +tpm_ppi_mmio_read(uint64_t addr, unsigned size, uint32_t val) "PPI read 0x" TARGET_FMT_plx " len:%u val: 0x%" PRIx32
> +tpm_ppi_mmio_write(uint64_t addr, unsigned size, uint32_t val) "PPI write 0x" TARGET_FMT_plx " len:%u val: 0x%" PRIx32
> +
>  # hw/tpm/tpm_util.c
>  tpm_util_get_buffer_size_hdr_len(uint32_t len, size_t expected) "tpm_resp->hdr.len = %u, expected = %zu"
>  tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, expected = %zu"

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 2/4] acpi: add fw_cfg file for TPM and PPI virtual memory device
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 2/4] acpi: add fw_cfg file for TPM and PPI virtual memory device Marc-André Lureau
@ 2018-06-21 10:00   ` Igor Mammedov
  2018-06-21 10:10     ` Marc-André Lureau
  0 siblings, 1 reply; 40+ messages in thread
From: Igor Mammedov @ 2018-06-21 10:00 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Paolo Bonzini, stefanb, Marcel Apfelbaum,
	Eduardo Habkost, Michael S. Tsirkin, Richard Henderson

On Tue, 15 May 2018 14:14:31 +0200
Marc-André Lureau <marcandre.lureau@redhat.com> wrote:

> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
> 
> To avoid having to hard code the base address of the PPI virtual
> memory device we introduce a fw_cfg file etc/tpm/config that holds the
> base address of the PPI device, the version of the PPI interface and
> the version of the attached TPM.
is it related to TPM_PPI_ADDR_BASE added in previous patch?

> 
> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> [ Marc-André: renamed to etc/tpm/config, made it static, document it ]
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  include/hw/acpi/tpm.h |  3 +++
>  hw/i386/acpi-build.c  | 17 +++++++++++++++++
>  docs/specs/tpm.txt    | 20 ++++++++++++++++++++
>  3 files changed, 40 insertions(+)
> 
> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
> index c082df7d1d..f79d68a77a 100644
> --- a/include/hw/acpi/tpm.h
> +++ b/include/hw/acpi/tpm.h
> @@ -193,4 +193,7 @@ REG32(CRB_DATA_BUFFER, 0x80)
>  #define TPM_PPI_ADDR_SIZE           0x400
>  #define TPM_PPI_ADDR_BASE           0xFED45000
>  
> +#define TPM_PPI_VERSION_NONE        0
> +#define TPM_PPI_VERSION_1_30        1
> +
>  #endif /* HW_ACPI_TPM_H */
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index 9bc6d97ea1..f6d447f03a 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -119,6 +119,12 @@ typedef struct AcpiBuildPciBusHotplugState {
>      bool pcihp_bridge_en;
>  } AcpiBuildPciBusHotplugState;
>  
> +typedef struct FWCfgTPMConfig {
> +    uint32_t tpmppi_address;
> +    uint8_t tpm_version;
> +    uint8_t tpmppi_version;
> +} QEMU_PACKED FWCfgTPMConfig;
> +
>  static void init_common_fadt_data(Object *o, AcpiFadtData *data)
>  {
>      uint32_t io = object_property_get_uint(o, ACPI_PM_PROP_PM_IO_BASE, NULL);
> @@ -2873,6 +2879,7 @@ void acpi_setup(void)
>      AcpiBuildTables tables;
>      AcpiBuildState *build_state;
>      Object *vmgenid_dev;
> +    static FWCfgTPMConfig tpm_config;
>  
>      if (!pcms->fw_cfg) {
>          ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
> @@ -2907,6 +2914,16 @@ void acpi_setup(void)
>      fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
>                      tables.tcpalog->data, acpi_data_len(tables.tcpalog));
>  
> +    if (tpm_find()) {
> +        tpm_config = (FWCfgTPMConfig) {
> +            .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE),
> +            .tpm_version = cpu_to_le32(tpm_get_version(tpm_find())),
> +            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_NONE)
> +        };
> +        fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config",
> +                        &tpm_config, sizeof tpm_config);
> +    }
why it's in ACPI part of the code, shouldn't it be a part of device,
could TPM be used without ACPI at all (-noacpi CLI option)?

Wouldn't adding fwcfg entry unconditionally break migration?

> +
>      vmgenid_dev = find_vmgenid_dev();
>      if (vmgenid_dev) {
>          vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), pcms->fw_cfg,
> diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt
> index c230c4c93e..2ddb768084 100644
> --- a/docs/specs/tpm.txt
> +++ b/docs/specs/tpm.txt
> @@ -20,6 +20,26 @@ QEMU files related to TPM TIS interface:
>   - hw/tpm/tpm_tis.h
>  
>  
> += fw_cfg interface =
> +
> +The bios/firmware may use the "etc/tpm/config" fw_cfg entry for
> +configuring the guest appropriately.
> +
> +The entry of 6 bytes has the following content, in little-endian:
> +
> +    #define TPM_VERSION_UNSPEC          0
> +    #define TPM_VERSION_1_2             1
> +    #define TPM_VERSION_2_0             2
> +
> +    #define TPM_PPI_VERSION_NONE        0
> +    #define TPM_PPI_VERSION_1_30        1
> +
> +    struct FWCfgTPMConfig {
> +        uint32_t tpmppi_address;         /* PPI memory location */
> +        uint8_t tpm_version;             /* TPM version */
> +        uint8_t tpmppi_version;          /* PPI version */
> +    };
> +
>  = ACPI Interface =
>  
>  The TPM device is defined with ACPI ID "PNP0C31". QEMU builds a SSDT and passes

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 2/4] acpi: add fw_cfg file for TPM and PPI virtual memory device
  2018-06-21 10:00   ` Igor Mammedov
@ 2018-06-21 10:10     ` Marc-André Lureau
  2018-06-21 13:55       ` Igor Mammedov
                         ` (2 more replies)
  0 siblings, 3 replies; 40+ messages in thread
From: Marc-André Lureau @ 2018-06-21 10:10 UTC (permalink / raw)
  To: Igor Mammedov, Laszlo Ersek
  Cc: Eduardo Habkost, Michael S. Tsirkin, Stefan Berger, QEMU,
	Paolo Bonzini, Richard Henderson

Hi

On Thu, Jun 21, 2018 at 12:00 PM, Igor Mammedov <imammedo@redhat.com> wrote:
> On Tue, 15 May 2018 14:14:31 +0200
> Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
>
>> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>
>> To avoid having to hard code the base address of the PPI virtual
>> memory device we introduce a fw_cfg file etc/tpm/config that holds the
>> base address of the PPI device, the version of the PPI interface and
>> the version of the attached TPM.
> is it related to TPM_PPI_ADDR_BASE added in previous patch?
>
>>
>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>> [ Marc-André: renamed to etc/tpm/config, made it static, document it ]
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  include/hw/acpi/tpm.h |  3 +++
>>  hw/i386/acpi-build.c  | 17 +++++++++++++++++
>>  docs/specs/tpm.txt    | 20 ++++++++++++++++++++
>>  3 files changed, 40 insertions(+)
>>
>> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
>> index c082df7d1d..f79d68a77a 100644
>> --- a/include/hw/acpi/tpm.h
>> +++ b/include/hw/acpi/tpm.h
>> @@ -193,4 +193,7 @@ REG32(CRB_DATA_BUFFER, 0x80)
>>  #define TPM_PPI_ADDR_SIZE           0x400
>>  #define TPM_PPI_ADDR_BASE           0xFED45000
>>
>> +#define TPM_PPI_VERSION_NONE        0
>> +#define TPM_PPI_VERSION_1_30        1
>> +
>>  #endif /* HW_ACPI_TPM_H */
>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>> index 9bc6d97ea1..f6d447f03a 100644
>> --- a/hw/i386/acpi-build.c
>> +++ b/hw/i386/acpi-build.c
>> @@ -119,6 +119,12 @@ typedef struct AcpiBuildPciBusHotplugState {
>>      bool pcihp_bridge_en;
>>  } AcpiBuildPciBusHotplugState;
>>
>> +typedef struct FWCfgTPMConfig {
>> +    uint32_t tpmppi_address;
>> +    uint8_t tpm_version;
>> +    uint8_t tpmppi_version;
>> +} QEMU_PACKED FWCfgTPMConfig;
>> +
>>  static void init_common_fadt_data(Object *o, AcpiFadtData *data)
>>  {
>>      uint32_t io = object_property_get_uint(o, ACPI_PM_PROP_PM_IO_BASE, NULL);
>> @@ -2873,6 +2879,7 @@ void acpi_setup(void)
>>      AcpiBuildTables tables;
>>      AcpiBuildState *build_state;
>>      Object *vmgenid_dev;
>> +    static FWCfgTPMConfig tpm_config;
>>
>>      if (!pcms->fw_cfg) {
>>          ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
>> @@ -2907,6 +2914,16 @@ void acpi_setup(void)
>>      fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
>>                      tables.tcpalog->data, acpi_data_len(tables.tcpalog));
>>
>> +    if (tpm_find()) {
>> +        tpm_config = (FWCfgTPMConfig) {
>> +            .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE),
>> +            .tpm_version = cpu_to_le32(tpm_get_version(tpm_find())),
>> +            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_NONE)
>> +        };
>> +        fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config",
>> +                        &tpm_config, sizeof tpm_config);
>> +    }
> why it's in ACPI part of the code, shouldn't it be a part of device,
> could TPM be used without ACPI at all (-noacpi CLI option)?
>
> Wouldn't adding fwcfg entry unconditionally break migration?

Because of unstable entry IDs? that could be problematic. (especially
during boot time) What do you think Laszlo?

I guess we could have a "ppi" device property, that would imply having
the etc/tpm/config fw_cfg entry. We would enable it by default in
newer machine types (3.0?)

>
>> +
>>      vmgenid_dev = find_vmgenid_dev();
>>      if (vmgenid_dev) {
>>          vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), pcms->fw_cfg,
>> diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt
>> index c230c4c93e..2ddb768084 100644
>> --- a/docs/specs/tpm.txt
>> +++ b/docs/specs/tpm.txt
>> @@ -20,6 +20,26 @@ QEMU files related to TPM TIS interface:
>>   - hw/tpm/tpm_tis.h
>>
>>
>> += fw_cfg interface =
>> +
>> +The bios/firmware may use the "etc/tpm/config" fw_cfg entry for
>> +configuring the guest appropriately.
>> +
>> +The entry of 6 bytes has the following content, in little-endian:
>> +
>> +    #define TPM_VERSION_UNSPEC          0
>> +    #define TPM_VERSION_1_2             1
>> +    #define TPM_VERSION_2_0             2
>> +
>> +    #define TPM_PPI_VERSION_NONE        0
>> +    #define TPM_PPI_VERSION_1_30        1
>> +
>> +    struct FWCfgTPMConfig {
>> +        uint32_t tpmppi_address;         /* PPI memory location */
>> +        uint8_t tpm_version;             /* TPM version */
>> +        uint8_t tpmppi_version;          /* PPI version */
>> +    };
>> +
>>  = ACPI Interface =
>>
>>  The TPM device is defined with ACPI ID "PNP0C31". QEMU builds a SSDT and passes
>
>



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 1/4] tpm: implement virtual memory device for TPM PPI
  2018-06-21  9:49   ` Igor Mammedov
@ 2018-06-21 10:51     ` Marc-André Lureau
  2018-06-21 13:59       ` Igor Mammedov
  0 siblings, 1 reply; 40+ messages in thread
From: Marc-André Lureau @ 2018-06-21 10:51 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Eduardo Habkost, Michael S. Tsirkin, Stefan Berger, QEMU,
	Paolo Bonzini, Richard Henderson

Hi

On Thu, Jun 21, 2018 at 11:49 AM, Igor Mammedov <imammedo@redhat.com> wrote:
> On Tue, 15 May 2018 14:14:30 +0200
> Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
>
>> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>
>> Implement a virtual memory device for the TPM Physical Presence interface.
>> The memory is located at 0xfffef000 and used by ACPI to send messages to the
>> firmware (BIOS) and by the firmware to provide parameters for each one of
>> the supported codes.
>>
>> This device should be used by all TPM interfaces on x86 and can be added
>> by calling tpm_ppi_init_io().
>>
>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>
>> ---
>>
>> v3 (Marc-André):
>>  - merge CRB support
>>  - use trace events instead of DEBUG printf
>>  - headers inclusion simplification
>>
>> v2:
>>  - moved to byte access since an infrequently used device;
>>    this simplifies code
>>  - increase size of device to 0x400
>>  - move device to 0xfffef000 since SeaBIOS has some code at 0xffff0000:
>>    'On the emulators, the bios at 0xf0000 is also at 0xffff0000'
>> ---
>>  hw/tpm/tpm_ppi.h      | 26 ++++++++++++++++++++
>>  include/hw/acpi/tpm.h |  6 +++++
>>  hw/tpm/tpm_crb.c      |  5 ++++
>>  hw/tpm/tpm_ppi.c      | 56 +++++++++++++++++++++++++++++++++++++++++++
>>  hw/tpm/tpm_tis.c      |  5 ++++
>>  hw/tpm/Makefile.objs  |  2 +-
>>  hw/tpm/trace-events   |  4 ++++
>>  7 files changed, 103 insertions(+), 1 deletion(-)
>>  create mode 100644 hw/tpm/tpm_ppi.h
>>  create mode 100644 hw/tpm/tpm_ppi.c
>>
>> diff --git a/hw/tpm/tpm_ppi.h b/hw/tpm/tpm_ppi.h
>> new file mode 100644
>> index 0000000000..17030bd989
>> --- /dev/null
>> +++ b/hw/tpm/tpm_ppi.h
>> @@ -0,0 +1,26 @@
>> +/*
>> + * TPM Physical Presence Interface
>> + *
>> + * Copyright (C) 2018 IBM Corporation
>> + *
>> + * Authors:
>> + *  Stefan Berger    <stefanb@us.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>> + * See the COPYING file in the top-level directory.
>> + */
>> +#ifndef TPM_TPM_PPI_H
>> +#define TPM_TPM_PPI_H
>> +
>> +#include "hw/acpi/tpm.h"
>> +#include "exec/address-spaces.h"
>> +
>> +typedef struct TPMPPI {
>> +    MemoryRegion mmio;
>> +
>> +    uint8_t ram[TPM_PPI_ADDR_SIZE];
>> +} TPMPPI;
>> +
>> +void tpm_ppi_init_io(TPMPPI *tpmppi, struct MemoryRegion *m, Object *obj);
>> +
>> +#endif /* TPM_TPM_PPI_H */
>> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
>> index 46ac4dc581..c082df7d1d 100644
>> --- a/include/hw/acpi/tpm.h
>> +++ b/include/hw/acpi/tpm.h
>> @@ -187,4 +187,10 @@ REG32(CRB_DATA_BUFFER, 0x80)
>>  #define TPM2_START_METHOD_MMIO      6
>>  #define TPM2_START_METHOD_CRB       7
>>
>> +/*
>> + * Physical Presence Interface
>> + */
>> +#define TPM_PPI_ADDR_SIZE           0x400
>> +#define TPM_PPI_ADDR_BASE           0xFED45000
>> +
>>  #endif /* HW_ACPI_TPM_H */
>> diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
>> index a92dd50437..4f585564d9 100644
>> --- a/hw/tpm/tpm_crb.c
>> +++ b/hw/tpm/tpm_crb.c
>> @@ -29,6 +29,7 @@
>>  #include "sysemu/reset.h"
>>  #include "tpm_int.h"
>>  #include "tpm_util.h"
>> +#include "tpm_ppi.h"
>>  #include "trace.h"
>>
>>  typedef struct CRBState {
>> @@ -41,6 +42,8 @@ typedef struct CRBState {
>>      MemoryRegion cmdmem;
>>
>>      size_t be_buffer_size;
>> +
>> +    TPMPPI ppi;
>>  } CRBState;
>>
>>  #define CRB(obj) OBJECT_CHECK(CRBState, (obj), TYPE_TPM_CRB)
>> @@ -291,6 +294,8 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp)
>>      memory_region_add_subregion(get_system_memory(),
>>          TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem);
>>
>> +    tpm_ppi_init_io(&s->ppi, get_system_memory(), OBJECT(s));
>> +
>>      qemu_register_reset(tpm_crb_reset, dev);
>>  }
>>
>> diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c
>> new file mode 100644
>> index 0000000000..0019c3e6fc
>> --- /dev/null
>> +++ b/hw/tpm/tpm_ppi.c
>> @@ -0,0 +1,56 @@
>> +/*
>> + * tpm_ppi.c - TPM Physical Presence Interface
>> + *
>> + * Copyright (C) 2018 IBM Corporation
>> + *
>> + * Authors:
>> + *  Stefan Berger <stefanb@us.ibm.com>
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>> + * See the COPYING file in the top-level directory.
>> + *
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +
>> +#include "tpm_ppi.h"
>> +#include "trace.h"
>> +
>> +static uint64_t tpm_ppi_mmio_read(void *opaque, hwaddr addr,
>> +                                  unsigned size)
>> +{
>> +    TPMPPI *s = opaque;
>> +
>> +    trace_tpm_ppi_mmio_read(addr, size, s->ram[addr]);
>> +
>> +    return s->ram[addr];
>> +}
>> +
>> +static void tpm_ppi_mmio_write(void *opaque, hwaddr addr,
>> +                               uint64_t val, unsigned size)
>> +{
>> +    TPMPPI *s = opaque;
>> +
>> +    trace_tpm_ppi_mmio_write(addr, size, val);
>> +
>> +    s->ram[addr] = val;
>> +}
>> +
>> +static const MemoryRegionOps tpm_ppi_memory_ops = {
>> +    .read = tpm_ppi_mmio_read,
>> +    .write = tpm_ppi_mmio_write,
>> +    .endianness = DEVICE_NATIVE_ENDIAN,
>> +    .valid = {
>> +        .min_access_size = 1,
>> +        .max_access_size = 1,
>> +    },
>> +};
>> +
>> +void tpm_ppi_init_io(TPMPPI *tpmppi, struct MemoryRegion *m, Object *obj)
>> +{
>> +    memory_region_init_io(&tpmppi->mmio, obj, &tpm_ppi_memory_ops,
>> +                          tpmppi, "tpm-ppi-mmio",
>> +                          TPM_PPI_ADDR_SIZE);
>> +
>> +    memory_region_add_subregion(m, TPM_PPI_ADDR_BASE, &tpmppi->mmio);
> I'd push TPM_PPI_ADDR_BASE up to the stack so it would be obvious
> at tpm_ppi_init_io() call site wrt which region the offset is applied
>
> also maybe s/TPM_PPI_ADDR_BASE/TPM_PPI_ADDR_OFFSET/?

Hmm, it's a fixed address, and we already use TPM_TIS_ADDR_BASE /
TPM_CRB_ADDR_BASE.

>
>> +}
>> diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
>> index 12f5c9a759..9a2fec455a 100644
>> --- a/hw/tpm/tpm_tis.c
>> +++ b/hw/tpm/tpm_tis.c
>> @@ -31,6 +31,7 @@
>>  #include "sysemu/tpm_backend.h"
>>  #include "tpm_int.h"
>>  #include "tpm_util.h"
>> +#include "tpm_ppi.h"
>>  #include "trace.h"
>>
>>  #define TPM_TIS_NUM_LOCALITIES      5     /* per spec */
>> @@ -81,6 +82,8 @@ typedef struct TPMState {
>>      TPMVersion be_tpm_version;
>>
>>      size_t be_buffer_size;
>> +
>> +    TPMPPI ppi;
>>  } TPMState;
>>
>>  #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
>> @@ -976,6 +979,8 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
>>
>>      memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
>>                                  TPM_TIS_ADDR_BASE, &s->mmio);
>> +
>> +    tpm_ppi_init_io(&s->ppi, isa_address_space(ISA_DEVICE(dev)), OBJECT(s));
> what address space it would get here and  at what offset address space is mapped?

Agree, that's a bit better, done

thanks

>
>>  }
>>
>>  static void tpm_tis_initfn(Object *obj)
>> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
>> index 1dc9f8bf2c..eedd8b6858 100644
>> --- a/hw/tpm/Makefile.objs
>> +++ b/hw/tpm/Makefile.objs
>> @@ -1,4 +1,4 @@
>> -common-obj-y += tpm_util.o
>> +common-obj-y += tpm_util.o tpm_ppi.o
>>  common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
>>  common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o
>>  common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
>> diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events
>> index 25bee0cecf..81f9923401 100644
>> --- a/hw/tpm/trace-events
>> +++ b/hw/tpm/trace-events
>> @@ -8,6 +8,10 @@ tpm_crb_mmio_write(uint64_t addr, unsigned size, uint32_t val) "CRB write 0x" TA
>>  tpm_passthrough_handle_request(void *cmd) "processing command %p"
>>  tpm_passthrough_reset(void) "reset"
>>
>> +# hw/tpm/tpm_ppi.c
>> +tpm_ppi_mmio_read(uint64_t addr, unsigned size, uint32_t val) "PPI read 0x" TARGET_FMT_plx " len:%u val: 0x%" PRIx32
>> +tpm_ppi_mmio_write(uint64_t addr, unsigned size, uint32_t val) "PPI write 0x" TARGET_FMT_plx " len:%u val: 0x%" PRIx32
>> +
>>  # hw/tpm/tpm_util.c
>>  tpm_util_get_buffer_size_hdr_len(uint32_t len, size_t expected) "tpm_resp->hdr.len = %u, expected = %zu"
>>  tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, expected = %zu"
>
>



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface Marc-André Lureau
  2018-06-20 14:08   ` Michael S. Tsirkin
@ 2018-06-21 12:54   ` Igor Mammedov
  2018-06-21 13:21     ` Marc-André Lureau
  1 sibling, 1 reply; 40+ messages in thread
From: Igor Mammedov @ 2018-06-21 12:54 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Eduardo Habkost, Michael S. Tsirkin, stefanb,
	Paolo Bonzini, Richard Henderson

On Tue, 15 May 2018 14:14:32 +0200
Marc-André Lureau <marcandre.lureau@redhat.com> wrote:

> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
> 
> The TPM Physical Presence interface consists of an ACPI part, a shared
> memory part, and code in the firmware. Users can send messages to the
> firmware by writing a code into the shared memory through invoking the
> ACPI code. When a reboot happens, the firmware looks for the code and
> acts on it by sending sequences of commands to the TPM.
> 
> This patch adds the ACPI code. It is similar to the one in EDK2 but doesn't
> assume that SMIs are necessary to use. It uses a similar datastructure for
> the shared memory as EDK2 does so that EDK2 and SeaBIOS could both make use
> of it. I extended the shared memory data structure with an array of 256
> bytes, one for each code that could be implemented. The array contains
> flags describing the individual codes. This decouples the ACPI implementation
> from the firmware implementation.
> 
> The underlying TCG specification is accessible from the following page.
> 
> https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/
> 
> This patch implements version 1.30.
> 
> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> 
> ---
> 
> v4 (Marc-André):
>  - replace 'DerefOf (FUNC [N])' with a function, to fix Windows ACPI
>     handling.
>  - replace 'return Package (..) {} ' with scoped variables, to fix
>    Windows ACPI handling.
> 
> v3:
>  - add support for PPI to CRB
>  - split up OperationRegion TPPI into two parts, one containing
>    the registers (TPP1) and the other one the flags (TPP2); switched
>    the order of the flags versus registers in the code
>  - adapted ACPI code to small changes to the array of flags where
>    previous flag 0 was removed and now shifting right wasn't always
>    necessary anymore
> 
> v2:
>  - get rid of FAIL variable; function 5 was using it and always
>    returns 0; the value is related to the ACPI function call not
>    a possible failure of the TPM function call.
>  - extend shared memory data structure with per-opcode entries
>    holding flags and use those flags to determine what to return
>    to caller
>  - implement interface version 1.3
> ---
>  include/hw/acpi/tpm.h |  21 +++
>  hw/i386/acpi-build.c  | 294 +++++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 314 insertions(+), 1 deletion(-)
> 
> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
> index f79d68a77a..fc53f08827 100644
> --- a/include/hw/acpi/tpm.h
> +++ b/include/hw/acpi/tpm.h
> @@ -196,4 +196,25 @@ REG32(CRB_DATA_BUFFER, 0x80)
>  #define TPM_PPI_VERSION_NONE        0
>  #define TPM_PPI_VERSION_1_30        1
>  
> +struct tpm_ppi {
> +    uint8_t  func[256];      /* 0x000: per TPM function implementation flags;
> +                                       set by BIOS */
> +/* whether function is blocked by BIOS settings; bits 0, 1, 2 */
> +#define TPM_PPI_FUNC_NOT_IMPLEMENTED     (0 << 0)
> +#define TPM_PPI_FUNC_BIOS_ONLY           (1 << 0)
> +#define TPM_PPI_FUNC_BLOCKED             (2 << 0)
> +#define TPM_PPI_FUNC_ALLOWED_USR_REQ     (3 << 0)
> +#define TPM_PPI_FUNC_ALLOWED_USR_NOT_REQ (4 << 0)
> +#define TPM_PPI_FUNC_MASK                (7 << 0)
> +    uint8_t ppin;            /* 0x100 : set by BIOS */
> +    uint32_t ppip;           /* 0x101 : set by ACPI; not used */
> +    uint32_t pprp;           /* 0x105 : response from TPM; set by BIOS */
> +    uint32_t pprq;           /* 0x109 : opcode; set by ACPI */
> +    uint32_t pprm;           /* 0x10d : parameter for opcode; set by ACPI */
> +    uint32_t lppr;           /* 0x111 : last opcode; set by BIOS */
> +    uint32_t fret;           /* 0x115 : set by ACPI; not used */
> +    uint8_t res1[0x40];      /* 0x119 : reserved for future use */
> +    uint8_t next_step;       /* 0x159 : next step after reboot; set by BIOS */
> +} QEMU_PACKED;
is this structure plant to be used for accessing data from within QEMU
or it is just used for convenience of calculating offsets/sizes for AML?


> +
>  #endif /* HW_ACPI_TPM_H */
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index f6d447f03a..95be4f0710 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -43,6 +43,7 @@
>  #include "hw/acpi/memory_hotplug.h"
>  #include "sysemu/tpm.h"
>  #include "hw/acpi/tpm.h"
> +#include "hw/tpm/tpm_ppi.h"
>  #include "hw/acpi/vmgenid.h"
>  #include "sysemu/tpm_backend.h"
>  #include "hw/timer/mc146818rtc_regs.h"
> @@ -1789,6 +1790,292 @@ static Aml *build_q35_osc_method(void)
>      return method;
>  }
>  
> +static void
> +build_tpm_ppi(Aml *dev)
> +{
> +    Aml *method, *name, *field, *ifctx, *ifctx2, *ifctx3, *pak;
> +    struct tpm_ppi *tpm_ppi = NULL;
> +    int i;
plain AML variables throughout the function make code rather unreadable
(well, like any other AML code would be).
Pls take a look at how build_legacy_cpu_hotplug_aml() uses intermediate
more or less sanely named variables to make it more understandable.
that also should allow to reduce LOC this function takes.

> +    /*
> +     * TPP1 is for the flags that indicate which PPI operations
> +     * are supported by the firmware. The firmware is expected to
> +     * write these flags.
> +     */
> +    aml_append(dev,
> +               aml_operation_region("TPP1", AML_SYSTEM_MEMORY,
> +                                    aml_int(TPM_PPI_ADDR_BASE),
> +                                    sizeof(tpm_ppi->func)));
> +    field = aml_field("TPP1", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
> +    for (i = 0; i < sizeof(tpm_ppi->func); i++) {
> +        char *tmp = g_strdup_printf("FN%02X", i);
> +        aml_append(field, aml_named_field(tmp, BITS_PER_BYTE));
> +        g_free(tmp);
> +    }
> +    aml_append(dev, field);
> +
> +    /*
> +     * TPP2 is for the registers that ACPI code used to pass
> +     * the PPI code and parameter (PPRQ, PPRM) to the firmware.
> +     */
> +    aml_append(dev,
> +               aml_operation_region("TPP2", AML_SYSTEM_MEMORY,
> +                                    aml_int(TPM_PPI_ADDR_BASE +
> +                                            offsetof(struct tpm_ppi, ppin)),
> +                                    sizeof(struct tpm_ppi) -
> +                                        sizeof(tpm_ppi->func)));
> +    field = aml_field("TPP2", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
> +    aml_append(field, aml_named_field("PPIN",
> +               sizeof(uint8_t) * BITS_PER_BYTE));
here you already don't use tpm_ppi for sizing, so it creates a confusing mix
of both approaches.

From ACPI pov I'd prefer PPI table documented somewhere in spec docs 
(similar docs/specs/acpi_mem_hotplug.txt) and would look like in
other use-cases:

   aml_append(field, aml_named_field("PPIN", 8)

and drop "struct tpm_ppi" altogether replacing places it was used by
explicit constants.

> +    aml_append(field, aml_named_field("PPIP",
> +               sizeof(uint32_t) * BITS_PER_BYTE));
> +    aml_append(field, aml_named_field("PPRP",
> +               sizeof(uint32_t) * BITS_PER_BYTE));
> +    aml_append(field, aml_named_field("PPRQ",
> +               sizeof(uint32_t) * BITS_PER_BYTE));
> +    aml_append(field, aml_named_field("PPRM",
> +               sizeof(uint32_t) * BITS_PER_BYTE));
> +    aml_append(field, aml_named_field("LPPR",
> +               sizeof(uint32_t) * BITS_PER_BYTE));
> +    aml_append(dev, field);
> +
> +    method = aml_method("TPFN", 1, AML_SERIALIZED);
not quite sure how this method (supposed to ) work(s),
it could use nice comment explaining mechanics.

> +    {
> +        for (i = 0; i < sizeof(tpm_ppi->func); i++) {
> +            ifctx = aml_if(aml_equal(aml_int(i), aml_arg(0)));
> +            {
> +                aml_append(ifctx, aml_return(aml_name("FN%02X", i)));
> +            }
> +            aml_append(method, ifctx);
> +        }
> +        aml_append(method, aml_return(aml_int(0)));
> +    }
> +    aml_append(dev, method);
> +
> +    pak = aml_package(2);
> +    aml_append(pak, aml_int(0));
> +    aml_append(pak, aml_int(0));
> +    name = aml_name_decl("TPM2", pak);
> +    aml_append(dev, name);
> +
> +    pak = aml_package(3);
> +    aml_append(pak, aml_int(0));
> +    aml_append(pak, aml_int(0));
> +    aml_append(pak, aml_int(0));
> +    name = aml_name_decl("TPM3", pak);
> +    aml_append(dev, name);
> +
> +    method = aml_method("_DSM", 4, AML_SERIALIZED);
> +    {
> +        uint8_t zerobyte[1] = { 0 };
> +
> +        ifctx = aml_if(
> +            aml_equal(aml_arg(0),
> +                      aml_touuid("3DDDFAA6-361B-4EB4-A424-8D10089D1653")));
a comment pointing to a specific part/version of spec that documents this _DSM
for every uuid/function used here would help to review it.

> +        {
> +            aml_append(ifctx,
> +                       aml_store(aml_to_integer(aml_arg(2)), aml_local(0)));
> +
> +            /* standard DSM query function */
> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(0)));
> +            {
> +                uint8_t byte_list[2] = { 0xff, 0x01 };
> +                aml_append(ifctx2, aml_return(aml_buffer(2, byte_list)));
> +            }
> +            aml_append(ifctx, ifctx2);
> +
> +            /* interface version: 1.3 */
> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(1)));
> +            {
> +                aml_append(ifctx2, aml_return(aml_string("1.3")));
> +            }
> +            aml_append(ifctx, ifctx2);
> +
> +            /* submit TPM operation */
> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(2)));
> +            {
> +                /* get opcode */
> +                aml_append(ifctx2,
> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
> +                                                           aml_int(0))),
> +                                     aml_local(0)));
> +                /* get opcode flags */
> +                aml_append(ifctx2,
> +                           aml_store(aml_call1("TPFN", aml_local(0)),
> +                                     aml_local(1)));
> +                ifctx3 = aml_if(
> +                    aml_equal(
> +                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
> +                        aml_int(TPM_PPI_FUNC_NOT_IMPLEMENTED)));
> +                {
> +                    /* 1: not implemented */
> +                    aml_append(ifctx3, aml_return(aml_int(1)));
> +                }
> +                aml_append(ifctx2, ifctx3);
> +                aml_append(ifctx2, aml_store(aml_local(0), aml_name("PPRQ")));
> +                aml_append(ifctx2, aml_store(aml_int(0), aml_name("PPRM")));
> +                /* 0: success */
> +                aml_append(ifctx2, aml_return(aml_int(0)));
> +            }
> +            aml_append(ifctx, ifctx2);
> +
> +            /* get pending TPM operation */
> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(3)));
> +            {
> +                /* revision to integer */
> +                aml_append(ifctx2,
> +                           aml_store(
> +                               aml_to_integer(aml_arg(1)),
> +                               aml_local(1)));
> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(1)));
> +                {
> +                    aml_append(ifctx3,
> +                               aml_store(
> +                                   aml_name("PPRQ"),
> +                                   aml_index(aml_name("TPM2"), aml_int(1))));
> +                    aml_append(ifctx3, aml_return(aml_name("TPM2")));
> +                }
> +                aml_append(ifctx2, ifctx3);
> +
> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(2)));
> +                {
> +                    aml_append(ifctx3,
> +                               aml_store(
> +                                   aml_name("PPRQ"),
> +                                   aml_index(aml_name("TPM3"), aml_int(1))));
> +                    aml_append(ifctx3,
> +                               aml_store(
> +                                   aml_name("PPRM"),
> +                                   aml_index(aml_name("TPM3"), aml_int(2))));
> +                    aml_append(ifctx3, aml_return(aml_name("TPM3")));
> +                }
> +                aml_append(ifctx2, ifctx3);
> +            }
> +            aml_append(ifctx, ifctx2);
> +
> +            /* get platform-specific action to transition to pre-OS env. */
> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(4)));
> +            {
> +                /* reboot */
> +                aml_append(ifctx2, aml_return(aml_int(2)));
> +            }
> +            aml_append(ifctx, ifctx2);
> +
> +            /* get TPM operation response */
> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(5)));
> +            {
> +                aml_append(ifctx2,
> +                           aml_store(
> +                               aml_name("LPPR"),
> +                               aml_index(aml_name("TPM3"), aml_int(1))));
> +                aml_append(ifctx2,
> +                           aml_store(
> +                               aml_name("PPRP"),
> +                               aml_index(aml_name("TPM3"), aml_int(2))));
> +                aml_append(ifctx2, aml_return(aml_name("TPM3")));
> +            }
> +            aml_append(ifctx, ifctx2);
> +
> +            /* submit preferred user language */
> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(6)));
> +            {
> +                /* 3 = not implemented */
> +                aml_append(ifctx2, aml_return(aml_int(3)));
> +            }
> +            aml_append(ifctx, ifctx2);
> +
> +            /* submit TPM operation v2 */
> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(7)));
> +            {
> +                /* get opcode */
> +                aml_append(ifctx2,
> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
> +                                                           aml_int(0))),
> +                                     aml_local(0)));
> +                /* get opcode flags */
> +                aml_append(ifctx2,
> +                           aml_store(aml_call1("TPFN", aml_local(0)),
> +                                     aml_local(1)));
> +                ifctx3 = aml_if(
> +                    aml_equal(
> +                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
> +                        aml_int(TPM_PPI_FUNC_NOT_IMPLEMENTED)));
> +                {
> +                    /* 1: not implemented */
> +                    aml_append(ifctx3, aml_return(aml_int(1)));
> +                }
> +                aml_append(ifctx2, ifctx3);
> +
> +                ifctx3 = aml_if(
> +                    aml_equal(
> +                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
> +                        aml_int(TPM_PPI_FUNC_BLOCKED)));
> +                {
> +                    /* 3: blocked by firmware */
> +                    aml_append(ifctx3, aml_return(aml_int(3)));
> +                }
> +                aml_append(ifctx2, ifctx3);
> +
> +                /* revision to integer */
> +                aml_append(ifctx2,
> +                           aml_store(
> +                               aml_to_integer(aml_arg(1)),
> +                               aml_local(1)));
> +
> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(1)));
> +                {
> +                    /* revision 1 */
> +                    aml_append(ifctx3, aml_store(aml_local(0),
> +                                                 aml_name("PPRQ")));
> +                    aml_append(ifctx3, aml_store(aml_int(0),
> +                                                 aml_name("PPRM")));
> +                }
> +                aml_append(ifctx2, ifctx3);
> +
> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(2)));
> +                {
> +                    /* revision 2 */
> +                    aml_append(ifctx3,
> +                               aml_store(aml_local(0), aml_name("PPRQ")));
> +                    aml_append(ifctx3,
> +                               aml_store(
> +                                   aml_derefof(aml_index(aml_arg(3),
> +                                                         aml_int(1))),
> +                                   aml_name("PPRM")));
> +                }
> +                aml_append(ifctx2, ifctx3);
> +                /* 0: success */
> +                aml_append(ifctx2, aml_return(aml_int(0)));
> +            }
> +            aml_append(ifctx, ifctx2);
> +
> +            /* get user confirmation status for operation */
> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(8)));
> +            {
> +                /* get opcode */
> +                aml_append(ifctx2,
> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
> +                                                           aml_int(0))),
> +                                     aml_local(0)));
> +                /* get opcode flags */
> +                aml_append(ifctx2,
> +                           aml_store(aml_call1("TPFN", aml_local(0)),
> +                                     aml_local(1)));
> +                /* return confirmation status code */
> +                aml_append(ifctx2,
> +                           aml_return(
> +                               aml_and(aml_local(1),
> +                                       aml_int(TPM_PPI_FUNC_MASK), NULL)));
> +            }
> +            aml_append(ifctx, ifctx2);
> +
> +            aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
> +        }
> +        aml_append(method, ifctx);
> +    }
> +    aml_append(dev, method);
> +}
> +
>  static void
>  build_dsdt(GArray *table_data, BIOSLinker *linker,
>             AcpiPmInfo *pm, AcpiMiscInfo *misc,
> @@ -2153,6 +2440,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
>                   */
>                  /* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
>                  aml_append(dev, aml_name_decl("_CRS", crs));
> +
> +                build_tpm_ppi(dev);
> +
>                  aml_append(scope, dev);
>              }
>  
> @@ -2172,6 +2462,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
>          aml_append(method, aml_return(aml_int(0x0f)));
>          aml_append(dev, method);
>  
> +        build_tpm_ppi(dev);
> +
>          aml_append(sb_scope, dev);
>      }
>  
> @@ -2918,7 +3210,7 @@ void acpi_setup(void)
>          tpm_config = (FWCfgTPMConfig) {
>              .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE),
>              .tpm_version = cpu_to_le32(tpm_get_version(tpm_find())),
> -            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_NONE)
what was the point of introducing TPM_PPI_VERSION_NONE if it would not be used?
maybe patch ordering is problem? what if we put fwcfg patch after this one?

> +            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_1_30)
>          };
>          fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config",
>                          &tpm_config, sizeof tpm_config);

hopefully patch would be more review-able with comments and nicely named
variables, so I could actually review it functionality wise without reading
whole TPM spec(s)

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 4/4] tpm: add a fake ACPI memory clear interface
  2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 4/4] tpm: add a fake ACPI memory clear interface Marc-André Lureau
@ 2018-06-21 13:02   ` Igor Mammedov
  2018-06-21 13:24     ` Marc-André Lureau
  0 siblings, 1 reply; 40+ messages in thread
From: Igor Mammedov @ 2018-06-21 13:02 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: qemu-devel, Paolo Bonzini, stefanb, Marcel Apfelbaum,
	Eduardo Habkost, Michael S. Tsirkin, Richard Henderson

On Tue, 15 May 2018 14:14:33 +0200
Marc-André Lureau <marcandre.lureau@redhat.com> wrote:

> This allows to pass the last failing test from the Windows HLK TPM 2.0
> TCG PPI 1.3 tests.
> 
> The interface is described in the "TCG Platform Reset Attack
> Mitigation Specification", chapter 6 "ACPI _DSM Function". Whether or
> not we should have a real implementation remains an open question to me.
might it cause security issues?
What are implications of faking it and how hard it's to implement thing
per spec?

 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  hw/i386/acpi-build.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> index 95be4f0710..392a1e50bd 100644
> --- a/hw/i386/acpi-build.c
> +++ b/hw/i386/acpi-build.c
> @@ -2072,6 +2072,15 @@ build_tpm_ppi(Aml *dev)
>              aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
>          }
>          aml_append(method, ifctx);
> +
> +       /* dummy MOR Memory Clear for the sake of WLK PPI test */
> +        ifctx = aml_if(
> +            aml_equal(aml_arg(0),
> +                      aml_touuid("376054ED-CC13-4675-901C-4756D7F2D45D")));
> +        {
> +            aml_append(ifctx, aml_return(aml_int(0)));
> +        }
> +        aml_append(method, ifctx);
>      }
>      aml_append(dev, method);
>  }

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-06-21 12:54   ` Igor Mammedov
@ 2018-06-21 13:21     ` Marc-André Lureau
  2018-06-21 13:22       ` Marc-André Lureau
                         ` (2 more replies)
  0 siblings, 3 replies; 40+ messages in thread
From: Marc-André Lureau @ 2018-06-21 13:21 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Eduardo Habkost, Stefan Berger, Michael S. Tsirkin, QEMU,
	Paolo Bonzini, Richard Henderson

Hi

On Thu, Jun 21, 2018 at 2:54 PM, Igor Mammedov <imammedo@redhat.com> wrote:
> On Tue, 15 May 2018 14:14:32 +0200
> Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
>
>> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>
>> The TPM Physical Presence interface consists of an ACPI part, a shared
>> memory part, and code in the firmware. Users can send messages to the
>> firmware by writing a code into the shared memory through invoking the
>> ACPI code. When a reboot happens, the firmware looks for the code and
>> acts on it by sending sequences of commands to the TPM.
>>
>> This patch adds the ACPI code. It is similar to the one in EDK2 but doesn't
>> assume that SMIs are necessary to use. It uses a similar datastructure for
>> the shared memory as EDK2 does so that EDK2 and SeaBIOS could both make use
>> of it. I extended the shared memory data structure with an array of 256
>> bytes, one for each code that could be implemented. The array contains
>> flags describing the individual codes. This decouples the ACPI implementation
>> from the firmware implementation.
>>
>> The underlying TCG specification is accessible from the following page.
>>
>> https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/
>>
>> This patch implements version 1.30.
>>
>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>
>> ---
>>
>> v4 (Marc-André):
>>  - replace 'DerefOf (FUNC [N])' with a function, to fix Windows ACPI
>>     handling.
>>  - replace 'return Package (..) {} ' with scoped variables, to fix
>>    Windows ACPI handling.
>>
>> v3:
>>  - add support for PPI to CRB
>>  - split up OperationRegion TPPI into two parts, one containing
>>    the registers (TPP1) and the other one the flags (TPP2); switched
>>    the order of the flags versus registers in the code
>>  - adapted ACPI code to small changes to the array of flags where
>>    previous flag 0 was removed and now shifting right wasn't always
>>    necessary anymore
>>
>> v2:
>>  - get rid of FAIL variable; function 5 was using it and always
>>    returns 0; the value is related to the ACPI function call not
>>    a possible failure of the TPM function call.
>>  - extend shared memory data structure with per-opcode entries
>>    holding flags and use those flags to determine what to return
>>    to caller
>>  - implement interface version 1.3
>> ---
>>  include/hw/acpi/tpm.h |  21 +++
>>  hw/i386/acpi-build.c  | 294 +++++++++++++++++++++++++++++++++++++++++-
>>  2 files changed, 314 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
>> index f79d68a77a..fc53f08827 100644
>> --- a/include/hw/acpi/tpm.h
>> +++ b/include/hw/acpi/tpm.h
>> @@ -196,4 +196,25 @@ REG32(CRB_DATA_BUFFER, 0x80)
>>  #define TPM_PPI_VERSION_NONE        0
>>  #define TPM_PPI_VERSION_1_30        1
>>
>> +struct tpm_ppi {
>> +    uint8_t  func[256];      /* 0x000: per TPM function implementation flags;
>> +                                       set by BIOS */
>> +/* whether function is blocked by BIOS settings; bits 0, 1, 2 */
>> +#define TPM_PPI_FUNC_NOT_IMPLEMENTED     (0 << 0)
>> +#define TPM_PPI_FUNC_BIOS_ONLY           (1 << 0)
>> +#define TPM_PPI_FUNC_BLOCKED             (2 << 0)
>> +#define TPM_PPI_FUNC_ALLOWED_USR_REQ     (3 << 0)
>> +#define TPM_PPI_FUNC_ALLOWED_USR_NOT_REQ (4 << 0)
>> +#define TPM_PPI_FUNC_MASK                (7 << 0)
>> +    uint8_t ppin;            /* 0x100 : set by BIOS */
>> +    uint32_t ppip;           /* 0x101 : set by ACPI; not used */
>> +    uint32_t pprp;           /* 0x105 : response from TPM; set by BIOS */
>> +    uint32_t pprq;           /* 0x109 : opcode; set by ACPI */
>> +    uint32_t pprm;           /* 0x10d : parameter for opcode; set by ACPI */
>> +    uint32_t lppr;           /* 0x111 : last opcode; set by BIOS */
>> +    uint32_t fret;           /* 0x115 : set by ACPI; not used */
>> +    uint8_t res1[0x40];      /* 0x119 : reserved for future use */
>> +    uint8_t next_step;       /* 0x159 : next step after reboot; set by BIOS */
>> +} QEMU_PACKED;
> is this structure plant to be used for accessing data from within QEMU
> or it is just used for convenience of calculating offsets/sizes for AML?
>
>

For convenience (and it can be useful for debugging).

>> +
>>  #endif /* HW_ACPI_TPM_H */
>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>> index f6d447f03a..95be4f0710 100644
>> --- a/hw/i386/acpi-build.c
>> +++ b/hw/i386/acpi-build.c
>> @@ -43,6 +43,7 @@
>>  #include "hw/acpi/memory_hotplug.h"
>>  #include "sysemu/tpm.h"
>>  #include "hw/acpi/tpm.h"
>> +#include "hw/tpm/tpm_ppi.h"
>>  #include "hw/acpi/vmgenid.h"
>>  #include "sysemu/tpm_backend.h"
>>  #include "hw/timer/mc146818rtc_regs.h"
>> @@ -1789,6 +1790,292 @@ static Aml *build_q35_osc_method(void)
>>      return method;
>>  }
>>
>> +static void
>> +build_tpm_ppi(Aml *dev)
>> +{
>> +    Aml *method, *name, *field, *ifctx, *ifctx2, *ifctx3, *pak;
>> +    struct tpm_ppi *tpm_ppi = NULL;
>> +    int i;
> plain AML variables throughout the function make code rather unreadable
> (well, like any other AML code would be).
> Pls take a look at how build_legacy_cpu_hotplug_aml() uses intermediate
> more or less sanely named variables to make it more understandable.
> that also should allow to reduce LOC this function takes.

Sorry, I don't understand what I should take from
build_legacy_cpu_hotplug_aml() approach. Could you describe a little
bit?


>
>> +    /*
>> +     * TPP1 is for the flags that indicate which PPI operations
>> +     * are supported by the firmware. The firmware is expected to
>> +     * write these flags.
>> +     */
>> +    aml_append(dev,
>> +               aml_operation_region("TPP1", AML_SYSTEM_MEMORY,
>> +                                    aml_int(TPM_PPI_ADDR_BASE),
>> +                                    sizeof(tpm_ppi->func)));
>> +    field = aml_field("TPP1", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
>> +    for (i = 0; i < sizeof(tpm_ppi->func); i++) {
>> +        char *tmp = g_strdup_printf("FN%02X", i);
>> +        aml_append(field, aml_named_field(tmp, BITS_PER_BYTE));
>> +        g_free(tmp);
>> +    }
>> +    aml_append(dev, field);
>> +
>> +    /*
>> +     * TPP2 is for the registers that ACPI code used to pass
>> +     * the PPI code and parameter (PPRQ, PPRM) to the firmware.
>> +     */
>> +    aml_append(dev,
>> +               aml_operation_region("TPP2", AML_SYSTEM_MEMORY,
>> +                                    aml_int(TPM_PPI_ADDR_BASE +
>> +                                            offsetof(struct tpm_ppi, ppin)),
>> +                                    sizeof(struct tpm_ppi) -
>> +                                        sizeof(tpm_ppi->func)));
>> +    field = aml_field("TPP2", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
>> +    aml_append(field, aml_named_field("PPIN",
>> +               sizeof(uint8_t) * BITS_PER_BYTE));
> here you already don't use tpm_ppi for sizing, so it creates a confusing mix
> of both approaches.

True, sizeof_field() will become handy here. I can leave a TODO?


>
> From ACPI pov I'd prefer PPI table documented somewhere in spec docs
> (similar docs/specs/acpi_mem_hotplug.txt) and would look like in
> other use-cases:
>
>    aml_append(field, aml_named_field("PPIN", 8)
>
> and drop "struct tpm_ppi" altogether replacing places it was used by
> explicit constants.

I have a slight preference for the tpm_ppi structure. But ok with
replacing it with constant. Stefan, do you agree?

>> +    aml_append(field, aml_named_field("PPIP",
>> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> +    aml_append(field, aml_named_field("PPRP",
>> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> +    aml_append(field, aml_named_field("PPRQ",
>> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> +    aml_append(field, aml_named_field("PPRM",
>> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> +    aml_append(field, aml_named_field("LPPR",
>> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> +    aml_append(dev, field);
>> +
>> +    method = aml_method("TPFN", 1, AML_SERIALIZED);
> not quite sure how this method (supposed to ) work(s),
> it could use nice comment explaining mechanics.
>

Windows doesn't like DerefOf (FUNC [N]), it returned wrong values. It
took me a while to figure this out. My laptop TPM ACPI table uses the
same trick, so I assume this is a Windows acpi bug/limitation. Instead
we use a function that returns the corresponding field.

So we declare each field / array entry:
            OperationRegion (TPP1, SystemMemory, 0xFED45000, 0x0100)
            Field (TPP1, AnyAcc, NoLock, Preserve)
            {
                FN00,   8,
                FN01,   8,....

And the method to access it:

           Method (TPFN, 1, Serialized)
            {
                If ((Zero == Arg0))
                {
                    Return (FN00) /* \_SB_.TPM_.FN00 */
                }
.....



>> +    {
>> +        for (i = 0; i < sizeof(tpm_ppi->func); i++) {
>> +            ifctx = aml_if(aml_equal(aml_int(i), aml_arg(0)));
>> +            {
>> +                aml_append(ifctx, aml_return(aml_name("FN%02X", i)));
>> +            }
>> +            aml_append(method, ifctx);
>> +        }
>> +        aml_append(method, aml_return(aml_int(0)));
>> +    }
>> +    aml_append(dev, method);
>> +
>> +    pak = aml_package(2);
>> +    aml_append(pak, aml_int(0));
>> +    aml_append(pak, aml_int(0));
>> +    name = aml_name_decl("TPM2", pak);
>> +    aml_append(dev, name);
>> +
>> +    pak = aml_package(3);
>> +    aml_append(pak, aml_int(0));
>> +    aml_append(pak, aml_int(0));
>> +    aml_append(pak, aml_int(0));
>> +    name = aml_name_decl("TPM3", pak);
>> +    aml_append(dev, name);
>> +
>> +    method = aml_method("_DSM", 4, AML_SERIALIZED);
>> +    {
>> +        uint8_t zerobyte[1] = { 0 };
>> +
>> +        ifctx = aml_if(
>> +            aml_equal(aml_arg(0),
>> +                      aml_touuid("3DDDFAA6-361B-4EB4-A424-8D10089D1653")));
> a comment pointing to a specific part/version of spec that documents this _DSM
> for every uuid/function used here would help to review it.

ok, fixing that.

The spec PDF is fairly easy to read imho:

https://trustedcomputinggroup.org/wp-content/uploads/Physical-Presence-Interface_1-30_0-52.pdf
>
>> +        {
>> +            aml_append(ifctx,
>> +                       aml_store(aml_to_integer(aml_arg(2)), aml_local(0)));
>> +
>> +            /* standard DSM query function */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(0)));
>> +            {
>> +                uint8_t byte_list[2] = { 0xff, 0x01 };
>> +                aml_append(ifctx2, aml_return(aml_buffer(2, byte_list)));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* interface version: 1.3 */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(1)));
>> +            {
>> +                aml_append(ifctx2, aml_return(aml_string("1.3")));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* submit TPM operation */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(2)));
>> +            {
>> +                /* get opcode */
>> +                aml_append(ifctx2,
>> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
>> +                                                           aml_int(0))),
>> +                                     aml_local(0)));
>> +                /* get opcode flags */
>> +                aml_append(ifctx2,
>> +                           aml_store(aml_call1("TPFN", aml_local(0)),
>> +                                     aml_local(1)));
>> +                ifctx3 = aml_if(
>> +                    aml_equal(
>> +                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
>> +                        aml_int(TPM_PPI_FUNC_NOT_IMPLEMENTED)));
>> +                {
>> +                    /* 1: not implemented */
>> +                    aml_append(ifctx3, aml_return(aml_int(1)));
>> +                }
>> +                aml_append(ifctx2, ifctx3);
>> +                aml_append(ifctx2, aml_store(aml_local(0), aml_name("PPRQ")));
>> +                aml_append(ifctx2, aml_store(aml_int(0), aml_name("PPRM")));
>> +                /* 0: success */
>> +                aml_append(ifctx2, aml_return(aml_int(0)));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* get pending TPM operation */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(3)));
>> +            {
>> +                /* revision to integer */
>> +                aml_append(ifctx2,
>> +                           aml_store(
>> +                               aml_to_integer(aml_arg(1)),
>> +                               aml_local(1)));
>> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(1)));
>> +                {
>> +                    aml_append(ifctx3,
>> +                               aml_store(
>> +                                   aml_name("PPRQ"),
>> +                                   aml_index(aml_name("TPM2"), aml_int(1))));
>> +                    aml_append(ifctx3, aml_return(aml_name("TPM2")));
>> +                }
>> +                aml_append(ifctx2, ifctx3);
>> +
>> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(2)));
>> +                {
>> +                    aml_append(ifctx3,
>> +                               aml_store(
>> +                                   aml_name("PPRQ"),
>> +                                   aml_index(aml_name("TPM3"), aml_int(1))));
>> +                    aml_append(ifctx3,
>> +                               aml_store(
>> +                                   aml_name("PPRM"),
>> +                                   aml_index(aml_name("TPM3"), aml_int(2))));
>> +                    aml_append(ifctx3, aml_return(aml_name("TPM3")));
>> +                }
>> +                aml_append(ifctx2, ifctx3);
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* get platform-specific action to transition to pre-OS env. */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(4)));
>> +            {
>> +                /* reboot */
>> +                aml_append(ifctx2, aml_return(aml_int(2)));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* get TPM operation response */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(5)));
>> +            {
>> +                aml_append(ifctx2,
>> +                           aml_store(
>> +                               aml_name("LPPR"),
>> +                               aml_index(aml_name("TPM3"), aml_int(1))));
>> +                aml_append(ifctx2,
>> +                           aml_store(
>> +                               aml_name("PPRP"),
>> +                               aml_index(aml_name("TPM3"), aml_int(2))));
>> +                aml_append(ifctx2, aml_return(aml_name("TPM3")));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* submit preferred user language */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(6)));
>> +            {
>> +                /* 3 = not implemented */
>> +                aml_append(ifctx2, aml_return(aml_int(3)));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* submit TPM operation v2 */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(7)));
>> +            {
>> +                /* get opcode */
>> +                aml_append(ifctx2,
>> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
>> +                                                           aml_int(0))),
>> +                                     aml_local(0)));
>> +                /* get opcode flags */
>> +                aml_append(ifctx2,
>> +                           aml_store(aml_call1("TPFN", aml_local(0)),
>> +                                     aml_local(1)));
>> +                ifctx3 = aml_if(
>> +                    aml_equal(
>> +                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
>> +                        aml_int(TPM_PPI_FUNC_NOT_IMPLEMENTED)));
>> +                {
>> +                    /* 1: not implemented */
>> +                    aml_append(ifctx3, aml_return(aml_int(1)));
>> +                }
>> +                aml_append(ifctx2, ifctx3);
>> +
>> +                ifctx3 = aml_if(
>> +                    aml_equal(
>> +                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
>> +                        aml_int(TPM_PPI_FUNC_BLOCKED)));
>> +                {
>> +                    /* 3: blocked by firmware */
>> +                    aml_append(ifctx3, aml_return(aml_int(3)));
>> +                }
>> +                aml_append(ifctx2, ifctx3);
>> +
>> +                /* revision to integer */
>> +                aml_append(ifctx2,
>> +                           aml_store(
>> +                               aml_to_integer(aml_arg(1)),
>> +                               aml_local(1)));
>> +
>> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(1)));
>> +                {
>> +                    /* revision 1 */
>> +                    aml_append(ifctx3, aml_store(aml_local(0),
>> +                                                 aml_name("PPRQ")));
>> +                    aml_append(ifctx3, aml_store(aml_int(0),
>> +                                                 aml_name("PPRM")));
>> +                }
>> +                aml_append(ifctx2, ifctx3);
>> +
>> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(2)));
>> +                {
>> +                    /* revision 2 */
>> +                    aml_append(ifctx3,
>> +                               aml_store(aml_local(0), aml_name("PPRQ")));
>> +                    aml_append(ifctx3,
>> +                               aml_store(
>> +                                   aml_derefof(aml_index(aml_arg(3),
>> +                                                         aml_int(1))),
>> +                                   aml_name("PPRM")));
>> +                }
>> +                aml_append(ifctx2, ifctx3);
>> +                /* 0: success */
>> +                aml_append(ifctx2, aml_return(aml_int(0)));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            /* get user confirmation status for operation */
>> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(8)));
>> +            {
>> +                /* get opcode */
>> +                aml_append(ifctx2,
>> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
>> +                                                           aml_int(0))),
>> +                                     aml_local(0)));
>> +                /* get opcode flags */
>> +                aml_append(ifctx2,
>> +                           aml_store(aml_call1("TPFN", aml_local(0)),
>> +                                     aml_local(1)));
>> +                /* return confirmation status code */
>> +                aml_append(ifctx2,
>> +                           aml_return(
>> +                               aml_and(aml_local(1),
>> +                                       aml_int(TPM_PPI_FUNC_MASK), NULL)));
>> +            }
>> +            aml_append(ifctx, ifctx2);
>> +
>> +            aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
>> +        }
>> +        aml_append(method, ifctx);
>> +    }
>> +    aml_append(dev, method);
>> +}
>> +
>>  static void
>>  build_dsdt(GArray *table_data, BIOSLinker *linker,
>>             AcpiPmInfo *pm, AcpiMiscInfo *misc,
>> @@ -2153,6 +2440,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
>>                   */
>>                  /* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
>>                  aml_append(dev, aml_name_decl("_CRS", crs));
>> +
>> +                build_tpm_ppi(dev);
>> +
>>                  aml_append(scope, dev);
>>              }
>>
>> @@ -2172,6 +2462,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
>>          aml_append(method, aml_return(aml_int(0x0f)));
>>          aml_append(dev, method);
>>
>> +        build_tpm_ppi(dev);
>> +
>>          aml_append(sb_scope, dev);
>>      }
>>
>> @@ -2918,7 +3210,7 @@ void acpi_setup(void)
>>          tpm_config = (FWCfgTPMConfig) {
>>              .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE),
>>              .tpm_version = cpu_to_le32(tpm_get_version(tpm_find())),
>> -            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_NONE)
> what was the point of introducing TPM_PPI_VERSION_NONE if it would not be used?
> maybe patch ordering is problem? what if we put fwcfg patch after this one?

edk2 already knows that NONE (0) is no PPI. So we at least have to
keep the same indexing.

I don't see much point in reordering. If you look at v4, you may want
to squash things together too, but that makes reviewing more
complicated. As the long as the split is natural, and no regression
are introduced, I would rather keep it the way it is.

>
>> +            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_1_30)
>>          };
>>          fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config",
>>                          &tpm_config, sizeof tpm_config);
>
> hopefully patch would be more review-able with comments and nicely named
> variables, so I could actually review it functionality wise without reading
> whole TPM spec(s)

Let see what I can do.

Thanks!


-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-06-21 13:21     ` Marc-André Lureau
@ 2018-06-21 13:22       ` Marc-André Lureau
  2018-06-21 14:13         ` Marc-André Lureau
  2018-06-21 13:48       ` Stefan Berger
  2018-06-21 14:23       ` Igor Mammedov
  2 siblings, 1 reply; 40+ messages in thread
From: Marc-André Lureau @ 2018-06-21 13:22 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Eduardo Habkost, Stefan Berger, Michael S. Tsirkin, QEMU,
	Paolo Bonzini, Richard Henderson

Hi

On Thu, Jun 21, 2018 at 3:21 PM, Marc-André Lureau
<marcandre.lureau@gmail.com> wrote:

>>> +    method = aml_method("TPFN", 1, AML_SERIALIZED);
>> not quite sure how this method (supposed to ) work(s),
>> it could use nice comment explaining mechanics.
>>
>
> Windows doesn't like DerefOf (FUNC [N]), it returned wrong values. It
> took me a while to figure this out. My laptop TPM ACPI table uses the
> same trick, so I assume this is a Windows acpi bug/limitation. Instead
> we use a function that returns the corresponding field.

Sorry, I am wrong, my laptop doesn't use such table. I don't know
where I saw someone using the same trick though..


-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 4/4] tpm: add a fake ACPI memory clear interface
  2018-06-21 13:02   ` Igor Mammedov
@ 2018-06-21 13:24     ` Marc-André Lureau
  2018-06-21 13:59       ` Stefan Berger
  2018-06-21 14:33       ` Igor Mammedov
  0 siblings, 2 replies; 40+ messages in thread
From: Marc-André Lureau @ 2018-06-21 13:24 UTC (permalink / raw)
  To: Igor Mammedov, Laszlo Ersek
  Cc: Eduardo Habkost, Michael S. Tsirkin, Stefan Berger, QEMU,
	Paolo Bonzini, Richard Henderson

Hi

On Thu, Jun 21, 2018 at 3:02 PM, Igor Mammedov <imammedo@redhat.com> wrote:
> On Tue, 15 May 2018 14:14:33 +0200
> Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
>
>> This allows to pass the last failing test from the Windows HLK TPM 2.0
>> TCG PPI 1.3 tests.
>>
>> The interface is described in the "TCG Platform Reset Attack
>> Mitigation Specification", chapter 6 "ACPI _DSM Function". Whether or
>> not we should have a real implementation remains an open question to me.
> might it cause security issues?

Good question. If the guest assumes success of this operation perhaps.
I'll check the spec.

> What are implications of faking it and how hard it's to implement thing
> per spec?

Laszlo answerd that in "[Qemu-devel] investigating TPM for
OVMF-on-QEMU"  2f2b) TCG Memory Clear Interface

>
>
>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> ---
>>  hw/i386/acpi-build.c | 9 +++++++++
>>  1 file changed, 9 insertions(+)
>>
>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>> index 95be4f0710..392a1e50bd 100644
>> --- a/hw/i386/acpi-build.c
>> +++ b/hw/i386/acpi-build.c
>> @@ -2072,6 +2072,15 @@ build_tpm_ppi(Aml *dev)
>>              aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
>>          }
>>          aml_append(method, ifctx);
>> +
>> +       /* dummy MOR Memory Clear for the sake of WLK PPI test */
>> +        ifctx = aml_if(
>> +            aml_equal(aml_arg(0),
>> +                      aml_touuid("376054ED-CC13-4675-901C-4756D7F2D45D")));
>> +        {
>> +            aml_append(ifctx, aml_return(aml_int(0)));
>> +        }
>> +        aml_append(method, ifctx);
>>      }
>>      aml_append(dev, method);
>>  }
>
>



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-06-21 13:21     ` Marc-André Lureau
  2018-06-21 13:22       ` Marc-André Lureau
@ 2018-06-21 13:48       ` Stefan Berger
  2018-06-21 14:23       ` Igor Mammedov
  2 siblings, 0 replies; 40+ messages in thread
From: Stefan Berger @ 2018-06-21 13:48 UTC (permalink / raw)
  To: Marc-André Lureau, Igor Mammedov
  Cc: Eduardo Habkost, Michael S. Tsirkin, QEMU, Paolo Bonzini,
	Richard Henderson

On 06/21/2018 09:21 AM, Marc-André Lureau wrote:
> Hi
>
> On Thu, Jun 21, 2018 at 2:54 PM, Igor Mammedov <imammedo@redhat.com> wrote:
>> On Tue, 15 May 2018 14:14:32 +0200
>> Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
>>
>>> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>
>>> The TPM Physical Presence interface consists of an ACPI part, a shared
>>> memory part, and code in the firmware. Users can send messages to the
>>> firmware by writing a code into the shared memory through invoking the
>>> ACPI code. When a reboot happens, the firmware looks for the code and
>>> acts on it by sending sequences of commands to the TPM.
>>>
>>> This patch adds the ACPI code. It is similar to the one in EDK2 but doesn't
>>> assume that SMIs are necessary to use. It uses a similar datastructure for
>>> the shared memory as EDK2 does so that EDK2 and SeaBIOS could both make use
>>> of it. I extended the shared memory data structure with an array of 256
>>> bytes, one for each code that could be implemented. The array contains
>>> flags describing the individual codes. This decouples the ACPI implementation
>>> from the firmware implementation.
>>>
>>> The underlying TCG specification is accessible from the following page.
>>>
>>> https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/
>>>
>>> This patch implements version 1.30.
>>>
>>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>
>>> ---
>>>
>>> v4 (Marc-André):
>>>   - replace 'DerefOf (FUNC [N])' with a function, to fix Windows ACPI
>>>      handling.
>>>   - replace 'return Package (..) {} ' with scoped variables, to fix
>>>     Windows ACPI handling.
>>>
>>> v3:
>>>   - add support for PPI to CRB
>>>   - split up OperationRegion TPPI into two parts, one containing
>>>     the registers (TPP1) and the other one the flags (TPP2); switched
>>>     the order of the flags versus registers in the code
>>>   - adapted ACPI code to small changes to the array of flags where
>>>     previous flag 0 was removed and now shifting right wasn't always
>>>     necessary anymore
>>>
>>> v2:
>>>   - get rid of FAIL variable; function 5 was using it and always
>>>     returns 0; the value is related to the ACPI function call not
>>>     a possible failure of the TPM function call.
>>>   - extend shared memory data structure with per-opcode entries
>>>     holding flags and use those flags to determine what to return
>>>     to caller
>>>   - implement interface version 1.3
>>> ---
>>>
>>>
>>  From ACPI pov I'd prefer PPI table documented somewhere in spec docs
>> (similar docs/specs/acpi_mem_hotplug.txt) and would look like in
>> other use-cases:
>>
>>     aml_append(field, aml_named_field("PPIN", 8)
>>
>> and drop "struct tpm_ppi" altogether replacing places it was used by
>> explicit constants.
> I have a slight preference for the tpm_ppi structure. But ok with
> replacing it with constant. Stefan, do you agree?

The PPI structure will appear in the firmware code and if it is the same 
and is correctly used we know that both are in sync. So I wouldn't get 
rid of it based on just that. If we have to changed all 
sizeof(uint32_t/uint8_t) to correctly use that shared structure, I'd 
prefer that.

     Stefan

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 2/4] acpi: add fw_cfg file for TPM and PPI virtual memory device
  2018-06-21 10:10     ` Marc-André Lureau
@ 2018-06-21 13:55       ` Igor Mammedov
  2018-06-22  0:16       ` Laszlo Ersek
  2018-06-25 15:20       ` Laszlo Ersek
  2 siblings, 0 replies; 40+ messages in thread
From: Igor Mammedov @ 2018-06-21 13:55 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Laszlo Ersek, Eduardo Habkost, Michael S. Tsirkin, Stefan Berger,
	QEMU, Paolo Bonzini, Richard Henderson

On Thu, 21 Jun 2018 12:10:32 +0200
Marc-André Lureau <marcandre.lureau@gmail.com> wrote:

> Hi
> 
> On Thu, Jun 21, 2018 at 12:00 PM, Igor Mammedov <imammedo@redhat.com> wrote:
> > On Tue, 15 May 2018 14:14:31 +0200
> > Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
> >  
> >> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
> >>
> >> To avoid having to hard code the base address of the PPI virtual
> >> memory device we introduce a fw_cfg file etc/tpm/config that holds the
> >> base address of the PPI device, the version of the PPI interface and
> >> the version of the attached TPM.  
> > is it related to TPM_PPI_ADDR_BASE added in previous patch?
> >  
> >>
> >> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> >> [ Marc-André: renamed to etc/tpm/config, made it static, document it ]
> >> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> >> ---
> >>  include/hw/acpi/tpm.h |  3 +++
> >>  hw/i386/acpi-build.c  | 17 +++++++++++++++++
> >>  docs/specs/tpm.txt    | 20 ++++++++++++++++++++
> >>  3 files changed, 40 insertions(+)
> >>
> >> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
> >> index c082df7d1d..f79d68a77a 100644
> >> --- a/include/hw/acpi/tpm.h
> >> +++ b/include/hw/acpi/tpm.h
> >> @@ -193,4 +193,7 @@ REG32(CRB_DATA_BUFFER, 0x80)
> >>  #define TPM_PPI_ADDR_SIZE           0x400
> >>  #define TPM_PPI_ADDR_BASE           0xFED45000
> >>
> >> +#define TPM_PPI_VERSION_NONE        0
> >> +#define TPM_PPI_VERSION_1_30        1
> >> +
> >>  #endif /* HW_ACPI_TPM_H */
> >> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> >> index 9bc6d97ea1..f6d447f03a 100644
> >> --- a/hw/i386/acpi-build.c
> >> +++ b/hw/i386/acpi-build.c
> >> @@ -119,6 +119,12 @@ typedef struct AcpiBuildPciBusHotplugState {
> >>      bool pcihp_bridge_en;
> >>  } AcpiBuildPciBusHotplugState;
> >>
> >> +typedef struct FWCfgTPMConfig {
> >> +    uint32_t tpmppi_address;
> >> +    uint8_t tpm_version;
> >> +    uint8_t tpmppi_version;
> >> +} QEMU_PACKED FWCfgTPMConfig;
> >> +
> >>  static void init_common_fadt_data(Object *o, AcpiFadtData *data)
> >>  {
> >>      uint32_t io = object_property_get_uint(o, ACPI_PM_PROP_PM_IO_BASE, NULL);
> >> @@ -2873,6 +2879,7 @@ void acpi_setup(void)
> >>      AcpiBuildTables tables;
> >>      AcpiBuildState *build_state;
> >>      Object *vmgenid_dev;
> >> +    static FWCfgTPMConfig tpm_config;
> >>
> >>      if (!pcms->fw_cfg) {
> >>          ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
> >> @@ -2907,6 +2914,16 @@ void acpi_setup(void)
> >>      fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
> >>                      tables.tcpalog->data, acpi_data_len(tables.tcpalog));
> >>
> >> +    if (tpm_find()) {
> >> +        tpm_config = (FWCfgTPMConfig) {
> >> +            .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE),
> >> +            .tpm_version = cpu_to_le32(tpm_get_version(tpm_find())),
> >> +            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_NONE)
> >> +        };
> >> +        fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config",
> >> +                        &tpm_config, sizeof tpm_config);
> >> +    }  
> > why it's in ACPI part of the code, shouldn't it be a part of device,
> > could TPM be used without ACPI at all (-noacpi CLI option)?
> >
> > Wouldn't adding fwcfg entry unconditionally break migration?  
> 
> Because of unstable entry IDs? that could be problematic. (especially
> during boot time) What do you think Laszlo?
> 
> I guess we could have a "ppi" device property, that would imply having
> the etc/tpm/config fw_cfg entry. We would enable it by default in
> newer machine types (3.0?)
yep, something like this.
usual practice is to enable it by default and disable it for old
machine types using hw compat props (include/hw/compat.h)

> 
> >  
> >> +
> >>      vmgenid_dev = find_vmgenid_dev();
> >>      if (vmgenid_dev) {
> >>          vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), pcms->fw_cfg,
> >> diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt
> >> index c230c4c93e..2ddb768084 100644
> >> --- a/docs/specs/tpm.txt
> >> +++ b/docs/specs/tpm.txt
> >> @@ -20,6 +20,26 @@ QEMU files related to TPM TIS interface:
> >>   - hw/tpm/tpm_tis.h
> >>
> >>
> >> += fw_cfg interface =
> >> +
> >> +The bios/firmware may use the "etc/tpm/config" fw_cfg entry for
> >> +configuring the guest appropriately.
> >> +
> >> +The entry of 6 bytes has the following content, in little-endian:
> >> +
> >> +    #define TPM_VERSION_UNSPEC          0
> >> +    #define TPM_VERSION_1_2             1
> >> +    #define TPM_VERSION_2_0             2
> >> +
> >> +    #define TPM_PPI_VERSION_NONE        0
> >> +    #define TPM_PPI_VERSION_1_30        1
> >> +
> >> +    struct FWCfgTPMConfig {
> >> +        uint32_t tpmppi_address;         /* PPI memory location */
> >> +        uint8_t tpm_version;             /* TPM version */
> >> +        uint8_t tpmppi_version;          /* PPI version */
> >> +    };
> >> +
> >>  = ACPI Interface =
> >>
> >>  The TPM device is defined with ACPI ID "PNP0C31". QEMU builds a SSDT and passes  
> >
> >  
> 
> 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 1/4] tpm: implement virtual memory device for TPM PPI
  2018-06-21 10:51     ` Marc-André Lureau
@ 2018-06-21 13:59       ` Igor Mammedov
  0 siblings, 0 replies; 40+ messages in thread
From: Igor Mammedov @ 2018-06-21 13:59 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Eduardo Habkost, Stefan Berger, Michael S. Tsirkin, QEMU,
	Paolo Bonzini, Richard Henderson

On Thu, 21 Jun 2018 12:51:34 +0200
Marc-André Lureau <marcandre.lureau@gmail.com> wrote:

> Hi
> 
> On Thu, Jun 21, 2018 at 11:49 AM, Igor Mammedov <imammedo@redhat.com> wrote:
> > On Tue, 15 May 2018 14:14:30 +0200
> > Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
> >  
> >> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
> >>
> >> Implement a virtual memory device for the TPM Physical Presence interface.
> >> The memory is located at 0xfffef000 and used by ACPI to send messages to the
> >> firmware (BIOS) and by the firmware to provide parameters for each one of
> >> the supported codes.
> >>
> >> This device should be used by all TPM interfaces on x86 and can be added
> >> by calling tpm_ppi_init_io().
> >>
> >> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> >> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> >>
> >> ---
> >>
> >> v3 (Marc-André):
> >>  - merge CRB support
> >>  - use trace events instead of DEBUG printf
> >>  - headers inclusion simplification
> >>
> >> v2:
> >>  - moved to byte access since an infrequently used device;
> >>    this simplifies code
> >>  - increase size of device to 0x400
> >>  - move device to 0xfffef000 since SeaBIOS has some code at 0xffff0000:
> >>    'On the emulators, the bios at 0xf0000 is also at 0xffff0000'
> >> ---
> >>  hw/tpm/tpm_ppi.h      | 26 ++++++++++++++++++++
> >>  include/hw/acpi/tpm.h |  6 +++++
> >>  hw/tpm/tpm_crb.c      |  5 ++++
> >>  hw/tpm/tpm_ppi.c      | 56 +++++++++++++++++++++++++++++++++++++++++++
> >>  hw/tpm/tpm_tis.c      |  5 ++++
> >>  hw/tpm/Makefile.objs  |  2 +-
> >>  hw/tpm/trace-events   |  4 ++++
> >>  7 files changed, 103 insertions(+), 1 deletion(-)
> >>  create mode 100644 hw/tpm/tpm_ppi.h
> >>  create mode 100644 hw/tpm/tpm_ppi.c
> >>
> >> diff --git a/hw/tpm/tpm_ppi.h b/hw/tpm/tpm_ppi.h
> >> new file mode 100644
> >> index 0000000000..17030bd989
> >> --- /dev/null
> >> +++ b/hw/tpm/tpm_ppi.h
> >> @@ -0,0 +1,26 @@
> >> +/*
> >> + * TPM Physical Presence Interface
> >> + *
> >> + * Copyright (C) 2018 IBM Corporation
> >> + *
> >> + * Authors:
> >> + *  Stefan Berger    <stefanb@us.ibm.com>
> >> + *
> >> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> >> + * See the COPYING file in the top-level directory.
> >> + */
> >> +#ifndef TPM_TPM_PPI_H
> >> +#define TPM_TPM_PPI_H
> >> +
> >> +#include "hw/acpi/tpm.h"
> >> +#include "exec/address-spaces.h"
> >> +
> >> +typedef struct TPMPPI {
> >> +    MemoryRegion mmio;
> >> +
> >> +    uint8_t ram[TPM_PPI_ADDR_SIZE];
> >> +} TPMPPI;
> >> +
> >> +void tpm_ppi_init_io(TPMPPI *tpmppi, struct MemoryRegion *m, Object *obj);
> >> +
> >> +#endif /* TPM_TPM_PPI_H */
> >> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
> >> index 46ac4dc581..c082df7d1d 100644
> >> --- a/include/hw/acpi/tpm.h
> >> +++ b/include/hw/acpi/tpm.h
> >> @@ -187,4 +187,10 @@ REG32(CRB_DATA_BUFFER, 0x80)
> >>  #define TPM2_START_METHOD_MMIO      6
> >>  #define TPM2_START_METHOD_CRB       7
> >>
> >> +/*
> >> + * Physical Presence Interface
> >> + */
> >> +#define TPM_PPI_ADDR_SIZE           0x400
> >> +#define TPM_PPI_ADDR_BASE           0xFED45000
> >> +
> >>  #endif /* HW_ACPI_TPM_H */
> >> diff --git a/hw/tpm/tpm_crb.c b/hw/tpm/tpm_crb.c
> >> index a92dd50437..4f585564d9 100644
> >> --- a/hw/tpm/tpm_crb.c
> >> +++ b/hw/tpm/tpm_crb.c
> >> @@ -29,6 +29,7 @@
> >>  #include "sysemu/reset.h"
> >>  #include "tpm_int.h"
> >>  #include "tpm_util.h"
> >> +#include "tpm_ppi.h"
> >>  #include "trace.h"
> >>
> >>  typedef struct CRBState {
> >> @@ -41,6 +42,8 @@ typedef struct CRBState {
> >>      MemoryRegion cmdmem;
> >>
> >>      size_t be_buffer_size;
> >> +
> >> +    TPMPPI ppi;
> >>  } CRBState;
> >>
> >>  #define CRB(obj) OBJECT_CHECK(CRBState, (obj), TYPE_TPM_CRB)
> >> @@ -291,6 +294,8 @@ static void tpm_crb_realize(DeviceState *dev, Error **errp)
> >>      memory_region_add_subregion(get_system_memory(),
> >>          TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem);
> >>
> >> +    tpm_ppi_init_io(&s->ppi, get_system_memory(), OBJECT(s));
> >> +
> >>      qemu_register_reset(tpm_crb_reset, dev);
> >>  }
> >>
> >> diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c
> >> new file mode 100644
> >> index 0000000000..0019c3e6fc
> >> --- /dev/null
> >> +++ b/hw/tpm/tpm_ppi.c
> >> @@ -0,0 +1,56 @@
> >> +/*
> >> + * tpm_ppi.c - TPM Physical Presence Interface
> >> + *
> >> + * Copyright (C) 2018 IBM Corporation
> >> + *
> >> + * Authors:
> >> + *  Stefan Berger <stefanb@us.ibm.com>
> >> + *
> >> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> >> + * See the COPYING file in the top-level directory.
> >> + *
> >> + */
> >> +
> >> +#include "qemu/osdep.h"
> >> +
> >> +#include "tpm_ppi.h"
> >> +#include "trace.h"
> >> +
> >> +static uint64_t tpm_ppi_mmio_read(void *opaque, hwaddr addr,
> >> +                                  unsigned size)
> >> +{
> >> +    TPMPPI *s = opaque;
> >> +
> >> +    trace_tpm_ppi_mmio_read(addr, size, s->ram[addr]);
> >> +
> >> +    return s->ram[addr];
> >> +}
> >> +
> >> +static void tpm_ppi_mmio_write(void *opaque, hwaddr addr,
> >> +                               uint64_t val, unsigned size)
> >> +{
> >> +    TPMPPI *s = opaque;
> >> +
> >> +    trace_tpm_ppi_mmio_write(addr, size, val);
> >> +
> >> +    s->ram[addr] = val;
> >> +}
> >> +
> >> +static const MemoryRegionOps tpm_ppi_memory_ops = {
> >> +    .read = tpm_ppi_mmio_read,
> >> +    .write = tpm_ppi_mmio_write,
> >> +    .endianness = DEVICE_NATIVE_ENDIAN,
> >> +    .valid = {
> >> +        .min_access_size = 1,
> >> +        .max_access_size = 1,
> >> +    },
> >> +};
> >> +
> >> +void tpm_ppi_init_io(TPMPPI *tpmppi, struct MemoryRegion *m, Object *obj)
> >> +{
> >> +    memory_region_init_io(&tpmppi->mmio, obj, &tpm_ppi_memory_ops,
> >> +                          tpmppi, "tpm-ppi-mmio",
> >> +                          TPM_PPI_ADDR_SIZE);
> >> +
> >> +    memory_region_add_subregion(m, TPM_PPI_ADDR_BASE, &tpmppi->mmio);  
> > I'd push TPM_PPI_ADDR_BASE up to the stack so it would be obvious
> > at tpm_ppi_init_io() call site wrt which region the offset is applied
> >
> > also maybe s/TPM_PPI_ADDR_BASE/TPM_PPI_ADDR_OFFSET/?  
> 
> Hmm, it's a fixed address, and we already use TPM_TIS_ADDR_BASE /
> TPM_CRB_ADDR_BASE.
problem here is that it is no clear if 'm' is address space where
absolute address is fine to use ot some subregion in which case
it should be offset relative to 'm'.

it would get worse/more confusing when called with isa address
space is passed in in wich case I have not a clue where it would end up.

> 
> >  
> >> +}
> >> diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
> >> index 12f5c9a759..9a2fec455a 100644
> >> --- a/hw/tpm/tpm_tis.c
> >> +++ b/hw/tpm/tpm_tis.c
> >> @@ -31,6 +31,7 @@
> >>  #include "sysemu/tpm_backend.h"
> >>  #include "tpm_int.h"
> >>  #include "tpm_util.h"
> >> +#include "tpm_ppi.h"
> >>  #include "trace.h"
> >>
> >>  #define TPM_TIS_NUM_LOCALITIES      5     /* per spec */
> >> @@ -81,6 +82,8 @@ typedef struct TPMState {
> >>      TPMVersion be_tpm_version;
> >>
> >>      size_t be_buffer_size;
> >> +
> >> +    TPMPPI ppi;
> >>  } TPMState;
> >>
> >>  #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
> >> @@ -976,6 +979,8 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
> >>
> >>      memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
> >>                                  TPM_TIS_ADDR_BASE, &s->mmio);
> >> +
> >> +    tpm_ppi_init_io(&s->ppi, isa_address_space(ISA_DEVICE(dev)), OBJECT(s));  
> > what address space it would get here and  at what offset address space is mapped?  
> 
> Agree, that's a bit better, done
> 
> thanks
> 
> >  
> >>  }
> >>
> >>  static void tpm_tis_initfn(Object *obj)
> >> diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
> >> index 1dc9f8bf2c..eedd8b6858 100644
> >> --- a/hw/tpm/Makefile.objs
> >> +++ b/hw/tpm/Makefile.objs
> >> @@ -1,4 +1,4 @@
> >> -common-obj-y += tpm_util.o
> >> +common-obj-y += tpm_util.o tpm_ppi.o
> >>  common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
> >>  common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o
> >>  common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
> >> diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events
> >> index 25bee0cecf..81f9923401 100644
> >> --- a/hw/tpm/trace-events
> >> +++ b/hw/tpm/trace-events
> >> @@ -8,6 +8,10 @@ tpm_crb_mmio_write(uint64_t addr, unsigned size, uint32_t val) "CRB write 0x" TA
> >>  tpm_passthrough_handle_request(void *cmd) "processing command %p"
> >>  tpm_passthrough_reset(void) "reset"
> >>
> >> +# hw/tpm/tpm_ppi.c
> >> +tpm_ppi_mmio_read(uint64_t addr, unsigned size, uint32_t val) "PPI read 0x" TARGET_FMT_plx " len:%u val: 0x%" PRIx32
> >> +tpm_ppi_mmio_write(uint64_t addr, unsigned size, uint32_t val) "PPI write 0x" TARGET_FMT_plx " len:%u val: 0x%" PRIx32
> >> +
> >>  # hw/tpm/tpm_util.c
> >>  tpm_util_get_buffer_size_hdr_len(uint32_t len, size_t expected) "tpm_resp->hdr.len = %u, expected = %zu"
> >>  tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, expected = %zu"  
> >
> >  
> 
> 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 4/4] tpm: add a fake ACPI memory clear interface
  2018-06-21 13:24     ` Marc-André Lureau
@ 2018-06-21 13:59       ` Stefan Berger
  2018-06-21 14:33       ` Igor Mammedov
  1 sibling, 0 replies; 40+ messages in thread
From: Stefan Berger @ 2018-06-21 13:59 UTC (permalink / raw)
  To: Marc-André Lureau, Igor Mammedov, Laszlo Ersek
  Cc: Eduardo Habkost, Michael S. Tsirkin, QEMU, Paolo Bonzini,
	Richard Henderson

On 06/21/2018 09:24 AM, Marc-André Lureau wrote:
> Hi
>
> On Thu, Jun 21, 2018 at 3:02 PM, Igor Mammedov <imammedo@redhat.com> wrote:
>> On Tue, 15 May 2018 14:14:33 +0200
>> Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
>>
>>> This allows to pass the last failing test from the Windows HLK TPM 2.0
>>> TCG PPI 1.3 tests.
>>>
>>> The interface is described in the "TCG Platform Reset Attack
>>> Mitigation Specification", chapter 6 "ACPI _DSM Function". Whether or
>>> not we should have a real implementation remains an open question to me.
>> might it cause security issues?
> Good question. If the guest assumes success of this operation perhaps.
> I'll check the spec.
We could reserve a flag in the PPI interface where the firmware can 
indicate that it supports it. ACPI would read that flag and it hide this 
interface if not supported.

>
>> What are implications of faking it and how hard it's to implement thing
>> per spec?
> Laszlo answerd that in "[Qemu-devel] investigating TPM for
> OVMF-on-QEMU"  2f2b) TCG Memory Clear Interface
>
>>
>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>> ---
>>>   hw/i386/acpi-build.c | 9 +++++++++
>>>   1 file changed, 9 insertions(+)
>>>
>>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>>> index 95be4f0710..392a1e50bd 100644
>>> --- a/hw/i386/acpi-build.c
>>> +++ b/hw/i386/acpi-build.c
>>> @@ -2072,6 +2072,15 @@ build_tpm_ppi(Aml *dev)
>>>               aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
>>>           }
>>>           aml_append(method, ifctx);
>>> +
>>> +       /* dummy MOR Memory Clear for the sake of WLK PPI test */
>>> +        ifctx = aml_if(
>>> +            aml_equal(aml_arg(0),
>>> +                      aml_touuid("376054ED-CC13-4675-901C-4756D7F2D45D")));
>>> +        {
>>> +            aml_append(ifctx, aml_return(aml_int(0)));
>>> +        }
>>> +        aml_append(method, ifctx);
>>>       }
>>>       aml_append(dev, method);
>>>   }
>>
>
>

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-06-21 13:22       ` Marc-André Lureau
@ 2018-06-21 14:13         ` Marc-André Lureau
  2018-06-21 14:27           ` Igor Mammedov
  0 siblings, 1 reply; 40+ messages in thread
From: Marc-André Lureau @ 2018-06-21 14:13 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Eduardo Habkost, Stefan Berger, Michael S. Tsirkin, QEMU,
	Paolo Bonzini, Richard Henderson

Hi

On Thu, Jun 21, 2018 at 3:22 PM, Marc-André Lureau
<marcandre.lureau@gmail.com> wrote:
> Hi
>
> On Thu, Jun 21, 2018 at 3:21 PM, Marc-André Lureau
> <marcandre.lureau@gmail.com> wrote:
>
>>>> +    method = aml_method("TPFN", 1, AML_SERIALIZED);
>>> not quite sure how this method (supposed to ) work(s),
>>> it could use nice comment explaining mechanics.
>>>
>>
>> Windows doesn't like DerefOf (FUNC [N]), it returned wrong values. It
>> took me a while to figure this out. My laptop TPM ACPI table uses the
>> same trick, so I assume this is a Windows acpi bug/limitation. Instead
>> we use a function that returns the corresponding field.
>
> Sorry, I am wrong, my laptop doesn't use such table. I don't know
> where I saw someone using the same trick though..

fwiw, I also asked on OSR list for help but got no answer:
http://www.osronline.com/showThread.CFM?link=288617





-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-06-21 13:21     ` Marc-André Lureau
  2018-06-21 13:22       ` Marc-André Lureau
  2018-06-21 13:48       ` Stefan Berger
@ 2018-06-21 14:23       ` Igor Mammedov
  2018-06-21 17:10         ` Marc-André Lureau
  2 siblings, 1 reply; 40+ messages in thread
From: Igor Mammedov @ 2018-06-21 14:23 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Eduardo Habkost, Stefan Berger, Michael S. Tsirkin, QEMU,
	Paolo Bonzini, Richard Henderson

On Thu, 21 Jun 2018 15:21:02 +0200
Marc-André Lureau <marcandre.lureau@gmail.com> wrote:

> Hi
> 
> On Thu, Jun 21, 2018 at 2:54 PM, Igor Mammedov <imammedo@redhat.com> wrote:
> > On Tue, 15 May 2018 14:14:32 +0200
> > Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
> >  
> >> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
> >>
> >> The TPM Physical Presence interface consists of an ACPI part, a shared
> >> memory part, and code in the firmware. Users can send messages to the
> >> firmware by writing a code into the shared memory through invoking the
> >> ACPI code. When a reboot happens, the firmware looks for the code and
> >> acts on it by sending sequences of commands to the TPM.
> >>
> >> This patch adds the ACPI code. It is similar to the one in EDK2 but doesn't
> >> assume that SMIs are necessary to use. It uses a similar datastructure for
> >> the shared memory as EDK2 does so that EDK2 and SeaBIOS could both make use
> >> of it. I extended the shared memory data structure with an array of 256
> >> bytes, one for each code that could be implemented. The array contains
> >> flags describing the individual codes. This decouples the ACPI implementation
> >> from the firmware implementation.
> >>
> >> The underlying TCG specification is accessible from the following page.
> >>
> >> https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/
> >>
> >> This patch implements version 1.30.
> >>
> >> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> >>
> >> ---
> >>
> >> v4 (Marc-André):
> >>  - replace 'DerefOf (FUNC [N])' with a function, to fix Windows ACPI
> >>     handling.
> >>  - replace 'return Package (..) {} ' with scoped variables, to fix
> >>    Windows ACPI handling.
> >>
> >> v3:
> >>  - add support for PPI to CRB
> >>  - split up OperationRegion TPPI into two parts, one containing
> >>    the registers (TPP1) and the other one the flags (TPP2); switched
> >>    the order of the flags versus registers in the code
> >>  - adapted ACPI code to small changes to the array of flags where
> >>    previous flag 0 was removed and now shifting right wasn't always
> >>    necessary anymore
> >>
> >> v2:
> >>  - get rid of FAIL variable; function 5 was using it and always
> >>    returns 0; the value is related to the ACPI function call not
> >>    a possible failure of the TPM function call.
> >>  - extend shared memory data structure with per-opcode entries
> >>    holding flags and use those flags to determine what to return
> >>    to caller
> >>  - implement interface version 1.3
> >> ---
> >>  include/hw/acpi/tpm.h |  21 +++
> >>  hw/i386/acpi-build.c  | 294 +++++++++++++++++++++++++++++++++++++++++-
> >>  2 files changed, 314 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
> >> index f79d68a77a..fc53f08827 100644
> >> --- a/include/hw/acpi/tpm.h
> >> +++ b/include/hw/acpi/tpm.h
> >> @@ -196,4 +196,25 @@ REG32(CRB_DATA_BUFFER, 0x80)
> >>  #define TPM_PPI_VERSION_NONE        0
> >>  #define TPM_PPI_VERSION_1_30        1
> >>
> >> +struct tpm_ppi {
> >> +    uint8_t  func[256];      /* 0x000: per TPM function implementation flags;
> >> +                                       set by BIOS */
> >> +/* whether function is blocked by BIOS settings; bits 0, 1, 2 */
> >> +#define TPM_PPI_FUNC_NOT_IMPLEMENTED     (0 << 0)
> >> +#define TPM_PPI_FUNC_BIOS_ONLY           (1 << 0)
> >> +#define TPM_PPI_FUNC_BLOCKED             (2 << 0)
> >> +#define TPM_PPI_FUNC_ALLOWED_USR_REQ     (3 << 0)
> >> +#define TPM_PPI_FUNC_ALLOWED_USR_NOT_REQ (4 << 0)
> >> +#define TPM_PPI_FUNC_MASK                (7 << 0)
> >> +    uint8_t ppin;            /* 0x100 : set by BIOS */
> >> +    uint32_t ppip;           /* 0x101 : set by ACPI; not used */
> >> +    uint32_t pprp;           /* 0x105 : response from TPM; set by BIOS */
> >> +    uint32_t pprq;           /* 0x109 : opcode; set by ACPI */
> >> +    uint32_t pprm;           /* 0x10d : parameter for opcode; set by ACPI */
> >> +    uint32_t lppr;           /* 0x111 : last opcode; set by BIOS */
> >> +    uint32_t fret;           /* 0x115 : set by ACPI; not used */
> >> +    uint8_t res1[0x40];      /* 0x119 : reserved for future use */
> >> +    uint8_t next_step;       /* 0x159 : next step after reboot; set by BIOS */
> >> +} QEMU_PACKED;  
> > is this structure plant to be used for accessing data from within QEMU
> > or it is just used for convenience of calculating offsets/sizes for AML?
> >
> >  
> 
> For convenience (and it can be useful for debugging).
we are gradually getting rid of usage "struct foo" in ACPI code
(i.e. when I have time to convert old struct based approach
to build_append_int() table based format).
and for new code I usually require ACPI parts be struct less
(if there is no previous struct baggage to back it up).

Hence my request to drop dummy struct and document layout
properly in related spec doc (that's where FW should look for
documentation and not into struct definition somewhere in
the header). So I'd strongly prefer it be done this way.


> >> +
> >>  #endif /* HW_ACPI_TPM_H */
> >> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> >> index f6d447f03a..95be4f0710 100644
> >> --- a/hw/i386/acpi-build.c
> >> +++ b/hw/i386/acpi-build.c
> >> @@ -43,6 +43,7 @@
> >>  #include "hw/acpi/memory_hotplug.h"
> >>  #include "sysemu/tpm.h"
> >>  #include "hw/acpi/tpm.h"
> >> +#include "hw/tpm/tpm_ppi.h"
> >>  #include "hw/acpi/vmgenid.h"
> >>  #include "sysemu/tpm_backend.h"
> >>  #include "hw/timer/mc146818rtc_regs.h"
> >> @@ -1789,6 +1790,292 @@ static Aml *build_q35_osc_method(void)
> >>      return method;
> >>  }
> >>
> >> +static void
> >> +build_tpm_ppi(Aml *dev)
> >> +{
> >> +    Aml *method, *name, *field, *ifctx, *ifctx2, *ifctx3, *pak;
> >> +    struct tpm_ppi *tpm_ppi = NULL;
> >> +    int i;  
> > plain AML variables throughout the function make code rather unreadable
> > (well, like any other AML code would be).
> > Pls take a look at how build_legacy_cpu_hotplug_aml() uses intermediate
> > more or less sanely named variables to make it more understandable.
> > that also should allow to reduce LOC this function takes.  
> 
> Sorry, I don't understand what I should take from
> build_legacy_cpu_hotplug_aml() approach. Could you describe a little
> bit?
I was talking about something like this:

    Aml *apic_id = aml_arg(0);                                                   
    Aml *cpu_on = aml_local(0);
    ...
    Aml *cpus_map = aml_name(CPU_ON_BITMAP);
    ...
    aml_append(method,                                                           
        aml_store(aml_derefof(aml_index(cpus_map, apic_id)), cpu_on))

    ^^^ this part becomes much more read-able for reviewer/maintainer versus pure ASL

        aml_store(aml_derefof(aml_index(aml_name("CPON"), aml_arg(0))), aml_local(0)))

> >  
> >> +    /*
> >> +     * TPP1 is for the CPONflags that indicate which PPI operations
> >> +     * are supported by the firmware. The firmware is expected to
> >> +     * write these flags.
> >> +     */
> >> +    aml_append(dev,
> >> +               aml_operation_region("TPP1", AML_SYSTEM_MEMORY,
> >> +                                    aml_int(TPM_PPI_ADDR_BASE),
> >> +                                    sizeof(tpm_ppi->func)));
> >> +    field = aml_field("TPP1", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
> >> +    for (i = 0; i < sizeof(tpm_ppi->func); i++) {
> >> +        char *tmp = g_strdup_printf("FN%02X", i);
> >> +        aml_append(field, aml_named_field(tmp, BITS_PER_BYTE));
> >> +        g_free(tmp);
> >> +    }
> >> +    aml_append(dev, field);
> >> +
> >> +    /*
> >> +     * TPP2 is for the registers that ACPI code used to pass
> >> +     * the PPI code and parameter (PPRQ, PPRM) to the firmware.
> >> +     */
> >> +    aml_append(dev,
> >> +               aml_operation_region("TPP2", AML_SYSTEM_MEMORY,
> >> +                                    aml_int(TPM_PPI_ADDR_BASE +
> >> +                                            offsetof(struct tpm_ppi, ppin)),
> >> +                                    sizeof(struct tpm_ppi) -
> >> +                                        sizeof(tpm_ppi->func)));
> >> +    field = aml_field("TPP2", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
> >> +    aml_append(field, aml_named_field("PPIN",
> >> +               sizeof(uint8_t) * BITS_PER_BYTE));  
> > here you already don't use tpm_ppi for sizing, so it creates a confusing mix
> > of both approaches.  
> 
> True, sizeof_field() will become handy here. I can leave a TODO?

I'd just use a constant /8/ here like the rest of the code that uses aml_named_field()
(no need to over-complicate or create another precedent to copy from)

Why TODO, changes I suggested for this patch would change it quite heavily
so why merge patch that would be changed by follow up patch almost immediately.
I'd prefer cleaner code being merged unless there are very good reasons
to merge something that should be rewritten afterwards. 

> 
> 
> >
> > From ACPI pov I'd prefer PPI table documented somewhere in spec docs
> > (similar docs/specs/acpi_mem_hotplug.txt) and would look like in
> > other use-cases:
> >
> >    aml_append(field, aml_named_field("PPIN", 8)
> >
> > and drop "struct tpm_ppi" altogether replacing places it was used by
> > explicit constants.  
> 
> I have a slight preference for the tpm_ppi structure. But ok with
> replacing it with constant. Stefan, do you agree?
> 
> >> +    aml_append(field, aml_named_field("PPIP",
> >> +               sizeof(uint32_t) * BITS_PER_BYTE));
> >> +    aml_append(field, aml_named_field("PPRP",
> >> +               sizeof(uint32_t) * BITS_PER_BYTE));
> >> +    aml_append(field, aml_named_field("PPRQ",
> >> +               sizeof(uint32_t) * BITS_PER_BYTE));
> >> +    aml_append(field, aml_named_field("PPRM",
> >> +               sizeof(uint32_t) * BITS_PER_BYTE));
> >> +    aml_append(field, aml_named_field("LPPR",
> >> +               sizeof(uint32_t) * BITS_PER_BYTE));
> >> +    aml_append(dev, field);
> >> +
> >> +    method = aml_method("TPFN", 1, AML_SERIALIZED);  
> > not quite sure how this method (supposed to ) work(s),
> > it could use nice comment explaining mechanics.
> >  
> 
> Windows doesn't like DerefOf (FUNC [N]), it returned wrong values. It
> took me a while to figure this out. My laptop TPM ACPI table uses the
> same trick, so I assume this is a Windows acpi bug/limitation. Instead
> we use a function that returns the corresponding field.
> 
> So we declare each field / array entry:
>             OperationRegion (TPP1, SystemMemory, 0xFED45000, 0x0100)
>             Field (TPP1, AnyAcc, NoLock, Preserve)
>             {
>                 FN00,   8,
>                 FN01,   8,....
> 
> And the method to access it:
> 
>            Method (TPFN, 1, Serialized)
>             {
>                 If ((Zero == Arg0))
>                 {
>                     Return (FN00) /* \_SB_.TPM_.FN00 */
>                 }
> .....
> 
> 
> 
> >> +    {
> >> +        for (i = 0; i < sizeof(tpm_ppi->func); i++) {
> >> +            ifctx = aml_if(aml_equal(aml_int(i), aml_arg(0)));
> >> +            {
> >> +                aml_append(ifctx, aml_return(aml_name("FN%02X", i)));
> >> +            }
> >> +            aml_append(method, ifctx);
> >> +        }
> >> +        aml_append(method, aml_return(aml_int(0)));
> >> +    }
> >> +    aml_append(dev, method);
> >> +
> >> +    pak = aml_package(2);
> >> +    aml_append(pak, aml_int(0));
> >> +    aml_append(pak, aml_int(0));
> >> +    name = aml_name_decl("TPM2", pak);
> >> +    aml_append(dev, name);
> >> +
> >> +    pak = aml_package(3);
> >> +    aml_append(pak, aml_int(0));
> >> +    aml_append(pak, aml_int(0));
> >> +    aml_append(pak, aml_int(0));
> >> +    name = aml_name_decl("TPM3", pak);
> >> +    aml_append(dev, name);
> >> +
> >> +    method = aml_method("_DSM", 4, AML_SERIALIZED);
> >> +    {
> >> +        uint8_t zerobyte[1] = { 0 };
> >> +
> >> +        ifctx = aml_if(
> >> +            aml_equal(aml_arg(0),
> >> +                      aml_touuid("3DDDFAA6-361B-4EB4-A424-8D10089D1653")));  
> > a comment pointing to a specific part/version of spec that documents this _DSM
> > for every uuid/function used here would help to review it.  
> 
> ok, fixing that.
> 
> The spec PDF is fairly easy to read imho:
> 
> https://trustedcomputinggroup.org/wp-content/uploads/Physical-Presence-Interface_1-30_0-52.pdf
> >  
> >> +        {
> >> +            aml_append(ifctx,
> >> +                       aml_store(aml_to_integer(aml_arg(2)), aml_local(0)));
> >> +
> >> +            /* standard DSM query function */
> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(0)));
> >> +            {
> >> +                uint8_t byte_list[2] = { 0xff, 0x01 };
> >> +                aml_append(ifctx2, aml_return(aml_buffer(2, byte_list)));
> >> +            }
> >> +            aml_append(ifctx, ifctx2);
> >> +
> >> +            /* interface version: 1.3 */
> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(1)));
> >> +            {
> >> +                aml_append(ifctx2, aml_return(aml_string("1.3")));
> >> +            }
> >> +            aml_append(ifctx, ifctx2);
> >> +
> >> +            /* submit TPM operation */
> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(2)));
> >> +            {
> >> +                /* get opcode */
> >> +                aml_append(ifctx2,
> >> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
> >> +                                                           aml_int(0))),
> >> +                                     aml_local(0)));
> >> +                /* get opcode flags */
> >> +                aml_append(ifctx2,
> >> +                           aml_store(aml_call1("TPFN", aml_local(0)),
> >> +                                     aml_local(1)));
> >> +                ifctx3 = aml_if(
> >> +                    aml_equal(
> >> +                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
> >> +                        aml_int(TPM_PPI_FUNC_NOT_IMPLEMENTED)));
> >> +                {
> >> +                    /* 1: not implemented */
> >> +                    aml_append(ifctx3, aml_return(aml_int(1)));
> >> +                }
> >> +                aml_append(ifctx2, ifctx3);
> >> +                aml_append(ifctx2, aml_store(aml_local(0), aml_name("PPRQ")));
> >> +                aml_append(ifctx2, aml_store(aml_int(0), aml_name("PPRM")));
> >> +                /* 0: success */
> >> +                aml_append(ifctx2, aml_return(aml_int(0)));
> >> +            }
> >> +            aml_append(ifctx, ifctx2);
> >> +
> >> +            /* get pending TPM operation */
> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(3)));
> >> +            {
> >> +                /* revision to integer */
> >> +                aml_append(ifctx2,
> >> +                           aml_store(
> >> +                               aml_to_integer(aml_arg(1)),
> >> +                               aml_local(1)));
> >> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(1)));
> >> +                {
> >> +                    aml_append(ifctx3,
> >> +                               aml_store(
> >> +                                   aml_name("PPRQ"),
> >> +                                   aml_index(aml_name("TPM2"), aml_int(1))));
> >> +                    aml_append(ifctx3, aml_return(aml_name("TPM2")));
> >> +                }
> >> +                aml_append(ifctx2, ifctx3);
> >> +
> >> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(2)));
> >> +                {
> >> +                    aml_append(ifctx3,
> >> +                               aml_store(
> >> +                                   aml_name("PPRQ"),
> >> +                                   aml_index(aml_name("TPM3"), aml_int(1))));
> >> +                    aml_append(ifctx3,
> >> +                               aml_store(
> >> +                                   aml_name("PPRM"),
> >> +                                   aml_index(aml_name("TPM3"), aml_int(2))));
> >> +                    aml_append(ifctx3, aml_return(aml_name("TPM3")));
> >> +                }
> >> +                aml_append(ifctx2, ifctx3);
> >> +            }
> >> +            aml_append(ifctx, ifctx2);
> >> +
> >> +            /* get platform-specific action to transition to pre-OS env. */
> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(4)));
> >> +            {
> >> +                /* reboot */
> >> +                aml_append(ifctx2, aml_return(aml_int(2)));
> >> +            }
> >> +            aml_append(ifctx, ifctx2);
> >> +
> >> +            /* get TPM operation response */
> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(5)));
> >> +            {
> >> +                aml_append(ifctx2,
> >> +                           aml_store(
> >> +                               aml_name("LPPR"),
> >> +                               aml_index(aml_name("TPM3"), aml_int(1))));
> >> +                aml_append(ifctx2,
> >> +                           aml_store(
> >> +                               aml_name("PPRP"),
> >> +                               aml_index(aml_name("TPM3"), aml_int(2))));
> >> +                aml_append(ifctx2, aml_return(aml_name("TPM3")));
> >> +            }
> >> +            aml_append(ifctx, ifctx2);
> >> +
> >> +            /* submit preferred user language */
> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(6)));
> >> +            {
> >> +                /* 3 = not implemented */
> >> +                aml_append(ifctx2, aml_return(aml_int(3)));
> >> +            }
> >> +            aml_append(ifctx, ifctx2);
> >> +
> >> +            /* submit TPM operation v2 */
> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(7)));
> >> +            {
> >> +                /* get opcode */
> >> +                aml_append(ifctx2,
> >> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
> >> +                                                           aml_int(0))),
> >> +                                     aml_local(0)));
> >> +                /* get opcode flags */
> >> +                aml_append(ifctx2,
> >> +                           aml_store(aml_call1("TPFN", aml_local(0)),
> >> +                                     aml_local(1)));
> >> +                ifctx3 = aml_if(
> >> +                    aml_equal(
> >> +                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
> >> +                        aml_int(TPM_PPI_FUNC_NOT_IMPLEMENTED)));
> >> +                {
> >> +                    /* 1: not implemented */
> >> +                    aml_append(ifctx3, aml_return(aml_int(1)));
> >> +                }
> >> +                aml_append(ifctx2, ifctx3);
> >> +
> >> +                ifctx3 = aml_if(
> >> +                    aml_equal(
> >> +                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
> >> +                        aml_int(TPM_PPI_FUNC_BLOCKED)));
> >> +                {
> >> +                    /* 3: blocked by firmware */
> >> +                    aml_append(ifctx3, aml_return(aml_int(3)));
> >> +                }
> >> +                aml_append(ifctx2, ifctx3);
> >> +
> >> +                /* revision to integer */
> >> +                aml_append(ifctx2,
> >> +                           aml_store(
> >> +                               aml_to_integer(aml_arg(1)),
> >> +                               aml_local(1)));
> >> +
> >> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(1)));
> >> +                {
> >> +                    /* revision 1 */
> >> +                    aml_append(ifctx3, aml_store(aml_local(0),
> >> +                                                 aml_name("PPRQ")));
> >> +                    aml_append(ifctx3, aml_store(aml_int(0),
> >> +                                                 aml_name("PPRM")));
> >> +                }
> >> +                aml_append(ifctx2, ifctx3);
> >> +
> >> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(2)));
> >> +                {
> >> +                    /* revision 2 */
> >> +                    aml_append(ifctx3,
> >> +                               aml_store(aml_local(0), aml_name("PPRQ")));
> >> +                    aml_append(ifctx3,
> >> +                               aml_store(
> >> +                                   aml_derefof(aml_index(aml_arg(3),
> >> +                                                         aml_int(1))),
> >> +                                   aml_name("PPRM")));
> >> +                }
> >> +                aml_append(ifctx2, ifctx3);
> >> +                /* 0: success */
> >> +                aml_append(ifctx2, aml_return(aml_int(0)));
> >> +            }
> >> +            aml_append(ifctx, ifctx2);
> >> +
> >> +            /* get user confirmation status for operation */
> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(8)));
> >> +            {
> >> +                /* get opcode */
> >> +                aml_append(ifctx2,
> >> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
> >> +                                                           aml_int(0))),
> >> +                                     aml_local(0)));
> >> +                /* get opcode flags */
> >> +                aml_append(ifctx2,
> >> +                           aml_store(aml_call1("TPFN", aml_local(0)),
> >> +                                     aml_local(1)));
> >> +                /* return confirmation status code */
> >> +                aml_append(ifctx2,
> >> +                           aml_return(
> >> +                               aml_and(aml_local(1),
> >> +                                       aml_int(TPM_PPI_FUNC_MASK), NULL)));
> >> +            }
> >> +            aml_append(ifctx, ifctx2);
> >> +
> >> +            aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
> >> +        }
> >> +        aml_append(method, ifctx);
> >> +    }
> >> +    aml_append(dev, method);
> >> +}
> >> +
> >>  static void
> >>  build_dsdt(GArray *table_data, BIOSLinker *linker,
> >>             AcpiPmInfo *pm, AcpiMiscInfo *misc,
> >> @@ -2153,6 +2440,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
> >>                   */
> >>                  /* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
> >>                  aml_append(dev, aml_name_decl("_CRS", crs));
> >> +
> >> +                build_tpm_ppi(dev);
> >> +
> >>                  aml_append(scope, dev);
> >>              }
> >>
> >> @@ -2172,6 +2462,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
> >>          aml_append(method, aml_return(aml_int(0x0f)));
> >>          aml_append(dev, method);
> >>
> >> +        build_tpm_ppi(dev);
> >> +
> >>          aml_append(sb_scope, dev);
> >>      }
> >>
> >> @@ -2918,7 +3210,7 @@ void acpi_setup(void)
> >>          tpm_config = (FWCfgTPMConfig) {
> >>              .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE),
> >>              .tpm_version = cpu_to_le32(tpm_get_version(tpm_find())),
> >> -            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_NONE)  
> > what was the point of introducing TPM_PPI_VERSION_NONE if it would not be used?
> > maybe patch ordering is problem? what if we put fwcfg patch after this one?  
> 
> edk2 already knows that NONE (0) is no PPI. So we at least have to
> keep the same indexing.
> 
> I don't see much point in reordering. If you look at v4, you may want
> to squash things together too, but that makes reviewing more
> complicated. As the long as the split is natural, and no regression
> are introduced, I would rather keep it the way it is.
> 
> >  
> >> +            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_1_30)
> >>          };
> >>          fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config",
> >>                          &tpm_config, sizeof tpm_config);  
> >
> > hopefully patch would be more review-able with comments and nicely named
> > variables, so I could actually review it functionality wise without reading
> > whole TPM spec(s)  
> 
> Let see what I can do.
> 
> Thanks!
> 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-06-21 14:13         ` Marc-André Lureau
@ 2018-06-21 14:27           ` Igor Mammedov
  0 siblings, 0 replies; 40+ messages in thread
From: Igor Mammedov @ 2018-06-21 14:27 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Eduardo Habkost, Stefan Berger, Michael S. Tsirkin, QEMU,
	Paolo Bonzini, Richard Henderson

On Thu, 21 Jun 2018 16:13:32 +0200
Marc-André Lureau <marcandre.lureau@gmail.com> wrote:

> Hi
> 
> On Thu, Jun 21, 2018 at 3:22 PM, Marc-André Lureau
> <marcandre.lureau@gmail.com> wrote:
> > Hi
> >
> > On Thu, Jun 21, 2018 at 3:21 PM, Marc-André Lureau
> > <marcandre.lureau@gmail.com> wrote:
> >  
> >>>> +    method = aml_method("TPFN", 1, AML_SERIALIZED);  
> >>> not quite sure how this method (supposed to ) work(s),
> >>> it could use nice comment explaining mechanics.
> >>>  
> >>
> >> Windows doesn't like DerefOf (FUNC [N]), it returned wrong values. It
> >> took me a while to figure this out. My laptop TPM ACPI table uses the
> >> same trick, so I assume this is a Windows acpi bug/limitation. Instead
> >> we use a function that returns the corresponding field.  
> >
> > Sorry, I am wrong, my laptop doesn't use such table. I don't know
> > where I saw someone using the same trick though..  
> 
> fwiw, I also asked on OSR list for help but got no answer:
> http://www.osronline.com/showThread.CFM?link=288617
it is/might be fine if there is a workaround to make Windows work,
we should mention it in comment though (including windows versions
where it doesn't work) so in future someone else (including me and you)
won't break it by accident.

> 
> 
> 
> 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 4/4] tpm: add a fake ACPI memory clear interface
  2018-06-21 13:24     ` Marc-André Lureau
  2018-06-21 13:59       ` Stefan Berger
@ 2018-06-21 14:33       ` Igor Mammedov
  2018-06-26  9:22         ` Marc-André Lureau
  1 sibling, 1 reply; 40+ messages in thread
From: Igor Mammedov @ 2018-06-21 14:33 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Laszlo Ersek, Eduardo Habkost, Michael S. Tsirkin, Stefan Berger,
	QEMU, Paolo Bonzini, Richard Henderson

On Thu, 21 Jun 2018 15:24:44 +0200
Marc-André Lureau <marcandre.lureau@gmail.com> wrote:

> Hi
> 
> On Thu, Jun 21, 2018 at 3:02 PM, Igor Mammedov <imammedo@redhat.com> wrote:
> > On Tue, 15 May 2018 14:14:33 +0200
> > Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
> >  
> >> This allows to pass the last failing test from the Windows HLK TPM 2.0
> >> TCG PPI 1.3 tests.
> >>
> >> The interface is described in the "TCG Platform Reset Attack
> >> Mitigation Specification", chapter 6 "ACPI _DSM Function". Whether or
> >> not we should have a real implementation remains an open question to me.  
> > might it cause security issues?  
> 
> Good question. If the guest assumes success of this operation perhaps.
> I'll check the spec.
> 
> > What are implications of faking it and how hard it's to implement thing
> > per spec?  
> 
> Laszlo answerd that in "[Qemu-devel] investigating TPM for
> OVMF-on-QEMU"  2f2b) TCG Memory Clear Interface
I get that it's optional, but we probably shouldn't advertise/fake
feature if it's not supported.

> 
> >
> >  
> >> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> >> ---
> >>  hw/i386/acpi-build.c | 9 +++++++++
> >>  1 file changed, 9 insertions(+)
> >>
> >> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> >> index 95be4f0710..392a1e50bd 100644
> >> --- a/hw/i386/acpi-build.c
> >> +++ b/hw/i386/acpi-build.c
> >> @@ -2072,6 +2072,15 @@ build_tpm_ppi(Aml *dev)
> >>              aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
> >>          }
> >>          aml_append(method, ifctx);
> >> +
> >> +       /* dummy MOR Memory Clear for the sake of WLK PPI test */
> >> +        ifctx = aml_if(
> >> +            aml_equal(aml_arg(0),
> >> +                      aml_touuid("376054ED-CC13-4675-901C-4756D7F2D45D")));
> >> +        {
> >> +            aml_append(ifctx, aml_return(aml_int(0)));
> >> +        }
> >> +        aml_append(method, ifctx);
> >>      }
> >>      aml_append(dev, method);
> >>  }  
> >
> >  
> 
> 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-06-21 14:23       ` Igor Mammedov
@ 2018-06-21 17:10         ` Marc-André Lureau
  2018-06-21 17:36           ` Stefan Berger
  2018-06-22 13:40           ` Igor Mammedov
  0 siblings, 2 replies; 40+ messages in thread
From: Marc-André Lureau @ 2018-06-21 17:10 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Eduardo Habkost, Stefan Berger, Michael S. Tsirkin, QEMU,
	Paolo Bonzini, Richard Henderson

Hi

On Thu, Jun 21, 2018 at 4:23 PM, Igor Mammedov <imammedo@redhat.com> wrote:
> On Thu, 21 Jun 2018 15:21:02 +0200
> Marc-André Lureau <marcandre.lureau@gmail.com> wrote:
>
>> Hi
>>
>> On Thu, Jun 21, 2018 at 2:54 PM, Igor Mammedov <imammedo@redhat.com> wrote:
>> > On Tue, 15 May 2018 14:14:32 +0200
>> > Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
>> >
>> >> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
>> >>
>> >> The TPM Physical Presence interface consists of an ACPI part, a shared
>> >> memory part, and code in the firmware. Users can send messages to the
>> >> firmware by writing a code into the shared memory through invoking the
>> >> ACPI code. When a reboot happens, the firmware looks for the code and
>> >> acts on it by sending sequences of commands to the TPM.
>> >>
>> >> This patch adds the ACPI code. It is similar to the one in EDK2 but doesn't
>> >> assume that SMIs are necessary to use. It uses a similar datastructure for
>> >> the shared memory as EDK2 does so that EDK2 and SeaBIOS could both make use
>> >> of it. I extended the shared memory data structure with an array of 256
>> >> bytes, one for each code that could be implemented. The array contains
>> >> flags describing the individual codes. This decouples the ACPI implementation
>> >> from the firmware implementation.
>> >>
>> >> The underlying TCG specification is accessible from the following page.
>> >>
>> >> https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/
>> >>
>> >> This patch implements version 1.30.
>> >>
>> >> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>> >>
>> >> ---
>> >>
>> >> v4 (Marc-André):
>> >>  - replace 'DerefOf (FUNC [N])' with a function, to fix Windows ACPI
>> >>     handling.
>> >>  - replace 'return Package (..) {} ' with scoped variables, to fix
>> >>    Windows ACPI handling.
>> >>
>> >> v3:
>> >>  - add support for PPI to CRB
>> >>  - split up OperationRegion TPPI into two parts, one containing
>> >>    the registers (TPP1) and the other one the flags (TPP2); switched
>> >>    the order of the flags versus registers in the code
>> >>  - adapted ACPI code to small changes to the array of flags where
>> >>    previous flag 0 was removed and now shifting right wasn't always
>> >>    necessary anymore
>> >>
>> >> v2:
>> >>  - get rid of FAIL variable; function 5 was using it and always
>> >>    returns 0; the value is related to the ACPI function call not
>> >>    a possible failure of the TPM function call.
>> >>  - extend shared memory data structure with per-opcode entries
>> >>    holding flags and use those flags to determine what to return
>> >>    to caller
>> >>  - implement interface version 1.3
>> >> ---
>> >>  include/hw/acpi/tpm.h |  21 +++
>> >>  hw/i386/acpi-build.c  | 294 +++++++++++++++++++++++++++++++++++++++++-
>> >>  2 files changed, 314 insertions(+), 1 deletion(-)
>> >>
>> >> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
>> >> index f79d68a77a..fc53f08827 100644
>> >> --- a/include/hw/acpi/tpm.h
>> >> +++ b/include/hw/acpi/tpm.h
>> >> @@ -196,4 +196,25 @@ REG32(CRB_DATA_BUFFER, 0x80)
>> >>  #define TPM_PPI_VERSION_NONE        0
>> >>  #define TPM_PPI_VERSION_1_30        1
>> >>
>> >> +struct tpm_ppi {
>> >> +    uint8_t  func[256];      /* 0x000: per TPM function implementation flags;
>> >> +                                       set by BIOS */
>> >> +/* whether function is blocked by BIOS settings; bits 0, 1, 2 */
>> >> +#define TPM_PPI_FUNC_NOT_IMPLEMENTED     (0 << 0)
>> >> +#define TPM_PPI_FUNC_BIOS_ONLY           (1 << 0)
>> >> +#define TPM_PPI_FUNC_BLOCKED             (2 << 0)
>> >> +#define TPM_PPI_FUNC_ALLOWED_USR_REQ     (3 << 0)
>> >> +#define TPM_PPI_FUNC_ALLOWED_USR_NOT_REQ (4 << 0)
>> >> +#define TPM_PPI_FUNC_MASK                (7 << 0)
>> >> +    uint8_t ppin;            /* 0x100 : set by BIOS */
>> >> +    uint32_t ppip;           /* 0x101 : set by ACPI; not used */
>> >> +    uint32_t pprp;           /* 0x105 : response from TPM; set by BIOS */
>> >> +    uint32_t pprq;           /* 0x109 : opcode; set by ACPI */
>> >> +    uint32_t pprm;           /* 0x10d : parameter for opcode; set by ACPI */
>> >> +    uint32_t lppr;           /* 0x111 : last opcode; set by BIOS */
>> >> +    uint32_t fret;           /* 0x115 : set by ACPI; not used */
>> >> +    uint8_t res1[0x40];      /* 0x119 : reserved for future use */
>> >> +    uint8_t next_step;       /* 0x159 : next step after reboot; set by BIOS */
>> >> +} QEMU_PACKED;
>> > is this structure plant to be used for accessing data from within QEMU
>> > or it is just used for convenience of calculating offsets/sizes for AML?
>> >
>> >
>>
>> For convenience (and it can be useful for debugging).
> we are gradually getting rid of usage "struct foo" in ACPI code
> (i.e. when I have time to convert old struct based approach
> to build_append_int() table based format).
> and for new code I usually require ACPI parts be struct less
> (if there is no previous struct baggage to back it up).
>

The tpm_ppi struct is not an ACPI table, it's a fixed memory region /
layout to exchange between guest/os and firmware.

> Hence my request to drop dummy struct and document layout
> properly in related spec doc (that's where FW should look for
> documentation and not into struct definition somewhere in
> the header). So I'd strongly prefer it be done this way.

There is not much more than the field description for me ;). Stefan,
would you like to develop the structure usage?

>
>> >> +
>> >>  #endif /* HW_ACPI_TPM_H */
>> >> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>> >> index f6d447f03a..95be4f0710 100644
>> >> --- a/hw/i386/acpi-build.c
>> >> +++ b/hw/i386/acpi-build.c
>> >> @@ -43,6 +43,7 @@
>> >>  #include "hw/acpi/memory_hotplug.h"
>> >>  #include "sysemu/tpm.h"
>> >>  #include "hw/acpi/tpm.h"
>> >> +#include "hw/tpm/tpm_ppi.h"
>> >>  #include "hw/acpi/vmgenid.h"
>> >>  #include "sysemu/tpm_backend.h"
>> >>  #include "hw/timer/mc146818rtc_regs.h"
>> >> @@ -1789,6 +1790,292 @@ static Aml *build_q35_osc_method(void)
>> >>      return method;
>> >>  }
>> >>
>> >> +static void
>> >> +build_tpm_ppi(Aml *dev)
>> >> +{
>> >> +    Aml *method, *name, *field, *ifctx, *ifctx2, *ifctx3, *pak;
>> >> +    struct tpm_ppi *tpm_ppi = NULL;
>> >> +    int i;
>> > plain AML variables throughout the function make code rather unreadable
>> > (well, like any other AML code would be).
>> > Pls take a look at how build_legacy_cpu_hotplug_aml() uses intermediate
>> > more or less sanely named variables to make it more understandable.
>> > that also should allow to reduce LOC this function takes.
>>
>> Sorry, I don't understand what I should take from
>> build_legacy_cpu_hotplug_aml() approach. Could you describe a little
>> bit?
> I was talking about something like this:
>
>     Aml *apic_id = aml_arg(0);
>     Aml *cpu_on = aml_local(0);
>     ...
>     Aml *cpus_map = aml_name(CPU_ON_BITMAP);
>     ...
>     aml_append(method,
>         aml_store(aml_derefof(aml_index(cpus_map, apic_id)), cpu_on))
>
>     ^^^ this part becomes much more read-able for reviewer/maintainer versus pure ASL
>
>         aml_store(aml_derefof(aml_index(aml_name("CPON"), aml_arg(0))), aml_local(0)))

Ok

>
>> >
>> >> +    /*
>> >> +     * TPP1 is for the CPONflags that indicate which PPI operations
>> >> +     * are supported by the firmware. The firmware is expected to
>> >> +     * write these flags.
>> >> +     */
>> >> +    aml_append(dev,
>> >> +               aml_operation_region("TPP1", AML_SYSTEM_MEMORY,
>> >> +                                    aml_int(TPM_PPI_ADDR_BASE),
>> >> +                                    sizeof(tpm_ppi->func)));
>> >> +    field = aml_field("TPP1", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
>> >> +    for (i = 0; i < sizeof(tpm_ppi->func); i++) {
>> >> +        char *tmp = g_strdup_printf("FN%02X", i);
>> >> +        aml_append(field, aml_named_field(tmp, BITS_PER_BYTE));
>> >> +        g_free(tmp);
>> >> +    }
>> >> +    aml_append(dev, field);
>> >> +
>> >> +    /*
>> >> +     * TPP2 is for the registers that ACPI code used to pass
>> >> +     * the PPI code and parameter (PPRQ, PPRM) to the firmware.
>> >> +     */
>> >> +    aml_append(dev,
>> >> +               aml_operation_region("TPP2", AML_SYSTEM_MEMORY,
>> >> +                                    aml_int(TPM_PPI_ADDR_BASE +
>> >> +                                            offsetof(struct tpm_ppi, ppin)),
>> >> +                                    sizeof(struct tpm_ppi) -
>> >> +                                        sizeof(tpm_ppi->func)));
>> >> +    field = aml_field("TPP2", AML_ANY_ACC, AML_NOLOCK, AML_PRESERVE);
>> >> +    aml_append(field, aml_named_field("PPIN",
>> >> +               sizeof(uint8_t) * BITS_PER_BYTE));
>> > here you already don't use tpm_ppi for sizing, so it creates a confusing mix
>> > of both approaches.
>>
>> True, sizeof_field() will become handy here. I can leave a TODO?
>
> I'd just use a constant /8/ here like the rest of the code that uses aml_named_field()
> (no need to over-complicate or create another precedent to copy from)

ok

>
> Why TODO, changes I suggested for this patch would change it quite heavily
> so why merge patch that would be changed by follow up patch almost immediately.
> I'd prefer cleaner code being merged unless there are very good reasons
> to merge something that should be rewritten afterwards.

I thought we should use the upcoming sizeof_field() here. In this
case, TODO would make sense to avoid waiting for the other series.

>
>>
>>
>> >
>> > From ACPI pov I'd prefer PPI table documented somewhere in spec docs
>> > (similar docs/specs/acpi_mem_hotplug.txt) and would look like in
>> > other use-cases:
>> >
>> >    aml_append(field, aml_named_field("PPIN", 8)
>> >
>> > and drop "struct tpm_ppi" altogether replacing places it was used by
>> > explicit constants.
>>
>> I have a slight preference for the tpm_ppi structure. But ok with
>> replacing it with constant. Stefan, do you agree?
>>
>> >> +    aml_append(field, aml_named_field("PPIP",
>> >> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> >> +    aml_append(field, aml_named_field("PPRP",
>> >> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> >> +    aml_append(field, aml_named_field("PPRQ",
>> >> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> >> +    aml_append(field, aml_named_field("PPRM",
>> >> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> >> +    aml_append(field, aml_named_field("LPPR",
>> >> +               sizeof(uint32_t) * BITS_PER_BYTE));
>> >> +    aml_append(dev, field);
>> >> +
>> >> +    method = aml_method("TPFN", 1, AML_SERIALIZED);
>> > not quite sure how this method (supposed to ) work(s),
>> > it could use nice comment explaining mechanics.
>> >
>>
>> Windows doesn't like DerefOf (FUNC [N]), it returned wrong values. It
>> took me a while to figure this out. My laptop TPM ACPI table uses the
>> same trick, so I assume this is a Windows acpi bug/limitation. Instead
>> we use a function that returns the corresponding field.
>>
>> So we declare each field / array entry:
>>             OperationRegion (TPP1, SystemMemory, 0xFED45000, 0x0100)
>>             Field (TPP1, AnyAcc, NoLock, Preserve)
>>             {
>>                 FN00,   8,
>>                 FN01,   8,....
>>
>> And the method to access it:
>>
>>            Method (TPFN, 1, Serialized)
>>             {
>>                 If ((Zero == Arg0))
>>                 {
>>                     Return (FN00) /* \_SB_.TPM_.FN00 */
>>                 }
>> .....
>>
>>
>>
>> >> +    {
>> >> +        for (i = 0; i < sizeof(tpm_ppi->func); i++) {
>> >> +            ifctx = aml_if(aml_equal(aml_int(i), aml_arg(0)));
>> >> +            {
>> >> +                aml_append(ifctx, aml_return(aml_name("FN%02X", i)));
>> >> +            }
>> >> +            aml_append(method, ifctx);
>> >> +        }
>> >> +        aml_append(method, aml_return(aml_int(0)));
>> >> +    }
>> >> +    aml_append(dev, method);
>> >> +
>> >> +    pak = aml_package(2);
>> >> +    aml_append(pak, aml_int(0));
>> >> +    aml_append(pak, aml_int(0));
>> >> +    name = aml_name_decl("TPM2", pak);
>> >> +    aml_append(dev, name);
>> >> +
>> >> +    pak = aml_package(3);
>> >> +    aml_append(pak, aml_int(0));
>> >> +    aml_append(pak, aml_int(0));
>> >> +    aml_append(pak, aml_int(0));
>> >> +    name = aml_name_decl("TPM3", pak);
>> >> +    aml_append(dev, name);
>> >> +
>> >> +    method = aml_method("_DSM", 4, AML_SERIALIZED);
>> >> +    {
>> >> +        uint8_t zerobyte[1] = { 0 };
>> >> +
>> >> +        ifctx = aml_if(
>> >> +            aml_equal(aml_arg(0),
>> >> +                      aml_touuid("3DDDFAA6-361B-4EB4-A424-8D10089D1653")));
>> > a comment pointing to a specific part/version of spec that documents this _DSM
>> > for every uuid/function used here would help to review it.
>>
>> ok, fixing that.
>>
>> The spec PDF is fairly easy to read imho:
>>
>> https://trustedcomputinggroup.org/wp-content/uploads/Physical-Presence-Interface_1-30_0-52.pdf
>> >
>> >> +        {
>> >> +            aml_append(ifctx,
>> >> +                       aml_store(aml_to_integer(aml_arg(2)), aml_local(0)));
>> >> +
>> >> +            /* standard DSM query function */
>> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(0)));
>> >> +            {
>> >> +                uint8_t byte_list[2] = { 0xff, 0x01 };
>> >> +                aml_append(ifctx2, aml_return(aml_buffer(2, byte_list)));
>> >> +            }
>> >> +            aml_append(ifctx, ifctx2);
>> >> +
>> >> +            /* interface version: 1.3 */
>> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(1)));
>> >> +            {
>> >> +                aml_append(ifctx2, aml_return(aml_string("1.3")));
>> >> +            }
>> >> +            aml_append(ifctx, ifctx2);
>> >> +
>> >> +            /* submit TPM operation */
>> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(2)));
>> >> +            {
>> >> +                /* get opcode */
>> >> +                aml_append(ifctx2,
>> >> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
>> >> +                                                           aml_int(0))),
>> >> +                                     aml_local(0)));
>> >> +                /* get opcode flags */
>> >> +                aml_append(ifctx2,
>> >> +                           aml_store(aml_call1("TPFN", aml_local(0)),
>> >> +                                     aml_local(1)));
>> >> +                ifctx3 = aml_if(
>> >> +                    aml_equal(
>> >> +                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
>> >> +                        aml_int(TPM_PPI_FUNC_NOT_IMPLEMENTED)));
>> >> +                {
>> >> +                    /* 1: not implemented */
>> >> +                    aml_append(ifctx3, aml_return(aml_int(1)));
>> >> +                }
>> >> +                aml_append(ifctx2, ifctx3);
>> >> +                aml_append(ifctx2, aml_store(aml_local(0), aml_name("PPRQ")));
>> >> +                aml_append(ifctx2, aml_store(aml_int(0), aml_name("PPRM")));
>> >> +                /* 0: success */
>> >> +                aml_append(ifctx2, aml_return(aml_int(0)));
>> >> +            }
>> >> +            aml_append(ifctx, ifctx2);
>> >> +
>> >> +            /* get pending TPM operation */
>> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(3)));
>> >> +            {
>> >> +                /* revision to integer */
>> >> +                aml_append(ifctx2,
>> >> +                           aml_store(
>> >> +                               aml_to_integer(aml_arg(1)),
>> >> +                               aml_local(1)));
>> >> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(1)));
>> >> +                {
>> >> +                    aml_append(ifctx3,
>> >> +                               aml_store(
>> >> +                                   aml_name("PPRQ"),
>> >> +                                   aml_index(aml_name("TPM2"), aml_int(1))));
>> >> +                    aml_append(ifctx3, aml_return(aml_name("TPM2")));
>> >> +                }
>> >> +                aml_append(ifctx2, ifctx3);
>> >> +
>> >> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(2)));
>> >> +                {
>> >> +                    aml_append(ifctx3,
>> >> +                               aml_store(
>> >> +                                   aml_name("PPRQ"),
>> >> +                                   aml_index(aml_name("TPM3"), aml_int(1))));
>> >> +                    aml_append(ifctx3,
>> >> +                               aml_store(
>> >> +                                   aml_name("PPRM"),
>> >> +                                   aml_index(aml_name("TPM3"), aml_int(2))));
>> >> +                    aml_append(ifctx3, aml_return(aml_name("TPM3")));
>> >> +                }
>> >> +                aml_append(ifctx2, ifctx3);
>> >> +            }
>> >> +            aml_append(ifctx, ifctx2);
>> >> +
>> >> +            /* get platform-specific action to transition to pre-OS env. */
>> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(4)));
>> >> +            {
>> >> +                /* reboot */
>> >> +                aml_append(ifctx2, aml_return(aml_int(2)));
>> >> +            }
>> >> +            aml_append(ifctx, ifctx2);
>> >> +
>> >> +            /* get TPM operation response */
>> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(5)));
>> >> +            {
>> >> +                aml_append(ifctx2,
>> >> +                           aml_store(
>> >> +                               aml_name("LPPR"),
>> >> +                               aml_index(aml_name("TPM3"), aml_int(1))));
>> >> +                aml_append(ifctx2,
>> >> +                           aml_store(
>> >> +                               aml_name("PPRP"),
>> >> +                               aml_index(aml_name("TPM3"), aml_int(2))));
>> >> +                aml_append(ifctx2, aml_return(aml_name("TPM3")));
>> >> +            }
>> >> +            aml_append(ifctx, ifctx2);
>> >> +
>> >> +            /* submit preferred user language */
>> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(6)));
>> >> +            {
>> >> +                /* 3 = not implemented */
>> >> +                aml_append(ifctx2, aml_return(aml_int(3)));
>> >> +            }
>> >> +            aml_append(ifctx, ifctx2);
>> >> +
>> >> +            /* submit TPM operation v2 */
>> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(7)));
>> >> +            {
>> >> +                /* get opcode */
>> >> +                aml_append(ifctx2,
>> >> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
>> >> +                                                           aml_int(0))),
>> >> +                                     aml_local(0)));
>> >> +                /* get opcode flags */
>> >> +                aml_append(ifctx2,
>> >> +                           aml_store(aml_call1("TPFN", aml_local(0)),
>> >> +                                     aml_local(1)));
>> >> +                ifctx3 = aml_if(
>> >> +                    aml_equal(
>> >> +                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
>> >> +                        aml_int(TPM_PPI_FUNC_NOT_IMPLEMENTED)));
>> >> +                {
>> >> +                    /* 1: not implemented */
>> >> +                    aml_append(ifctx3, aml_return(aml_int(1)));
>> >> +                }
>> >> +                aml_append(ifctx2, ifctx3);
>> >> +
>> >> +                ifctx3 = aml_if(
>> >> +                    aml_equal(
>> >> +                        aml_and(aml_local(1), aml_int(TPM_PPI_FUNC_MASK), NULL),
>> >> +                        aml_int(TPM_PPI_FUNC_BLOCKED)));
>> >> +                {
>> >> +                    /* 3: blocked by firmware */
>> >> +                    aml_append(ifctx3, aml_return(aml_int(3)));
>> >> +                }
>> >> +                aml_append(ifctx2, ifctx3);
>> >> +
>> >> +                /* revision to integer */
>> >> +                aml_append(ifctx2,
>> >> +                           aml_store(
>> >> +                               aml_to_integer(aml_arg(1)),
>> >> +                               aml_local(1)));
>> >> +
>> >> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(1)));
>> >> +                {
>> >> +                    /* revision 1 */
>> >> +                    aml_append(ifctx3, aml_store(aml_local(0),
>> >> +                                                 aml_name("PPRQ")));
>> >> +                    aml_append(ifctx3, aml_store(aml_int(0),
>> >> +                                                 aml_name("PPRM")));
>> >> +                }
>> >> +                aml_append(ifctx2, ifctx3);
>> >> +
>> >> +                ifctx3 = aml_if(aml_equal(aml_local(1), aml_int(2)));
>> >> +                {
>> >> +                    /* revision 2 */
>> >> +                    aml_append(ifctx3,
>> >> +                               aml_store(aml_local(0), aml_name("PPRQ")));
>> >> +                    aml_append(ifctx3,
>> >> +                               aml_store(
>> >> +                                   aml_derefof(aml_index(aml_arg(3),
>> >> +                                                         aml_int(1))),
>> >> +                                   aml_name("PPRM")));
>> >> +                }
>> >> +                aml_append(ifctx2, ifctx3);
>> >> +                /* 0: success */
>> >> +                aml_append(ifctx2, aml_return(aml_int(0)));
>> >> +            }
>> >> +            aml_append(ifctx, ifctx2);
>> >> +
>> >> +            /* get user confirmation status for operation */
>> >> +            ifctx2 = aml_if(aml_equal(aml_local(0), aml_int(8)));
>> >> +            {
>> >> +                /* get opcode */
>> >> +                aml_append(ifctx2,
>> >> +                           aml_store(aml_derefof(aml_index(aml_arg(3),
>> >> +                                                           aml_int(0))),
>> >> +                                     aml_local(0)));
>> >> +                /* get opcode flags */
>> >> +                aml_append(ifctx2,
>> >> +                           aml_store(aml_call1("TPFN", aml_local(0)),
>> >> +                                     aml_local(1)));
>> >> +                /* return confirmation status code */
>> >> +                aml_append(ifctx2,
>> >> +                           aml_return(
>> >> +                               aml_and(aml_local(1),
>> >> +                                       aml_int(TPM_PPI_FUNC_MASK), NULL)));
>> >> +            }
>> >> +            aml_append(ifctx, ifctx2);
>> >> +
>> >> +            aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
>> >> +        }
>> >> +        aml_append(method, ifctx);
>> >> +    }
>> >> +    aml_append(dev, method);
>> >> +}
>> >> +
>> >>  static void
>> >>  build_dsdt(GArray *table_data, BIOSLinker *linker,
>> >>             AcpiPmInfo *pm, AcpiMiscInfo *misc,
>> >> @@ -2153,6 +2440,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
>> >>                   */
>> >>                  /* aml_append(crs, aml_irq_no_flags(TPM_TIS_IRQ)); */
>> >>                  aml_append(dev, aml_name_decl("_CRS", crs));
>> >> +
>> >> +                build_tpm_ppi(dev);
>> >> +
>> >>                  aml_append(scope, dev);
>> >>              }
>> >>
>> >> @@ -2172,6 +2462,8 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
>> >>          aml_append(method, aml_return(aml_int(0x0f)));
>> >>          aml_append(dev, method);
>> >>
>> >> +        build_tpm_ppi(dev);
>> >> +
>> >>          aml_append(sb_scope, dev);
>> >>      }
>> >>
>> >> @@ -2918,7 +3210,7 @@ void acpi_setup(void)
>> >>          tpm_config = (FWCfgTPMConfig) {
>> >>              .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE),
>> >>              .tpm_version = cpu_to_le32(tpm_get_version(tpm_find())),
>> >> -            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_NONE)
>> > what was the point of introducing TPM_PPI_VERSION_NONE if it would not be used?
>> > maybe patch ordering is problem? what if we put fwcfg patch after this one?
>>
>> edk2 already knows that NONE (0) is no PPI. So we at least have to
>> keep the same indexing.
>>
>> I don't see much point in reordering. If you look at v4, you may want
>> to squash things together too, but that makes reviewing more
>> complicated. As the long as the split is natural, and no regression
>> are introduced, I would rather keep it the way it is.
>>
>> >
>> >> +            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_1_30)
>> >>          };
>> >>          fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config",
>> >>                          &tpm_config, sizeof tpm_config);
>> >
>> > hopefully patch would be more review-able with comments and nicely named
>> > variables, so I could actually review it functionality wise without reading
>> > whole TPM spec(s)
>>
>> Let see what I can do.
>>
>> Thanks!
>>
>>
>



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-06-21 17:10         ` Marc-André Lureau
@ 2018-06-21 17:36           ` Stefan Berger
  2018-06-22 13:40           ` Igor Mammedov
  1 sibling, 0 replies; 40+ messages in thread
From: Stefan Berger @ 2018-06-21 17:36 UTC (permalink / raw)
  To: Marc-André Lureau, Igor Mammedov
  Cc: Eduardo Habkost, Michael S. Tsirkin, QEMU, Paolo Bonzini,
	Richard Henderson

On 06/21/2018 01:10 PM, Marc-André Lureau wrote:
> Hi
>
> On Thu, Jun 21, 2018 at 4:23 PM, Igor Mammedov <imammedo@redhat.com> wrote:
>> On Thu, 21 Jun 2018 15:21:02 +0200
>> Marc-André Lureau <marcandre.lureau@gmail.com> wrote:
>>
>>> Hi
>>>
>>> On Thu, Jun 21, 2018 at 2:54 PM, Igor Mammedov <imammedo@redhat.com> wrote:
>>>> On Tue, 15 May 2018 14:14:32 +0200
>>>> Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
>>>>
>>>>> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>>>
>>>>> The TPM Physical Presence interface consists of an ACPI part, a shared
>>>>> memory part, and code in the firmware. Users can send messages to the
>>>>> firmware by writing a code into the shared memory through invoking the
>>>>> ACPI code. When a reboot happens, the firmware looks for the code and
>>>>> acts on it by sending sequences of commands to the TPM.
>>>>>
>>>>> This patch adds the ACPI code. It is similar to the one in EDK2 but doesn't
>>>>> assume that SMIs are necessary to use. It uses a similar datastructure for
>>>>> the shared memory as EDK2 does so that EDK2 and SeaBIOS could both make use
>>>>> of it. I extended the shared memory data structure with an array of 256
>>>>> bytes, one for each code that could be implemented. The array contains
>>>>> flags describing the individual codes. This decouples the ACPI implementation
>>>>> from the firmware implementation.
>>>>>
>>>>> The underlying TCG specification is accessible from the following page.
>>>>>
>>>>> https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/
>>>>>
>>>>> This patch implements version 1.30.
>>>>>
>>>>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>>>
>>>>> ---
>>>>>
>>>>> v4 (Marc-André):
>>>>>   - replace 'DerefOf (FUNC [N])' with a function, to fix Windows ACPI
>>>>>      handling.
>>>>>   - replace 'return Package (..) {} ' with scoped variables, to fix
>>>>>     Windows ACPI handling.
>>>>>
>>>>> v3:
>>>>>   - add support for PPI to CRB
>>>>>   - split up OperationRegion TPPI into two parts, one containing
>>>>>     the registers (TPP1) and the other one the flags (TPP2); switched
>>>>>     the order of the flags versus registers in the code
>>>>>   - adapted ACPI code to small changes to the array of flags where
>>>>>     previous flag 0 was removed and now shifting right wasn't always
>>>>>     necessary anymore
>>>>>
>>>>> v2:
>>>>>   - get rid of FAIL variable; function 5 was using it and always
>>>>>     returns 0; the value is related to the ACPI function call not
>>>>>     a possible failure of the TPM function call.
>>>>>   - extend shared memory data structure with per-opcode entries
>>>>>     holding flags and use those flags to determine what to return
>>>>>     to caller
>>>>>   - implement interface version 1.3
>>>>> ---
>>>>>   include/hw/acpi/tpm.h |  21 +++
>>>>>   hw/i386/acpi-build.c  | 294 +++++++++++++++++++++++++++++++++++++++++-
>>>>>   2 files changed, 314 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
>>>>> index f79d68a77a..fc53f08827 100644
>>>>> --- a/include/hw/acpi/tpm.h
>>>>> +++ b/include/hw/acpi/tpm.h
>>>>> @@ -196,4 +196,25 @@ REG32(CRB_DATA_BUFFER, 0x80)
>>>>>   #define TPM_PPI_VERSION_NONE        0
>>>>>   #define TPM_PPI_VERSION_1_30        1
>>>>>
>>>>> +struct tpm_ppi {
>>>>> +    uint8_t  func[256];      /* 0x000: per TPM function implementation flags;
>>>>> +                                       set by BIOS */
>>>>> +/* whether function is blocked by BIOS settings; bits 0, 1, 2 */
>>>>> +#define TPM_PPI_FUNC_NOT_IMPLEMENTED     (0 << 0)
>>>>> +#define TPM_PPI_FUNC_BIOS_ONLY           (1 << 0)
>>>>> +#define TPM_PPI_FUNC_BLOCKED             (2 << 0)
>>>>> +#define TPM_PPI_FUNC_ALLOWED_USR_REQ     (3 << 0)
>>>>> +#define TPM_PPI_FUNC_ALLOWED_USR_NOT_REQ (4 << 0)
>>>>> +#define TPM_PPI_FUNC_MASK                (7 << 0)
>>>>> +    uint8_t ppin;            /* 0x100 : set by BIOS */
>>>>> +    uint32_t ppip;           /* 0x101 : set by ACPI; not used */
>>>>> +    uint32_t pprp;           /* 0x105 : response from TPM; set by BIOS */
>>>>> +    uint32_t pprq;           /* 0x109 : opcode; set by ACPI */
>>>>> +    uint32_t pprm;           /* 0x10d : parameter for opcode; set by ACPI */
>>>>> +    uint32_t lppr;           /* 0x111 : last opcode; set by BIOS */
>>>>> +    uint32_t fret;           /* 0x115 : set by ACPI; not used */
>>>>> +    uint8_t res1[0x40];      /* 0x119 : reserved for future use */
>>>>> +    uint8_t next_step;       /* 0x159 : next step after reboot; set by BIOS */
>>>>> +} QEMU_PACKED;
>>>> is this structure plant to be used for accessing data from within QEMU
>>>> or it is just used for convenience of calculating offsets/sizes for AML?
>>>>
>>>>
>>> For convenience (and it can be useful for debugging).
>> we are gradually getting rid of usage "struct foo" in ACPI code
>> (i.e. when I have time to convert old struct based approach
>> to build_append_int() table based format).
>> and for new code I usually require ACPI parts be struct less
>> (if there is no previous struct baggage to back it up).
>>
> The tpm_ppi struct is not an ACPI table, it's a fixed memory region /
> layout to exchange between guest/os and firmware.
>
>> Hence my request to drop dummy struct and document layout
>> properly in related spec doc (that's where FW should look for
>> documentation and not into struct definition somewhere in
>> the header). So I'd strongly prefer it be done this way.
> There is not much more than the field description for me ;). Stefan,
> would you like to develop the structure usage?

Will do.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 2/4] acpi: add fw_cfg file for TPM and PPI virtual memory device
  2018-06-21 10:10     ` Marc-André Lureau
  2018-06-21 13:55       ` Igor Mammedov
@ 2018-06-22  0:16       ` Laszlo Ersek
  2018-06-25 15:20       ` Laszlo Ersek
  2 siblings, 0 replies; 40+ messages in thread
From: Laszlo Ersek @ 2018-06-22  0:16 UTC (permalink / raw)
  To: Marc-André Lureau, Igor Mammedov
  Cc: Eduardo Habkost, Stefan Berger, Michael S. Tsirkin, QEMU,
	Paolo Bonzini, Richard Henderson

On 06/21/18 12:10, Marc-André Lureau wrote:

> What do you think Laszlo?

Apologies, I'm currently lacking the bandwidth to even understand the
question. I'm tagging this message for later; it'll take a while before
I get to it.

Thanks
Laszlo

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface
  2018-06-21 17:10         ` Marc-André Lureau
  2018-06-21 17:36           ` Stefan Berger
@ 2018-06-22 13:40           ` Igor Mammedov
  1 sibling, 0 replies; 40+ messages in thread
From: Igor Mammedov @ 2018-06-22 13:40 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Eduardo Habkost, Stefan Berger, Michael S. Tsirkin, QEMU,
	Paolo Bonzini, Richard Henderson

On Thu, 21 Jun 2018 19:10:38 +0200
Marc-André Lureau <marcandre.lureau@gmail.com> wrote:

> Hi
> 
> On Thu, Jun 21, 2018 at 4:23 PM, Igor Mammedov <imammedo@redhat.com> wrote:
> > On Thu, 21 Jun 2018 15:21:02 +0200
> > Marc-André Lureau <marcandre.lureau@gmail.com> wrote:
> >  
> >> Hi
> >>
> >> On Thu, Jun 21, 2018 at 2:54 PM, Igor Mammedov <imammedo@redhat.com> wrote:  
> >> > On Tue, 15 May 2018 14:14:32 +0200
> >> > Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
> >> >  
> >> >> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
> >> >>
> >> >> The TPM Physical Presence interface consists of an ACPI part, a shared
> >> >> memory part, and code in the firmware. Users can send messages to the
> >> >> firmware by writing a code into the shared memory through invoking the
> >> >> ACPI code. When a reboot happens, the firmware looks for the code and
> >> >> acts on it by sending sequences of commands to the TPM.
> >> >>
> >> >> This patch adds the ACPI code. It is similar to the one in EDK2 but doesn't
> >> >> assume that SMIs are necessary to use. It uses a similar datastructure for
> >> >> the shared memory as EDK2 does so that EDK2 and SeaBIOS could both make use
> >> >> of it. I extended the shared memory data structure with an array of 256
> >> >> bytes, one for each code that could be implemented. The array contains
> >> >> flags describing the individual codes. This decouples the ACPI implementation
> >> >> from the firmware implementation.
> >> >>
> >> >> The underlying TCG specification is accessible from the following page.
> >> >>
> >> >> https://trustedcomputinggroup.org/tcg-physical-presence-interface-specification/
> >> >>
> >> >> This patch implements version 1.30.
> >> >>
> >> >> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> >> >>
> >> >> ---
> >> >>
> >> >> v4 (Marc-André):
> >> >>  - replace 'DerefOf (FUNC [N])' with a function, to fix Windows ACPI
> >> >>     handling.
> >> >>  - replace 'return Package (..) {} ' with scoped variables, to fix
> >> >>    Windows ACPI handling.
> >> >>
> >> >> v3:
> >> >>  - add support for PPI to CRB
> >> >>  - split up OperationRegion TPPI into two parts, one containing
> >> >>    the registers (TPP1) and the other one the flags (TPP2); switched
> >> >>    the order of the flags versus registers in the code
> >> >>  - adapted ACPI code to small changes to the array of flags where
> >> >>    previous flag 0 was removed and now shifting right wasn't always
> >> >>    necessary anymore
> >> >>
> >> >> v2:
> >> >>  - get rid of FAIL variable; function 5 was using it and always
> >> >>    returns 0; the value is related to the ACPI function call not
> >> >>    a possible failure of the TPM function call.
> >> >>  - extend shared memory data structure with per-opcode entries
> >> >>    holding flags and use those flags to determine what to return
> >> >>    to caller
> >> >>  - implement interface version 1.3
> >> >> ---
> >> >>  include/hw/acpi/tpm.h |  21 +++
> >> >>  hw/i386/acpi-build.c  | 294 +++++++++++++++++++++++++++++++++++++++++-
> >> >>  2 files changed, 314 insertions(+), 1 deletion(-)
> >> >>
> >> >> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
> >> >> index f79d68a77a..fc53f08827 100644
> >> >> --- a/include/hw/acpi/tpm.h
> >> >> +++ b/include/hw/acpi/tpm.h
> >> >> @@ -196,4 +196,25 @@ REG32(CRB_DATA_BUFFER, 0x80)
> >> >>  #define TPM_PPI_VERSION_NONE        0
> >> >>  #define TPM_PPI_VERSION_1_30        1
> >> >>
> >> >> +struct tpm_ppi {
> >> >> +    uint8_t  func[256];      /* 0x000: per TPM function implementation flags;
> >> >> +                                       set by BIOS */
> >> >> +/* whether function is blocked by BIOS settings; bits 0, 1, 2 */
> >> >> +#define TPM_PPI_FUNC_NOT_IMPLEMENTED     (0 << 0)
> >> >> +#define TPM_PPI_FUNC_BIOS_ONLY           (1 << 0)
> >> >> +#define TPM_PPI_FUNC_BLOCKED             (2 << 0)
> >> >> +#define TPM_PPI_FUNC_ALLOWED_USR_REQ     (3 << 0)
> >> >> +#define TPM_PPI_FUNC_ALLOWED_USR_NOT_REQ (4 << 0)
> >> >> +#define TPM_PPI_FUNC_MASK                (7 << 0)
> >> >> +    uint8_t ppin;            /* 0x100 : set by BIOS */
> >> >> +    uint32_t ppip;           /* 0x101 : set by ACPI; not used */
> >> >> +    uint32_t pprp;           /* 0x105 : response from TPM; set by BIOS */
> >> >> +    uint32_t pprq;           /* 0x109 : opcode; set by ACPI */
> >> >> +    uint32_t pprm;           /* 0x10d : parameter for opcode; set by ACPI */
> >> >> +    uint32_t lppr;           /* 0x111 : last opcode; set by BIOS */
> >> >> +    uint32_t fret;           /* 0x115 : set by ACPI; not used */
> >> >> +    uint8_t res1[0x40];      /* 0x119 : reserved for future use */
> >> >> +    uint8_t next_step;       /* 0x159 : next step after reboot; set by BIOS */
> >> >> +} QEMU_PACKED;  
> >> > is this structure plant to be used for accessing data from within QEMU
> >> > or it is just used for convenience of calculating offsets/sizes for AML?
> >> >
> >> >  
> >>
> >> For convenience (and it can be useful for debugging).  
> > we are gradually getting rid of usage "struct foo" in ACPI code
> > (i.e. when I have time to convert old struct based approach
> > to build_append_int() table based format).
> > and for new code I usually require ACPI parts be struct less
> > (if there is no previous struct baggage to back it up).
> >  
> 
> The tpm_ppi struct is not an ACPI table, it's a fixed memory region /
> layout to exchange between guest/os and firmware.
it's interface between ACPI and firmware and it's used in ACPI
parts of code (mainly as means to document layout). I wouldn't care
much if it were buried inside of TPM code, but it's used mainly as
dummy struct for documenting and by ACPI parts of code for an implicit
sizing math, for that I'd like you to use spec/constants like any
other new ACPI code does.
So lets keep things consistent here at least for ACPI parts that
I maintain.

 
> > Hence my request to drop dummy struct and document layout
> > properly in related spec doc (that's where FW should look for
> > documentation and not into struct definition somewhere in
> > the header). So I'd strongly prefer it be done this way.  
> 
> There is not much more than the field description for me ;). Stefan,
> would you like to develop the structure usage?
You should use table format to document ACPI interface in spec
(ex: docs/specs/acpi_mem_hotplug.txt) at least for consistence sake.
I don't care that firmware side uses C code as documentation as
it's up whatever maintainers prefer over there.
 
[...]

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 2/4] acpi: add fw_cfg file for TPM and PPI virtual memory device
  2018-06-21 10:10     ` Marc-André Lureau
  2018-06-21 13:55       ` Igor Mammedov
  2018-06-22  0:16       ` Laszlo Ersek
@ 2018-06-25 15:20       ` Laszlo Ersek
  2018-06-26 10:38         ` Marc-André Lureau
  2 siblings, 1 reply; 40+ messages in thread
From: Laszlo Ersek @ 2018-06-25 15:20 UTC (permalink / raw)
  To: Marc-André Lureau, Igor Mammedov
  Cc: Eduardo Habkost, Stefan Berger, Michael S. Tsirkin, QEMU,
	Paolo Bonzini, Richard Henderson

On 06/21/18 12:10, Marc-André Lureau wrote:
> Hi
> 
> On Thu, Jun 21, 2018 at 12:00 PM, Igor Mammedov <imammedo@redhat.com> wrote:
>> On Tue, 15 May 2018 14:14:31 +0200
>> Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
>>
>>> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>
>>> To avoid having to hard code the base address of the PPI virtual
>>> memory device we introduce a fw_cfg file etc/tpm/config that holds the
>>> base address of the PPI device, the version of the PPI interface and
>>> the version of the attached TPM.
>> is it related to TPM_PPI_ADDR_BASE added in previous patch?
>>
>>>
>>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>> [ Marc-André: renamed to etc/tpm/config, made it static, document it ]
>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>> ---
>>>  include/hw/acpi/tpm.h |  3 +++
>>>  hw/i386/acpi-build.c  | 17 +++++++++++++++++
>>>  docs/specs/tpm.txt    | 20 ++++++++++++++++++++
>>>  3 files changed, 40 insertions(+)
>>>
>>> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
>>> index c082df7d1d..f79d68a77a 100644
>>> --- a/include/hw/acpi/tpm.h
>>> +++ b/include/hw/acpi/tpm.h
>>> @@ -193,4 +193,7 @@ REG32(CRB_DATA_BUFFER, 0x80)
>>>  #define TPM_PPI_ADDR_SIZE           0x400
>>>  #define TPM_PPI_ADDR_BASE           0xFED45000
>>>
>>> +#define TPM_PPI_VERSION_NONE        0
>>> +#define TPM_PPI_VERSION_1_30        1
>>> +
>>>  #endif /* HW_ACPI_TPM_H */
>>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>>> index 9bc6d97ea1..f6d447f03a 100644
>>> --- a/hw/i386/acpi-build.c
>>> +++ b/hw/i386/acpi-build.c
>>> @@ -119,6 +119,12 @@ typedef struct AcpiBuildPciBusHotplugState {
>>>      bool pcihp_bridge_en;
>>>  } AcpiBuildPciBusHotplugState;
>>>
>>> +typedef struct FWCfgTPMConfig {
>>> +    uint32_t tpmppi_address;
>>> +    uint8_t tpm_version;
>>> +    uint8_t tpmppi_version;
>>> +} QEMU_PACKED FWCfgTPMConfig;
>>> +
>>>  static void init_common_fadt_data(Object *o, AcpiFadtData *data)
>>>  {
>>>      uint32_t io = object_property_get_uint(o, ACPI_PM_PROP_PM_IO_BASE, NULL);
>>> @@ -2873,6 +2879,7 @@ void acpi_setup(void)
>>>      AcpiBuildTables tables;
>>>      AcpiBuildState *build_state;
>>>      Object *vmgenid_dev;
>>> +    static FWCfgTPMConfig tpm_config;
>>>
>>>      if (!pcms->fw_cfg) {
>>>          ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
>>> @@ -2907,6 +2914,16 @@ void acpi_setup(void)
>>>      fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
>>>                      tables.tcpalog->data, acpi_data_len(tables.tcpalog));
>>>
>>> +    if (tpm_find()) {
>>> +        tpm_config = (FWCfgTPMConfig) {
>>> +            .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE),
>>> +            .tpm_version = cpu_to_le32(tpm_get_version(tpm_find())),
>>> +            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_NONE)
>>> +        };
>>> +        fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config",
>>> +                        &tpm_config, sizeof tpm_config);
>>> +    }
>> why it's in ACPI part of the code, shouldn't it be a part of device,
>> could TPM be used without ACPI at all (-noacpi CLI option)?
>>
>> Wouldn't adding fwcfg entry unconditionally break migration?
> 
> Because of unstable entry IDs? that could be problematic. (especially
> during boot time) What do you think Laszlo?
> 
> I guess we could have a "ppi" device property, that would imply having
> the etc/tpm/config fw_cfg entry. We would enable it by default in
> newer machine types (3.0?)

Can we perhaps draw a parallel with "-device vmcoreinfo" here? For that
device model, fw_cfg_add_file_callback() is called in the realize
function, vmcoreinfo_realize(). If libvirt generates the identical
cmdline on both ends of the migration, and uses the same machine type, I
think the fw_cfg selectors should end up the same on both sides.

Thanks
Laszlo

>>
>>> +
>>>      vmgenid_dev = find_vmgenid_dev();
>>>      if (vmgenid_dev) {
>>>          vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), pcms->fw_cfg,
>>> diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt
>>> index c230c4c93e..2ddb768084 100644
>>> --- a/docs/specs/tpm.txt
>>> +++ b/docs/specs/tpm.txt
>>> @@ -20,6 +20,26 @@ QEMU files related to TPM TIS interface:
>>>   - hw/tpm/tpm_tis.h
>>>
>>>
>>> += fw_cfg interface =
>>> +
>>> +The bios/firmware may use the "etc/tpm/config" fw_cfg entry for
>>> +configuring the guest appropriately.
>>> +
>>> +The entry of 6 bytes has the following content, in little-endian:
>>> +
>>> +    #define TPM_VERSION_UNSPEC          0
>>> +    #define TPM_VERSION_1_2             1
>>> +    #define TPM_VERSION_2_0             2
>>> +
>>> +    #define TPM_PPI_VERSION_NONE        0
>>> +    #define TPM_PPI_VERSION_1_30        1
>>> +
>>> +    struct FWCfgTPMConfig {
>>> +        uint32_t tpmppi_address;         /* PPI memory location */
>>> +        uint8_t tpm_version;             /* TPM version */
>>> +        uint8_t tpmppi_version;          /* PPI version */
>>> +    };
>>> +
>>>  = ACPI Interface =
>>>
>>>  The TPM device is defined with ACPI ID "PNP0C31". QEMU builds a SSDT and passes
>>
>>
> 
> 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 4/4] tpm: add a fake ACPI memory clear interface
  2018-06-21 14:33       ` Igor Mammedov
@ 2018-06-26  9:22         ` Marc-André Lureau
  2018-06-26 12:34           ` Igor Mammedov
  0 siblings, 1 reply; 40+ messages in thread
From: Marc-André Lureau @ 2018-06-26  9:22 UTC (permalink / raw)
  To: Igor Mammedov
  Cc: Laszlo Ersek, Eduardo Habkost, Michael S. Tsirkin, Stefan Berger,
	QEMU, Paolo Bonzini, Richard Henderson

On Thu, Jun 21, 2018 at 4:33 PM, Igor Mammedov <imammedo@redhat.com> wrote:
> On Thu, 21 Jun 2018 15:24:44 +0200
> Marc-André Lureau <marcandre.lureau@gmail.com> wrote:
>
>> Hi
>>
>> On Thu, Jun 21, 2018 at 3:02 PM, Igor Mammedov <imammedo@redhat.com> wrote:
>> > On Tue, 15 May 2018 14:14:33 +0200
>> > Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
>> >
>> >> This allows to pass the last failing test from the Windows HLK TPM 2.0
>> >> TCG PPI 1.3 tests.
>> >>
>> >> The interface is described in the "TCG Platform Reset Attack
>> >> Mitigation Specification", chapter 6 "ACPI _DSM Function". Whether or
>> >> not we should have a real implementation remains an open question to me.
>> > might it cause security issues?
>>
>> Good question. If the guest assumes success of this operation perhaps.
>> I'll check the spec.
>>
>> > What are implications of faking it and how hard it's to implement thing
>> > per spec?
>>
>> Laszlo answerd that in "[Qemu-devel] investigating TPM for
>> OVMF-on-QEMU"  2f2b) TCG Memory Clear Interface
> I get that it's optional, but we probably shouldn't advertise/fake
> feature if it's not supported.

As said in the commit message, the objective was to pass the Windows
HLK test. If we don't want to advertize a fake interface, I am fine
droping this patch. We'll have to revisit with Laszlo the work needed
in the firmware to support it.

>
>>
>> >
>> >
>> >> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>> >> ---
>> >>  hw/i386/acpi-build.c | 9 +++++++++
>> >>  1 file changed, 9 insertions(+)
>> >>
>> >> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>> >> index 95be4f0710..392a1e50bd 100644
>> >> --- a/hw/i386/acpi-build.c
>> >> +++ b/hw/i386/acpi-build.c
>> >> @@ -2072,6 +2072,15 @@ build_tpm_ppi(Aml *dev)
>> >>              aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
>> >>          }
>> >>          aml_append(method, ifctx);
>> >> +
>> >> +       /* dummy MOR Memory Clear for the sake of WLK PPI test */
>> >> +        ifctx = aml_if(
>> >> +            aml_equal(aml_arg(0),
>> >> +                      aml_touuid("376054ED-CC13-4675-901C-4756D7F2D45D")));
>> >> +        {
>> >> +            aml_append(ifctx, aml_return(aml_int(0)));
>> >> +        }
>> >> +        aml_append(method, ifctx);
>> >>      }
>> >>      aml_append(dev, method);
>> >>  }
>> >
>> >
>>
>>
>>
>



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 2/4] acpi: add fw_cfg file for TPM and PPI virtual memory device
  2018-06-25 15:20       ` Laszlo Ersek
@ 2018-06-26 10:38         ` Marc-André Lureau
  2018-06-26 10:54           ` Laszlo Ersek
  0 siblings, 1 reply; 40+ messages in thread
From: Marc-André Lureau @ 2018-06-26 10:38 UTC (permalink / raw)
  To: Laszlo Ersek
  Cc: Igor Mammedov, Eduardo Habkost, Stefan Berger,
	Michael S. Tsirkin, QEMU, Paolo Bonzini, Richard Henderson

Hi

On Mon, Jun 25, 2018 at 5:20 PM, Laszlo Ersek <lersek@redhat.com> wrote:
> On 06/21/18 12:10, Marc-André Lureau wrote:
>> Hi
>>
>> On Thu, Jun 21, 2018 at 12:00 PM, Igor Mammedov <imammedo@redhat.com> wrote:
>>> On Tue, 15 May 2018 14:14:31 +0200
>>> Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
>>>
>>>> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>>
>>>> To avoid having to hard code the base address of the PPI virtual
>>>> memory device we introduce a fw_cfg file etc/tpm/config that holds the
>>>> base address of the PPI device, the version of the PPI interface and
>>>> the version of the attached TPM.
>>> is it related to TPM_PPI_ADDR_BASE added in previous patch?
>>>
>>>>
>>>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>> [ Marc-André: renamed to etc/tpm/config, made it static, document it ]
>>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>>> ---
>>>>  include/hw/acpi/tpm.h |  3 +++
>>>>  hw/i386/acpi-build.c  | 17 +++++++++++++++++
>>>>  docs/specs/tpm.txt    | 20 ++++++++++++++++++++
>>>>  3 files changed, 40 insertions(+)
>>>>
>>>> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
>>>> index c082df7d1d..f79d68a77a 100644
>>>> --- a/include/hw/acpi/tpm.h
>>>> +++ b/include/hw/acpi/tpm.h
>>>> @@ -193,4 +193,7 @@ REG32(CRB_DATA_BUFFER, 0x80)
>>>>  #define TPM_PPI_ADDR_SIZE           0x400
>>>>  #define TPM_PPI_ADDR_BASE           0xFED45000
>>>>
>>>> +#define TPM_PPI_VERSION_NONE        0
>>>> +#define TPM_PPI_VERSION_1_30        1
>>>> +
>>>>  #endif /* HW_ACPI_TPM_H */
>>>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>>>> index 9bc6d97ea1..f6d447f03a 100644
>>>> --- a/hw/i386/acpi-build.c
>>>> +++ b/hw/i386/acpi-build.c
>>>> @@ -119,6 +119,12 @@ typedef struct AcpiBuildPciBusHotplugState {
>>>>      bool pcihp_bridge_en;
>>>>  } AcpiBuildPciBusHotplugState;
>>>>
>>>> +typedef struct FWCfgTPMConfig {
>>>> +    uint32_t tpmppi_address;
>>>> +    uint8_t tpm_version;
>>>> +    uint8_t tpmppi_version;
>>>> +} QEMU_PACKED FWCfgTPMConfig;
>>>> +
>>>>  static void init_common_fadt_data(Object *o, AcpiFadtData *data)
>>>>  {
>>>>      uint32_t io = object_property_get_uint(o, ACPI_PM_PROP_PM_IO_BASE, NULL);
>>>> @@ -2873,6 +2879,7 @@ void acpi_setup(void)
>>>>      AcpiBuildTables tables;
>>>>      AcpiBuildState *build_state;
>>>>      Object *vmgenid_dev;
>>>> +    static FWCfgTPMConfig tpm_config;
>>>>
>>>>      if (!pcms->fw_cfg) {
>>>>          ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
>>>> @@ -2907,6 +2914,16 @@ void acpi_setup(void)
>>>>      fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
>>>>                      tables.tcpalog->data, acpi_data_len(tables.tcpalog));
>>>>
>>>> +    if (tpm_find()) {
>>>> +        tpm_config = (FWCfgTPMConfig) {
>>>> +            .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE),
>>>> +            .tpm_version = cpu_to_le32(tpm_get_version(tpm_find())),
>>>> +            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_NONE)
>>>> +        };
>>>> +        fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config",
>>>> +                        &tpm_config, sizeof tpm_config);
>>>> +    }
>>> why it's in ACPI part of the code, shouldn't it be a part of device,
>>> could TPM be used without ACPI at all (-noacpi CLI option)?
>>>
>>> Wouldn't adding fwcfg entry unconditionally break migration?
>>
>> Because of unstable entry IDs? that could be problematic. (especially
>> during boot time) What do you think Laszlo?
>>
>> I guess we could have a "ppi" device property, that would imply having
>> the etc/tpm/config fw_cfg entry. We would enable it by default in
>> newer machine types (3.0?)
>
> Can we perhaps draw a parallel with "-device vmcoreinfo" here? For that
> device model, fw_cfg_add_file_callback() is called in the realize
> function, vmcoreinfo_realize(). If libvirt generates the identical
> cmdline on both ends of the migration, and uses the same machine type, I
> think the fw_cfg selectors should end up the same on both sides.

-device vmcoreinfo is a  standalone fw-cfg entry. PPI is tied to a
TPM, the fw-cfg entry is an implementation detail between qemu and
firmware. So I prefer the "ppi" device property. Wrt to migration,
that should be equivalent to -device vmcoreinfo (except that -device
vmcoreinfo is not enabled by default in newer machine types)

> Thanks
> Laszlo
>
>>>
>>>> +
>>>>      vmgenid_dev = find_vmgenid_dev();
>>>>      if (vmgenid_dev) {
>>>>          vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), pcms->fw_cfg,
>>>> diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt
>>>> index c230c4c93e..2ddb768084 100644
>>>> --- a/docs/specs/tpm.txt
>>>> +++ b/docs/specs/tpm.txt
>>>> @@ -20,6 +20,26 @@ QEMU files related to TPM TIS interface:
>>>>   - hw/tpm/tpm_tis.h
>>>>
>>>>
>>>> += fw_cfg interface =
>>>> +
>>>> +The bios/firmware may use the "etc/tpm/config" fw_cfg entry for
>>>> +configuring the guest appropriately.
>>>> +
>>>> +The entry of 6 bytes has the following content, in little-endian:
>>>> +
>>>> +    #define TPM_VERSION_UNSPEC          0
>>>> +    #define TPM_VERSION_1_2             1
>>>> +    #define TPM_VERSION_2_0             2
>>>> +
>>>> +    #define TPM_PPI_VERSION_NONE        0
>>>> +    #define TPM_PPI_VERSION_1_30        1
>>>> +
>>>> +    struct FWCfgTPMConfig {
>>>> +        uint32_t tpmppi_address;         /* PPI memory location */
>>>> +        uint8_t tpm_version;             /* TPM version */
>>>> +        uint8_t tpmppi_version;          /* PPI version */
>>>> +    };
>>>> +
>>>>  = ACPI Interface =
>>>>
>>>>  The TPM device is defined with ACPI ID "PNP0C31". QEMU builds a SSDT and passes
>>>
>>>
>>
>>
>>
>



-- 
Marc-André Lureau

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 2/4] acpi: add fw_cfg file for TPM and PPI virtual memory device
  2018-06-26 10:38         ` Marc-André Lureau
@ 2018-06-26 10:54           ` Laszlo Ersek
  0 siblings, 0 replies; 40+ messages in thread
From: Laszlo Ersek @ 2018-06-26 10:54 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Igor Mammedov, Eduardo Habkost, Stefan Berger,
	Michael S. Tsirkin, QEMU, Paolo Bonzini, Richard Henderson

On 06/26/18 12:38, Marc-André Lureau wrote:
> Hi
> 
> On Mon, Jun 25, 2018 at 5:20 PM, Laszlo Ersek <lersek@redhat.com> wrote:
>> On 06/21/18 12:10, Marc-André Lureau wrote:
>>> Hi
>>>
>>> On Thu, Jun 21, 2018 at 12:00 PM, Igor Mammedov <imammedo@redhat.com> wrote:
>>>> On Tue, 15 May 2018 14:14:31 +0200
>>>> Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
>>>>
>>>>> From: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>>>
>>>>> To avoid having to hard code the base address of the PPI virtual
>>>>> memory device we introduce a fw_cfg file etc/tpm/config that holds the
>>>>> base address of the PPI device, the version of the PPI interface and
>>>>> the version of the attached TPM.
>>>> is it related to TPM_PPI_ADDR_BASE added in previous patch?
>>>>
>>>>>
>>>>> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
>>>>> [ Marc-André: renamed to etc/tpm/config, made it static, document it ]
>>>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>>>> ---
>>>>>  include/hw/acpi/tpm.h |  3 +++
>>>>>  hw/i386/acpi-build.c  | 17 +++++++++++++++++
>>>>>  docs/specs/tpm.txt    | 20 ++++++++++++++++++++
>>>>>  3 files changed, 40 insertions(+)
>>>>>
>>>>> diff --git a/include/hw/acpi/tpm.h b/include/hw/acpi/tpm.h
>>>>> index c082df7d1d..f79d68a77a 100644
>>>>> --- a/include/hw/acpi/tpm.h
>>>>> +++ b/include/hw/acpi/tpm.h
>>>>> @@ -193,4 +193,7 @@ REG32(CRB_DATA_BUFFER, 0x80)
>>>>>  #define TPM_PPI_ADDR_SIZE           0x400
>>>>>  #define TPM_PPI_ADDR_BASE           0xFED45000
>>>>>
>>>>> +#define TPM_PPI_VERSION_NONE        0
>>>>> +#define TPM_PPI_VERSION_1_30        1
>>>>> +
>>>>>  #endif /* HW_ACPI_TPM_H */
>>>>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>>>>> index 9bc6d97ea1..f6d447f03a 100644
>>>>> --- a/hw/i386/acpi-build.c
>>>>> +++ b/hw/i386/acpi-build.c
>>>>> @@ -119,6 +119,12 @@ typedef struct AcpiBuildPciBusHotplugState {
>>>>>      bool pcihp_bridge_en;
>>>>>  } AcpiBuildPciBusHotplugState;
>>>>>
>>>>> +typedef struct FWCfgTPMConfig {
>>>>> +    uint32_t tpmppi_address;
>>>>> +    uint8_t tpm_version;
>>>>> +    uint8_t tpmppi_version;
>>>>> +} QEMU_PACKED FWCfgTPMConfig;
>>>>> +
>>>>>  static void init_common_fadt_data(Object *o, AcpiFadtData *data)
>>>>>  {
>>>>>      uint32_t io = object_property_get_uint(o, ACPI_PM_PROP_PM_IO_BASE, NULL);
>>>>> @@ -2873,6 +2879,7 @@ void acpi_setup(void)
>>>>>      AcpiBuildTables tables;
>>>>>      AcpiBuildState *build_state;
>>>>>      Object *vmgenid_dev;
>>>>> +    static FWCfgTPMConfig tpm_config;
>>>>>
>>>>>      if (!pcms->fw_cfg) {
>>>>>          ACPI_BUILD_DPRINTF("No fw cfg. Bailing out.\n");
>>>>> @@ -2907,6 +2914,16 @@ void acpi_setup(void)
>>>>>      fw_cfg_add_file(pcms->fw_cfg, ACPI_BUILD_TPMLOG_FILE,
>>>>>                      tables.tcpalog->data, acpi_data_len(tables.tcpalog));
>>>>>
>>>>> +    if (tpm_find()) {
>>>>> +        tpm_config = (FWCfgTPMConfig) {
>>>>> +            .tpmppi_address = cpu_to_le32(TPM_PPI_ADDR_BASE),
>>>>> +            .tpm_version = cpu_to_le32(tpm_get_version(tpm_find())),
>>>>> +            .tpmppi_version = cpu_to_le32(TPM_PPI_VERSION_NONE)
>>>>> +        };
>>>>> +        fw_cfg_add_file(pcms->fw_cfg, "etc/tpm/config",
>>>>> +                        &tpm_config, sizeof tpm_config);
>>>>> +    }
>>>> why it's in ACPI part of the code, shouldn't it be a part of device,
>>>> could TPM be used without ACPI at all (-noacpi CLI option)?
>>>>
>>>> Wouldn't adding fwcfg entry unconditionally break migration?
>>>
>>> Because of unstable entry IDs? that could be problematic. (especially
>>> during boot time) What do you think Laszlo?
>>>
>>> I guess we could have a "ppi" device property, that would imply having
>>> the etc/tpm/config fw_cfg entry. We would enable it by default in
>>> newer machine types (3.0?)
>>
>> Can we perhaps draw a parallel with "-device vmcoreinfo" here? For that
>> device model, fw_cfg_add_file_callback() is called in the realize
>> function, vmcoreinfo_realize(). If libvirt generates the identical
>> cmdline on both ends of the migration, and uses the same machine type, I
>> think the fw_cfg selectors should end up the same on both sides.
> 
> -device vmcoreinfo is a  standalone fw-cfg entry. PPI is tied to a
> TPM, the fw-cfg entry is an implementation detail between qemu and
> firmware. So I prefer the "ppi" device property.

Ah, right, sorry I got confused for a moment. The TPM device makes sense
without the (optional) Physical Presence Interface too.

Thanks,
Laszlo

> Wrt to migration,
> that should be equivalent to -device vmcoreinfo (except that -device
> vmcoreinfo is not enabled by default in newer machine types)
> 
>> Thanks
>> Laszlo
>>
>>>>
>>>>> +
>>>>>      vmgenid_dev = find_vmgenid_dev();
>>>>>      if (vmgenid_dev) {
>>>>>          vmgenid_add_fw_cfg(VMGENID(vmgenid_dev), pcms->fw_cfg,
>>>>> diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt
>>>>> index c230c4c93e..2ddb768084 100644
>>>>> --- a/docs/specs/tpm.txt
>>>>> +++ b/docs/specs/tpm.txt
>>>>> @@ -20,6 +20,26 @@ QEMU files related to TPM TIS interface:
>>>>>   - hw/tpm/tpm_tis.h
>>>>>
>>>>>
>>>>> += fw_cfg interface =
>>>>> +
>>>>> +The bios/firmware may use the "etc/tpm/config" fw_cfg entry for
>>>>> +configuring the guest appropriately.
>>>>> +
>>>>> +The entry of 6 bytes has the following content, in little-endian:
>>>>> +
>>>>> +    #define TPM_VERSION_UNSPEC          0
>>>>> +    #define TPM_VERSION_1_2             1
>>>>> +    #define TPM_VERSION_2_0             2
>>>>> +
>>>>> +    #define TPM_PPI_VERSION_NONE        0
>>>>> +    #define TPM_PPI_VERSION_1_30        1
>>>>> +
>>>>> +    struct FWCfgTPMConfig {
>>>>> +        uint32_t tpmppi_address;         /* PPI memory location */
>>>>> +        uint8_t tpm_version;             /* TPM version */
>>>>> +        uint8_t tpmppi_version;          /* PPI version */
>>>>> +    };
>>>>> +
>>>>>  = ACPI Interface =
>>>>>
>>>>>  The TPM device is defined with ACPI ID "PNP0C31". QEMU builds a SSDT and passes
>>>>
>>>>
>>>
>>>
>>>
>>
> 
> 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 4/4] tpm: add a fake ACPI memory clear interface
  2018-06-26  9:22         ` Marc-André Lureau
@ 2018-06-26 12:34           ` Igor Mammedov
  2018-06-26 12:47             ` Laszlo Ersek
  0 siblings, 1 reply; 40+ messages in thread
From: Igor Mammedov @ 2018-06-26 12:34 UTC (permalink / raw)
  To: Marc-André Lureau
  Cc: Laszlo Ersek, Eduardo Habkost, Michael S. Tsirkin, Stefan Berger,
	QEMU, Paolo Bonzini, Richard Henderson

On Tue, 26 Jun 2018 11:22:26 +0200
Marc-André Lureau <marcandre.lureau@gmail.com> wrote:

> On Thu, Jun 21, 2018 at 4:33 PM, Igor Mammedov <imammedo@redhat.com> wrote:
> > On Thu, 21 Jun 2018 15:24:44 +0200
> > Marc-André Lureau <marcandre.lureau@gmail.com> wrote:
> >  
> >> Hi
> >>
> >> On Thu, Jun 21, 2018 at 3:02 PM, Igor Mammedov <imammedo@redhat.com> wrote:  
> >> > On Tue, 15 May 2018 14:14:33 +0200
> >> > Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
> >> >  
> >> >> This allows to pass the last failing test from the Windows HLK TPM 2.0
> >> >> TCG PPI 1.3 tests.
> >> >>
> >> >> The interface is described in the "TCG Platform Reset Attack
> >> >> Mitigation Specification", chapter 6 "ACPI _DSM Function". Whether or
> >> >> not we should have a real implementation remains an open question to me.  
> >> > might it cause security issues?  
> >>
> >> Good question. If the guest assumes success of this operation perhaps.
> >> I'll check the spec.
> >>  
> >> > What are implications of faking it and how hard it's to implement thing
> >> > per spec?  
> >>
> >> Laszlo answerd that in "[Qemu-devel] investigating TPM for
> >> OVMF-on-QEMU"  2f2b) TCG Memory Clear Interface  
> > I get that it's optional, but we probably shouldn't advertise/fake
> > feature if it's not supported.  
> 
> As said in the commit message, the objective was to pass the Windows
> HLK test. If we don't want to advertize a fake interface, I am fine
> droping this patch. We'll have to revisit with Laszlo the work needed
> in the firmware to support it.
I think it would be safer to drop this patch.


> >  
> >>  
> >> >
> >> >  
> >> >> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> >> >> ---
> >> >>  hw/i386/acpi-build.c | 9 +++++++++
> >> >>  1 file changed, 9 insertions(+)
> >> >>
> >> >> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
> >> >> index 95be4f0710..392a1e50bd 100644
> >> >> --- a/hw/i386/acpi-build.c
> >> >> +++ b/hw/i386/acpi-build.c
> >> >> @@ -2072,6 +2072,15 @@ build_tpm_ppi(Aml *dev)
> >> >>              aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
> >> >>          }
> >> >>          aml_append(method, ifctx);
> >> >> +
> >> >> +       /* dummy MOR Memory Clear for the sake of WLK PPI test */
> >> >> +        ifctx = aml_if(
> >> >> +            aml_equal(aml_arg(0),
> >> >> +                      aml_touuid("376054ED-CC13-4675-901C-4756D7F2D45D")));
> >> >> +        {
> >> >> +            aml_append(ifctx, aml_return(aml_int(0)));
> >> >> +        }
> >> >> +        aml_append(method, ifctx);
> >> >>      }
> >> >>      aml_append(dev, method);
> >> >>  }  
> >> >
> >> >  
> >>
> >>
> >>  
> >  
> 
> 
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 4/4] tpm: add a fake ACPI memory clear interface
  2018-06-26 12:34           ` Igor Mammedov
@ 2018-06-26 12:47             ` Laszlo Ersek
  2018-06-26 15:22               ` Stefan Berger
  0 siblings, 1 reply; 40+ messages in thread
From: Laszlo Ersek @ 2018-06-26 12:47 UTC (permalink / raw)
  To: Igor Mammedov, Marc-André Lureau
  Cc: Eduardo Habkost, Michael S. Tsirkin, Stefan Berger, QEMU,
	Paolo Bonzini, Richard Henderson

On 06/26/18 14:34, Igor Mammedov wrote:
> On Tue, 26 Jun 2018 11:22:26 +0200
> Marc-André Lureau <marcandre.lureau@gmail.com> wrote:
> 
>> On Thu, Jun 21, 2018 at 4:33 PM, Igor Mammedov <imammedo@redhat.com> wrote:
>>> On Thu, 21 Jun 2018 15:24:44 +0200
>>> Marc-André Lureau <marcandre.lureau@gmail.com> wrote:
>>>  
>>>> Hi
>>>>
>>>> On Thu, Jun 21, 2018 at 3:02 PM, Igor Mammedov <imammedo@redhat.com> wrote:  
>>>>> On Tue, 15 May 2018 14:14:33 +0200
>>>>> Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
>>>>>  
>>>>>> This allows to pass the last failing test from the Windows HLK TPM 2.0
>>>>>> TCG PPI 1.3 tests.
>>>>>>
>>>>>> The interface is described in the "TCG Platform Reset Attack
>>>>>> Mitigation Specification", chapter 6 "ACPI _DSM Function". Whether or
>>>>>> not we should have a real implementation remains an open question to me.  
>>>>> might it cause security issues?  
>>>>
>>>> Good question. If the guest assumes success of this operation perhaps.
>>>> I'll check the spec.
>>>>  
>>>>> What are implications of faking it and how hard it's to implement thing
>>>>> per spec?  
>>>>
>>>> Laszlo answerd that in "[Qemu-devel] investigating TPM for
>>>> OVMF-on-QEMU"  2f2b) TCG Memory Clear Interface  
>>> I get that it's optional, but we probably shouldn't advertise/fake
>>> feature if it's not supported.  
>>
>> As said in the commit message, the objective was to pass the Windows
>> HLK test. If we don't want to advertize a fake interface, I am fine
>> droping this patch. We'll have to revisit with Laszlo the work needed
>> in the firmware to support it.
> I think it would be safer to drop this patch.

This is BTW a feature that's very difficult for OVMF to implement, but
(I think) near trivial for QEMU to implement. The feature is about
clearing all of the guest RAM to zero at reboot.

For the firmware, it's difficult to solve, because in the 32-bit PEI
phase, we don't map DRAM beyond 4GB, so we can't re-set memory to zero
via normal addressing. (For physical platforms, this is different,
because their PEI phases have PEI modules that initialize the memory
controller(s), so they have platform-specific means to clear RAM.) For
QEMU, on the other hand, the feature "shouldn't be hard (TM)", just
implement a reset handler that clears all RAMBlocks on the host side (or
some such :) ).

Thanks,
Laszlo

> 
> 
>>>  
>>>>  
>>>>>
>>>>>  
>>>>>> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
>>>>>> ---
>>>>>>  hw/i386/acpi-build.c | 9 +++++++++
>>>>>>  1 file changed, 9 insertions(+)
>>>>>>
>>>>>> diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
>>>>>> index 95be4f0710..392a1e50bd 100644
>>>>>> --- a/hw/i386/acpi-build.c
>>>>>> +++ b/hw/i386/acpi-build.c
>>>>>> @@ -2072,6 +2072,15 @@ build_tpm_ppi(Aml *dev)
>>>>>>              aml_append(ifctx, aml_return(aml_buffer(1, zerobyte)));
>>>>>>          }
>>>>>>          aml_append(method, ifctx);
>>>>>> +
>>>>>> +       /* dummy MOR Memory Clear for the sake of WLK PPI test */
>>>>>> +        ifctx = aml_if(
>>>>>> +            aml_equal(aml_arg(0),
>>>>>> +                      aml_touuid("376054ED-CC13-4675-901C-4756D7F2D45D")));
>>>>>> +        {
>>>>>> +            aml_append(ifctx, aml_return(aml_int(0)));
>>>>>> +        }
>>>>>> +        aml_append(method, ifctx);
>>>>>>      }
>>>>>>      aml_append(dev, method);
>>>>>>  }  
>>>>>
>>>>>  
>>>>
>>>>
>>>>  
>>>  
>>
>>
>>
> 

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [Qemu-devel] [PATCH v3 4/4] tpm: add a fake ACPI memory clear interface
  2018-06-26 12:47             ` Laszlo Ersek
@ 2018-06-26 15:22               ` Stefan Berger
  0 siblings, 0 replies; 40+ messages in thread
From: Stefan Berger @ 2018-06-26 15:22 UTC (permalink / raw)
  To: qemu-devel

On 06/26/2018 08:47 AM, Laszlo Ersek wrote:
> On 06/26/18 14:34, Igor Mammedov wrote:
>> On Tue, 26 Jun 2018 11:22:26 +0200
>> Marc-André Lureau <marcandre.lureau@gmail.com> wrote:
>>
>>> On Thu, Jun 21, 2018 at 4:33 PM, Igor Mammedov <imammedo@redhat.com> wrote:
>>>> On Thu, 21 Jun 2018 15:24:44 +0200
>>>> Marc-André Lureau <marcandre.lureau@gmail.com> wrote:
>>>>   
>>>>> Hi
>>>>>
>>>>> On Thu, Jun 21, 2018 at 3:02 PM, Igor Mammedov <imammedo@redhat.com> wrote:
>>>>>> On Tue, 15 May 2018 14:14:33 +0200
>>>>>> Marc-André Lureau <marcandre.lureau@redhat.com> wrote:
>>>>>>   
>>>>>>> This allows to pass the last failing test from the Windows HLK TPM 2.0
>>>>>>> TCG PPI 1.3 tests.
>>>>>>>
>>>>>>> The interface is described in the "TCG Platform Reset Attack
>>>>>>> Mitigation Specification", chapter 6 "ACPI _DSM Function". Whether or
>>>>>>> not we should have a real implementation remains an open question to me.
>>>>>> might it cause security issues?
>>>>> Good question. If the guest assumes success of this operation perhaps.
>>>>> I'll check the spec.
>>>>>   
>>>>>> What are implications of faking it and how hard it's to implement thing
>>>>>> per spec?
>>>>> Laszlo answerd that in "[Qemu-devel] investigating TPM for
>>>>> OVMF-on-QEMU"  2f2b) TCG Memory Clear Interface
>>>> I get that it's optional, but we probably shouldn't advertise/fake
>>>> feature if it's not supported.
>>> As said in the commit message, the objective was to pass the Windows
>>> HLK test. If we don't want to advertize a fake interface, I am fine
>>> droping this patch. We'll have to revisit with Laszlo the work needed
>>> in the firmware to support it.
>> I think it would be safer to drop this patch.
> This is BTW a feature that's very difficult for OVMF to implement, but
> (I think) near trivial for QEMU to implement. The feature is about
> clearing all of the guest RAM to zero at reboot.
>
> For the firmware, it's difficult to solve, because in the 32-bit PEI
> phase, we don't map DRAM beyond 4GB, so we can't re-set memory to zero
> via normal addressing. (For physical platforms, this is different,
> because their PEI phases have PEI modules that initialize the memory
> controller(s), so they have platform-specific means to clear RAM.) For
> QEMU, on the other hand, the feature "shouldn't be hard (TM)", just
> implement a reset handler that clears all RAMBlocks on the host side (or
> some such :) ).

Except don't clear that PPI memory device where the user/ACPI posted the 
command for the firmware to act upon.

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2018-06-26 15:22 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-15 12:14 [Qemu-devel] [PATCH v3 0/4] Add support for TPM Physical Presence interface Marc-André Lureau
2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 1/4] tpm: implement virtual memory device for TPM PPI Marc-André Lureau
2018-05-15 14:19   ` Stefan Berger
2018-06-21  9:49   ` Igor Mammedov
2018-06-21 10:51     ` Marc-André Lureau
2018-06-21 13:59       ` Igor Mammedov
2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 2/4] acpi: add fw_cfg file for TPM and PPI virtual memory device Marc-André Lureau
2018-06-21 10:00   ` Igor Mammedov
2018-06-21 10:10     ` Marc-André Lureau
2018-06-21 13:55       ` Igor Mammedov
2018-06-22  0:16       ` Laszlo Ersek
2018-06-25 15:20       ` Laszlo Ersek
2018-06-26 10:38         ` Marc-André Lureau
2018-06-26 10:54           ` Laszlo Ersek
2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 3/4] acpi: build TPM Physical Presence interface Marc-André Lureau
2018-06-20 14:08   ` Michael S. Tsirkin
2018-06-20 14:35     ` Marc-André Lureau
2018-06-20 15:08       ` Laszlo Ersek
2018-06-20 15:31       ` Michael S. Tsirkin
2018-06-20 16:37       ` Stefan Berger
2018-06-21 12:54   ` Igor Mammedov
2018-06-21 13:21     ` Marc-André Lureau
2018-06-21 13:22       ` Marc-André Lureau
2018-06-21 14:13         ` Marc-André Lureau
2018-06-21 14:27           ` Igor Mammedov
2018-06-21 13:48       ` Stefan Berger
2018-06-21 14:23       ` Igor Mammedov
2018-06-21 17:10         ` Marc-André Lureau
2018-06-21 17:36           ` Stefan Berger
2018-06-22 13:40           ` Igor Mammedov
2018-05-15 12:14 ` [Qemu-devel] [PATCH v3 4/4] tpm: add a fake ACPI memory clear interface Marc-André Lureau
2018-06-21 13:02   ` Igor Mammedov
2018-06-21 13:24     ` Marc-André Lureau
2018-06-21 13:59       ` Stefan Berger
2018-06-21 14:33       ` Igor Mammedov
2018-06-26  9:22         ` Marc-André Lureau
2018-06-26 12:34           ` Igor Mammedov
2018-06-26 12:47             ` Laszlo Ersek
2018-06-26 15:22               ` Stefan Berger
2018-06-20 13:11 ` [Qemu-devel] [PATCH v3 0/4] Add support for TPM Physical Presence interface Marc-André Lureau

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.