diff --git a/delete-the-in-tpm.txt.patch b/delete-the-in-tpm.txt.patch new file mode 100644 index 0000000000000000000000000000000000000000..6ae808ad8539fbb7cef401ffb05c49ceb3f63556 --- /dev/null +++ b/delete-the-in-tpm.txt.patch @@ -0,0 +1,25 @@ +From 7256d5cd2b744156b74612c61a41f56b0d414374 Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Wed, 29 Jul 2020 08:45:50 +0000 +Subject: [PATCH] delete the in tpm.txt + +--- + docs/specs/tpm.txt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt +index 5d8c26b1..9c8cca04 100644 +--- a/docs/specs/tpm.txt ++++ b/docs/specs/tpm.txt +@@ -89,7 +89,7 @@ TPM upon reboot. The PPI specification defines the operation requests and the + actions the firmware has to take. The system administrator passes the operation + request number to the firmware through an ACPI interface which writes this + number to a memory location that the firmware knows. Upon reboot, the firmware +-finds the number and sends commands to the the TPM. The firmware writes the TPM ++finds the number and sends commands to the TPM. The firmware writes the TPM + result code and the operation request number to a memory location that ACPI can + read from and pass the result on to the administrator. + +-- +2.23.0 + diff --git a/docs-specs-tpm-reST-ify-TPM-documentation.patch b/docs-specs-tpm-reST-ify-TPM-documentation.patch new file mode 100644 index 0000000000000000000000000000000000000000..69c33de2aaa3afbedf4596e83934d223f297894e --- /dev/null +++ b/docs-specs-tpm-reST-ify-TPM-documentation.patch @@ -0,0 +1,992 @@ +From 6e8a3ff6ed88c353b30a356411694cb3fea9c607 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 21 Jan 2020 10:29:35 -0500 +Subject: [PATCH 3422/5109] docs/specs/tpm: reST-ify TPM documentation +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Marc-André Lureau +Reviewed-by: Stefan Berger +Message-Id: <20200121152935.649898-7-stefanb@linux.ibm.com> +Signed-off-by: David Gibson +--- + docs/specs/index.rst | 1 + + docs/specs/tpm.rst | 503 +++++++++++++++++++++++++++++++++++++++++++ + docs/specs/tpm.txt | 445 -------------------------------------- + 3 files changed, 504 insertions(+), 445 deletions(-) + create mode 100644 docs/specs/tpm.rst + delete mode 100644 docs/specs/tpm.txt + +diff --git a/docs/specs/index.rst b/docs/specs/index.rst +index 984ba44029..de46a8b5e7 100644 +--- a/docs/specs/index.rst ++++ b/docs/specs/index.rst +@@ -13,3 +13,4 @@ Contents: + ppc-xive + ppc-spapr-xive + acpi_hw_reduced_hotplug ++ tpm +diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst +new file mode 100644 +index 0000000000..2bdf637f55 +--- /dev/null ++++ b/docs/specs/tpm.rst +@@ -0,0 +1,503 @@ ++=============== ++QEMU TPM Device ++=============== ++ ++Guest-side hardware interface ++============================= ++ ++TIS interface ++------------- ++ ++The QEMU TPM emulation implements a TPM TIS hardware interface ++following the Trusted Computing Group's specification "TCG PC Client ++Specific TPM Interface Specification (TIS)", Specification Version ++1.3, 21 March 2013. (see the `TIS specification`_, or a later version ++of it). ++ ++The TIS interface makes a memory mapped IO region in the area ++0xfed40000-0xfed44fff available to the guest operating system. ++ ++QEMU files related to TPM TIS interface: ++ - ``hw/tpm/tpm_tis.c`` ++ - ``hw/tpm/tpm_tis.h`` ++ ++CRB interface ++------------- ++ ++QEMU also implements a TPM CRB interface following the Trusted ++Computing Group's specification "TCG PC Client Platform TPM Profile ++(PTP) Specification", Family "2.0", Level 00 Revision 01.03 v22, May ++22, 2017. (see the `CRB specification`_, or a later version of it) ++ ++The CRB interface makes a memory mapped IO region in the area ++0xfed40000-0xfed40fff (1 locality) available to the guest ++operating system. ++ ++QEMU files related to TPM CRB interface: ++ - ``hw/tpm/tpm_crb.c`` ++ ++SPAPR interface ++--------------- ++ ++pSeries (ppc64) machines offer a tpm-spapr device model. ++ ++QEMU files related to the SPAPR interface: ++ - ``hw/tpm/tpm_spapr.c`` ++ ++fw_cfg interface ++================ ++ ++The bios/firmware may read the ``"etc/tpm/config"`` fw_cfg entry for ++configuring the guest appropriately. ++ ++The entry of 6 bytes has the following content, in little-endian: ++ ++.. code-block:: c ++ ++ #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 it into the guest through the fw_cfg device. The device ++description contains the base address of the TIS interface 0xfed40000 ++and the size of the MMIO area (0x5000). In case a TPM2 is used by ++QEMU, a TPM2 ACPI table is also provided. The device is described to ++be used in polling mode rather than interrupt mode primarily because ++no unused IRQ could be found. ++ ++To support measurement logs to be written by the firmware, ++e.g. SeaBIOS, a TCPA table is implemented. This table provides a 64kb ++buffer where the firmware can write its log into. For TPM 2 only a ++more recent version of the TPM2 table provides support for ++measurements logs and a TCPA table does not need to be created. ++ ++The TCPA and TPM2 ACPI tables follow the Trusted Computing Group ++specification "TCG ACPI Specification" Family "1.2" and "2.0", Level ++00 Revision 00.37. (see the `ACPI specification`_, or a later version ++of it) ++ ++ACPI PPI Interface ++------------------ ++ ++QEMU supports the Physical Presence Interface (PPI) for TPM 1.2 and ++TPM 2. This interface requires ACPI and firmware support. (see the ++`PPI specification`_) ++ ++PPI enables a system administrator (root) to request a modification to ++the TPM upon reboot. The PPI specification defines the operation ++requests and the actions the firmware has to take. The system ++administrator passes the operation request number to the firmware ++through an ACPI interface which writes this number to a memory ++location that the firmware knows. Upon reboot, the firmware finds the ++number and sends commands to the TPM. The firmware writes the TPM ++result code and the operation request number to a memory location that ++ACPI can read from and pass the result on to the administrator. ++ ++The PPI specification defines a set of mandatory and optional ++operations for the firmware to implement. The ACPI interface also ++allows an administrator to list the supported operations. In QEMU the ++ACPI code is generated by QEMU, yet the firmware needs to implement ++support on a per-operations basis, and different firmwares may support ++a different subset. Therefore, QEMU introduces the virtual memory ++device for PPI where the firmware can indicate which operations it ++supports and ACPI can enable the ones that are supported and disable ++all others. This interface lies in main memory and has the following ++layout: ++ ++ +-------------+--------+--------+-------------------------------------------+ ++ | Field | Length | Offset | Description | ++ +=============+========+========+===========================================+ ++ | ``func`` | 0x100 | 0x000 | Firmware sets values for each supported | ++ | | | | operation. See defined values below. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``ppin`` | 0x1 | 0x100 | SMI interrupt to use. Set by firmware. | ++ | | | | Not supported. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``ppip`` | 0x4 | 0x101 | ACPI function index to pass to SMM code. | ++ | | | | Set by ACPI. Not supported. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``pprp`` | 0x4 | 0x105 | Result of last executed operation. Set by | ++ | | | | firmware. See function index 5 for values.| ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``pprq`` | 0x4 | 0x109 | Operation request number to execute. See | ++ | | | | 'Physical Presence Interface Operation | ++ | | | | Summary' tables in specs. Set by ACPI. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``pprm`` | 0x4 | 0x10d | Operation request optional parameter. | ++ | | | | Values depend on operation. Set by ACPI. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``lppr`` | 0x4 | 0x111 | Last executed operation request number. | ++ | | | | Copied from pprq field by firmware. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``fret`` | 0x4 | 0x115 | Result code from SMM function. | ++ | | | | Not supported. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``res1`` | 0x40 | 0x119 | Reserved for future use | ++ +-------------+--------+--------+-------------------------------------------+ ++ |``next_step``| 0x1 | 0x159 | Operation to execute after reboot by | ++ | | | | firmware. Used by firmware. | ++ +-------------+--------+--------+-------------------------------------------+ ++ | ``movv`` | 0x1 | 0x15a | Memory overwrite variable | ++ +-------------+--------+--------+-------------------------------------------+ ++ ++The following values are supported for the ``func`` field. They ++correspond to the values used by ACPI function index 8. ++ ++ +----------+-------------------------------------------------------------+ ++ | Value | Description | ++ +==========+=============================================================+ ++ | 0 | Operation is not implemented. | ++ +----------+-------------------------------------------------------------+ ++ | 1 | Operation is only accessible through firmware. | ++ +----------+-------------------------------------------------------------+ ++ | 2 | Operation is blocked for OS by firmware configuration. | ++ +----------+-------------------------------------------------------------+ ++ | 3 | Operation is allowed and physically present user required. | ++ +----------+-------------------------------------------------------------+ ++ | 4 | Operation is allowed and physically present user is not | ++ | | required. | ++ +----------+-------------------------------------------------------------+ ++ ++The location of the table is given by the fw_cfg ``tpmppi_address`` ++field. The PPI memory region size is 0x400 (``TPM_PPI_ADDR_SIZE``) to ++leave enough room for future updates. ++ ++QEMU files related to TPM ACPI tables: ++ - ``hw/i386/acpi-build.c`` ++ - ``include/hw/acpi/tpm.h`` ++ ++TPM backend devices ++=================== ++ ++The TPM implementation is split into two parts, frontend and ++backend. The frontend part is the hardware interface, such as the TPM ++TIS interface described earlier, and the other part is the TPM backend ++interface. The backend interfaces implement the interaction with a TPM ++device, which may be a physical or an emulated device. The split ++between the front- and backend devices allows a frontend to be ++connected with any available backend. This enables the TIS interface ++to be used with the passthrough backend or the swtpm backend. ++ ++QEMU files related to TPM backends: ++ - ``backends/tpm.c`` ++ - ``include/sysemu/tpm_backend.h`` ++ - ``include/sysemu/tpm_backend_int.h`` ++ ++The QEMU TPM passthrough device ++------------------------------- ++ ++In case QEMU is run on Linux as the host operating system it is ++possible to make the hardware TPM device available to a single QEMU ++guest. In this case the user must make sure that no other program is ++using the device, e.g., /dev/tpm0, before trying to start QEMU with ++it. ++ ++The passthrough driver uses the host's TPM device for sending TPM ++commands and receiving responses from. Besides that it accesses the ++TPM device's sysfs entry for support of command cancellation. Since ++none of the state of a hardware TPM can be migrated between hosts, ++virtual machine migration is disabled when the TPM passthrough driver ++is used. ++ ++Since the host's TPM device will already be initialized by the host's ++firmware, certain commands, e.g. ``TPM_Startup()``, sent by the ++virtual firmware for device initialization, will fail. In this case ++the firmware should not use the TPM. ++ ++Sharing the device with the host is generally not a recommended usage ++scenario for a TPM device. The primary reason for this is that two ++operating systems can then access the device's single set of ++resources, such as platform configuration registers ++(PCRs). Applications or kernel security subsystems, such as the Linux ++Integrity Measurement Architecture (IMA), are not expecting to share ++PCRs. ++ ++QEMU files related to the TPM passthrough device: ++ - ``hw/tpm/tpm_passthrough.c`` ++ - ``hw/tpm/tpm_util.c`` ++ - ``hw/tpm/tpm_util.h`` ++ ++ ++Command line to start QEMU with the TPM passthrough device using the host's ++hardware TPM ``/dev/tpm0``: ++ ++.. code-block:: console ++ ++ qemu-system-x86_64 -display sdl -accel kvm \ ++ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ ++ -tpmdev passthrough,id=tpm0,path=/dev/tpm0 \ ++ -device tpm-tis,tpmdev=tpm0 test.img ++ ++ ++The following commands should result in similar output inside the VM ++with a Linux kernel that either has the TPM TIS driver built-in or ++available as a module: ++ ++.. code-block:: console ++ ++ # dmesg | grep -i tpm ++ [ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) ++ ++ # dmesg | grep TCPA ++ [ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ ++ BXPCTCPA 0000001 BXPC 00000001) ++ ++ # ls -l /dev/tpm* ++ crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 ++ ++ # find /sys/devices/ | grep pcrs$ | xargs cat ++ PCR-00: 35 4E 3B CE 23 9F 38 59 ... ++ ... ++ PCR-23: 00 00 00 00 00 00 00 00 ... ++ ++The QEMU TPM emulator device ++---------------------------- ++ ++The TPM emulator device uses an external TPM emulator called 'swtpm' ++for sending TPM commands to and receiving responses from. The swtpm ++program must have been started before trying to access it through the ++TPM emulator with QEMU. ++ ++The TPM emulator implements a command channel for transferring TPM ++commands and responses as well as a control channel over which control ++commands can be sent. (see the `SWTPM protocol`_ specification) ++ ++The control channel serves the purpose of resetting, initializing, and ++migrating the TPM state, among other things. ++ ++The swtpm program behaves like a hardware TPM and therefore needs to ++be initialized by the firmware running inside the QEMU virtual ++machine. One necessary step for initializing the device is to send ++the TPM_Startup command to it. SeaBIOS, for example, has been ++instrumented to initialize a TPM 1.2 or TPM 2 device using this ++command. ++ ++QEMU files related to the TPM emulator device: ++ - ``hw/tpm/tpm_emulator.c`` ++ - ``hw/tpm/tpm_util.c`` ++ - ``hw/tpm/tpm_util.h`` ++ ++The following commands start the swtpm with a UnixIO control channel over ++a socket interface. They do not need to be run as root. ++ ++.. code-block:: console ++ ++ mkdir /tmp/mytpm1 ++ swtpm socket --tpmstate dir=/tmp/mytpm1 \ ++ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ ++ --log level=20 ++ ++Command line to start QEMU with the TPM emulator device communicating ++with the swtpm (x86): ++ ++.. code-block:: console ++ ++ qemu-system-x86_64 -display sdl -accel kvm \ ++ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-tis,tpmdev=tpm0 test.img ++ ++In case a pSeries machine is emulated, use the following command line: ++ ++.. code-block:: console ++ ++ qemu-system-ppc64 -display sdl -machine pseries,accel=kvm \ ++ -m 1024 -bios slof.bin -boot menu=on \ ++ -nodefaults -device VGA -device pci-ohci -device usb-kbd \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-spapr,tpmdev=tpm0 \ ++ -device spapr-vscsi,id=scsi0,reg=0x00002000 \ ++ -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ ++ -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 ++ ++In case SeaBIOS is used as firmware, it should show the TPM menu item ++after entering the menu with 'ESC'. ++ ++.. code-block:: console ++ ++ Select boot device: ++ 1. DVD/CD [ata1-0: QEMU DVD-ROM ATAPI-4 DVD/CD] ++ [...] ++ 5. Legacy option rom ++ ++ t. TPM Configuration ++ ++The following commands should result in similar output inside the VM ++with a Linux kernel that either has the TPM TIS driver built-in or ++available as a module: ++ ++.. code-block:: console ++ ++ # dmesg | grep -i tpm ++ [ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) ++ ++ # dmesg | grep TCPA ++ [ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ ++ BXPCTCPA 0000001 BXPC 00000001) ++ ++ # ls -l /dev/tpm* ++ crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 ++ ++ # find /sys/devices/ | grep pcrs$ | xargs cat ++ PCR-00: 35 4E 3B CE 23 9F 38 59 ... ++ ... ++ PCR-23: 00 00 00 00 00 00 00 00 ... ++ ++Migration with the TPM emulator ++=============================== ++ ++The TPM emulator supports the following types of virtual machine ++migration: ++ ++- VM save / restore (migration into a file) ++- Network migration ++- Snapshotting (migration into storage like QoW2 or QED) ++ ++The following command sequences can be used to test VM save / restore. ++ ++In a 1st terminal start an instance of a swtpm using the following command: ++ ++.. code-block:: console ++ ++ mkdir /tmp/mytpm1 ++ swtpm socket --tpmstate dir=/tmp/mytpm1 \ ++ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ ++ --log level=20 --tpm2 ++ ++In a 2nd terminal start the VM: ++ ++.. code-block:: console ++ ++ qemu-system-x86_64 -display sdl -accel kvm \ ++ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-tis,tpmdev=tpm0 \ ++ -monitor stdio \ ++ test.img ++ ++Verify that the attached TPM is working as expected using applications ++inside the VM. ++ ++To store the state of the VM use the following command in the QEMU ++monitor in the 2nd terminal: ++ ++.. code-block:: console ++ ++ (qemu) migrate "exec:cat > testvm.bin" ++ (qemu) quit ++ ++At this point a file called ``testvm.bin`` should exists and the swtpm ++and QEMU processes should have ended. ++ ++To test 'VM restore' you have to start the swtpm with the same ++parameters as before. If previously a TPM 2 [--tpm2] was saved, --tpm2 ++must now be passed again on the command line. ++ ++In the 1st terminal restart the swtpm with the same command line as ++before: ++ ++.. code-block:: console ++ ++ swtpm socket --tpmstate dir=/tmp/mytpm1 \ ++ --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ ++ --log level=20 --tpm2 ++ ++In the 2nd terminal restore the state of the VM using the additional ++'-incoming' option. ++ ++.. code-block:: console ++ ++ qemu-system-x86_64 -display sdl -accel kvm \ ++ -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-tis,tpmdev=tpm0 \ ++ -incoming "exec:cat < testvm.bin" \ ++ test.img ++ ++Troubleshooting migration ++------------------------- ++ ++There are several reasons why migration may fail. In case of problems, ++please ensure that the command lines adhere to the following rules ++and, if possible, that identical versions of QEMU and swtpm are used ++at all times. ++ ++VM save and restore: ++ ++ - QEMU command line parameters should be identical apart from the ++ '-incoming' option on VM restore ++ ++ - swtpm command line parameters should be identical ++ ++VM migration to 'localhost': ++ ++ - QEMU command line parameters should be identical apart from the ++ '-incoming' option on the destination side ++ ++ - swtpm command line parameters should point to two different ++ directories on the source and destination swtpm (--tpmstate dir=...) ++ (especially if different versions of libtpms were to be used on the ++ same machine). ++ ++VM migration across the network: ++ ++ - QEMU command line parameters should be identical apart from the ++ '-incoming' option on the destination side ++ ++ - swtpm command line parameters should be identical ++ ++VM Snapshotting: ++ - QEMU command line parameters should be identical ++ ++ - swtpm command line parameters should be identical ++ ++ ++Besides that, migration failure reasons on the swtpm level may include ++the following: ++ ++ - the versions of the swtpm on the source and destination sides are ++ incompatible ++ ++ - downgrading of TPM state may not be supported ++ ++ - the source and destination libtpms were compiled with different ++ compile-time options and the destination side refuses to accept the ++ state ++ ++ - different migration keys are used on the source and destination side ++ and the destination side cannot decrypt the migrated state ++ (swtpm ... --migration-key ... ) ++ ++ ++.. _TIS specification: ++ https://trustedcomputinggroup.org/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/ ++ ++.. _CRB specification: ++ https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/ ++ ++ ++.. _ACPI specification: ++ https://trustedcomputinggroup.org/tcg-acpi-specification/ ++ ++.. _PPI specification: ++ https://trustedcomputinggroup.org/resource/tcg-physical-presence-interface-specification/ ++ ++.. _SWTPM protocol: ++ https://github.com/stefanberger/swtpm/blob/master/man/man3/swtpm_ioctls.pod +diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt +deleted file mode 100644 +index 9c3e67d8a7..0000000000 +--- a/docs/specs/tpm.txt ++++ /dev/null +@@ -1,445 +0,0 @@ +-QEMU TPM Device +-=============== +- +-= Guest-side Hardware Interface = +- +-The QEMU TPM emulation implements a TPM TIS hardware interface following the +-Trusted Computing Group's specification "TCG PC Client Specific TPM Interface +-Specification (TIS)", Specification Version 1.3, 21 March 2013. This +-specification, or a later version of it, can be accessed from the following +-URL: +- +-https://trustedcomputinggroup.org/pc-client-work-group-pc-client-specific-tpm-interface-specification-tis/ +- +-The TIS interface makes a memory mapped IO region in the area 0xfed40000 - +-0xfed44fff available to the guest operating system. +- +- +-QEMU files related to TPM TIS interface: +- - hw/tpm/tpm_tis.c +- - hw/tpm/tpm_tis.h +- +- +-QEMU also implements a TPM CRB interface following the Trusted Computing +-Group's specification "TCG PC Client Platform TPM Profile (PTP) +-Specification", Family "2.0", Level 00 Revision 01.03 v22, May 22, 2017. +-This specification, or a later version of it, can be accessed from the +-following URL: +- +-https://trustedcomputinggroup.org/resource/pc-client-platform-tpm-profile-ptp-specification/ +- +-The CRB interface makes a memory mapped IO region in the area 0xfed40000 - +-0xfed40fff (1 locality) available to the guest operating system. +- +-QEMU files related to TPM CRB interface: +- - hw/tpm/tpm_crb.c +- +- +-pSeries (ppc64) machines offer a tpm-spapr device model. +- +-QEMU files related to the SPAPR interface: +- - hw/tpm/tpm_spapr.c +- +-= fw_cfg interface = +- +-The bios/firmware may read 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 +-it into the guest through the fw_cfg device. The device description contains +-the base address of the TIS interface 0xfed40000 and the size of the MMIO area +-(0x5000). In case a TPM2 is used by QEMU, a TPM2 ACPI table is also provided. +-The device is described to be used in polling mode rather than interrupt mode +-primarily because no unused IRQ could be found. +- +-To support measurement logs to be written by the firmware, e.g. SeaBIOS, a TCPA +-table is implemented. This table provides a 64kb buffer where the firmware can +-write its log into. For TPM 2 only a more recent version of the TPM2 table +-provides support for measurements logs and a TCPA table does not need to be +-created. +- +-The TCPA and TPM2 ACPI tables follow the Trusted Computing Group specification +-"TCG ACPI Specification" Family "1.2" and "2.0", Level 00 Revision 00.37. This +-specification, or a later version of it, can be accessed from the following +-URL: +- +-https://trustedcomputinggroup.org/tcg-acpi-specification/ +- +-== ACPI PPI Interface == +- +-QEMU supports the Physical Presence Interface (PPI) for TPM 1.2 and TPM 2. This +-interface requires ACPI and firmware support. The specification can be found at +-the following URL: +- +-https://trustedcomputinggroup.org/resource/tcg-physical-presence-interface-specification/ +- +-PPI enables a system administrator (root) to request a modification to the +-TPM upon reboot. The PPI specification defines the operation requests and the +-actions the firmware has to take. The system administrator passes the operation +-request number to the firmware through an ACPI interface which writes this +-number to a memory location that the firmware knows. Upon reboot, the firmware +-finds the number and sends commands to the TPM. The firmware writes the TPM +-result code and the operation request number to a memory location that ACPI can +-read from and pass the result on to the administrator. +- +-The PPI specification defines a set of mandatory and optional operations for +-the firmware to implement. The ACPI interface also allows an administrator to +-list the supported operations. In QEMU the ACPI code is generated by QEMU, yet +-the firmware needs to implement support on a per-operations basis, and +-different firmwares may support a different subset. Therefore, QEMU introduces +-the virtual memory device for PPI where the firmware can indicate which +-operations it supports and ACPI can enable the ones that are supported and +-disable all others. This interface lies in main memory and has the following +-layout: +- +- +----------+--------+--------+-------------------------------------------+ +- | Field | Length | Offset | Description | +- +----------+--------+--------+-------------------------------------------+ +- | func | 0x100 | 0x000 | Firmware sets values for each supported | +- | | | | operation. See defined values below. | +- +----------+--------+--------+-------------------------------------------+ +- | ppin | 0x1 | 0x100 | SMI interrupt to use. Set by firmware. | +- | | | | Not supported. | +- +----------+--------+--------+-------------------------------------------+ +- | ppip | 0x4 | 0x101 | ACPI function index to pass to SMM code. | +- | | | | Set by ACPI. Not supported. | +- +----------+--------+--------+-------------------------------------------+ +- | pprp | 0x4 | 0x105 | Result of last executed operation. Set by | +- | | | | firmware. See function index 5 for values.| +- +----------+--------+--------+-------------------------------------------+ +- | pprq | 0x4 | 0x109 | Operation request number to execute. See | +- | | | | 'Physical Presence Interface Operation | +- | | | | Summary' tables in specs. Set by ACPI. | +- +----------+--------+--------+-------------------------------------------+ +- | pprm | 0x4 | 0x10d | Operation request optional parameter. | +- | | | | Values depend on operation. Set by ACPI. | +- +----------+--------+--------+-------------------------------------------+ +- | lppr | 0x4 | 0x111 | Last executed operation request number. | +- | | | | Copied from pprq field by firmware. | +- +----------+--------+--------+-------------------------------------------+ +- | fret | 0x4 | 0x115 | Result code from SMM function. | +- | | | | Not supported. | +- +----------+--------+--------+-------------------------------------------+ +- | res1 | 0x40 | 0x119 | Reserved for future use | +- +----------+--------+--------+-------------------------------------------+ +- | next_step| 0x1 | 0x159 | Operation to execute after reboot by | +- | | | | firmware. Used by firmware. | +- +----------+--------+--------+-------------------------------------------+ +- | movv | 0x1 | 0x15a | Memory overwrite variable | +- +----------+--------+--------+-------------------------------------------+ +- +- The following values are supported for the 'func' field. They correspond +- to the values used by ACPI function index 8. +- +- +----------+-------------------------------------------------------------+ +- | value | Description | +- +----------+-------------------------------------------------------------+ +- | 0 | Operation is not implemented. | +- +----------+-------------------------------------------------------------+ +- | 1 | Operation is only accessible through firmware. | +- +----------+-------------------------------------------------------------+ +- | 2 | Operation is blocked for OS by firmware configuration. | +- +----------+-------------------------------------------------------------+ +- | 3 | Operation is allowed and physically present user required. | +- +----------+-------------------------------------------------------------+ +- | 4 | Operation is allowed and physically present user is not | +- | | required. | +- +----------+-------------------------------------------------------------+ +- +-The location of the table is given by the fw_cfg tpmppi_address field. +-The PPI memory region size is 0x400 (TPM_PPI_ADDR_SIZE) to leave +-enough room for future updates. +- +- +-QEMU files related to TPM ACPI tables: +- - hw/i386/acpi-build.c +- - include/hw/acpi/tpm.h +- +- +-= TPM backend devices = +- +-The TPM implementation is split into two parts, frontend and backend. The +-frontend part is the hardware interface, such as the TPM TIS interface +-described earlier, and the other part is the TPM backend interface. The backend +-interfaces implement the interaction with a TPM device, which may be a physical +-or an emulated device. The split between the front- and backend devices allows +-a frontend to be connected with any available backend. This enables the TIS +-interface to be used with the passthrough backend or the (future) swtpm backend. +- +- +-QEMU files related to TPM backends: +- - backends/tpm.c +- - include/sysemu/tpm_backend.h +- - include/sysemu/tpm_backend_int.h +- +- +-== The QEMU TPM passthrough device == +- +-In case QEMU is run on Linux as the host operating system it is possible to +-make the hardware TPM device available to a single QEMU guest. In this case the +-user must make sure that no other program is using the device, e.g., /dev/tpm0, +-before trying to start QEMU with it. +- +-The passthrough driver uses the host's TPM device for sending TPM commands +-and receiving responses from. Besides that it accesses the TPM device's sysfs +-entry for support of command cancellation. Since none of the state of a +-hardware TPM can be migrated between hosts, virtual machine migration is +-disabled when the TPM passthrough driver is used. +- +-Since the host's TPM device will already be initialized by the host's firmware, +-certain commands, e.g. TPM_Startup(), sent by the virtual firmware for device +-initialization, will fail. In this case the firmware should not use the TPM. +- +-Sharing the device with the host is generally not a recommended usage scenario +-for a TPM device. The primary reason for this is that two operating systems can +-then access the device's single set of resources, such as platform configuration +-registers (PCRs). Applications or kernel security subsystems, such as the +-Linux Integrity Measurement Architecture (IMA), are not expecting to share PCRs. +- +- +-QEMU files related to the TPM passthrough device: +- - hw/tpm/tpm_passthrough.c +- - hw/tpm/tpm_util.c +- - hw/tpm/tpm_util.h +- +- +-Command line to start QEMU with the TPM passthrough device using the host's +-hardware TPM /dev/tpm0: +- +-qemu-system-x86_64 -display sdl -accel kvm \ +- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +- -tpmdev passthrough,id=tpm0,path=/dev/tpm0 \ +- -device tpm-tis,tpmdev=tpm0 test.img +- +-The following commands should result in similar output inside the VM with a +-Linux kernel that either has the TPM TIS driver built-in or available as a +-module: +- +-#> dmesg | grep -i tpm +-[ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) +- +-#> dmesg | grep TCPA +-[ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ +- BXPCTCPA 0000001 BXPC 00000001) +- +-#> ls -l /dev/tpm* +-crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 +- +-#> find /sys/devices/ | grep pcrs$ | xargs cat +-PCR-00: 35 4E 3B CE 23 9F 38 59 ... +-... +-PCR-23: 00 00 00 00 00 00 00 00 ... +- +- +-== The QEMU TPM emulator device == +- +-The TPM emulator device uses an external TPM emulator called 'swtpm' for +-sending TPM commands to and receiving responses from. The swtpm program +-must have been started before trying to access it through the TPM emulator +-with QEMU. +- +-The TPM emulator implements a command channel for transferring TPM commands +-and responses as well as a control channel over which control commands can +-be sent. The specification for the control channel can be found here: +- +-https://github.com/stefanberger/swtpm/blob/master/man/man3/swtpm_ioctls.pod +- +- +-The control channel serves the purpose of resetting, initializing, and +-migrating the TPM state, among other things. +- +-The swtpm program behaves like a hardware TPM and therefore needs to be +-initialized by the firmware running inside the QEMU virtual machine. +-One necessary step for initializing the device is to send the TPM_Startup +-command to it. SeaBIOS, for example, has been instrumented to initialize +-a TPM 1.2 or TPM 2 device using this command. +- +- +-QEMU files related to the TPM emulator device: +- - hw/tpm/tpm_emulator.c +- - hw/tpm/tpm_util.c +- - hw/tpm/tpm_util.h +- +- +-The following commands start the swtpm with a UnixIO control channel over +-a socket interface. They do not need to be run as root. +- +-mkdir /tmp/mytpm1 +-swtpm socket --tpmstate dir=/tmp/mytpm1 \ +- --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ +- --log level=20 +- +-Command line to start QEMU with the TPM emulator device communicating with +-the swtpm (x86): +- +-qemu-system-x86_64 -display sdl -accel kvm \ +- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ +- -tpmdev emulator,id=tpm0,chardev=chrtpm \ +- -device tpm-tis,tpmdev=tpm0 test.img +- +-In case a pSeries machine is emulated, use the following command line: +- +-qemu-system-ppc64 -display sdl -machine pseries,accel=kvm \ +- -m 1024 -bios slof.bin -boot menu=on \ +- -nodefaults -device VGA -device pci-ohci -device usb-kbd \ +- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ +- -tpmdev emulator,id=tpm0,chardev=chrtpm \ +- -device tpm-spapr,tpmdev=tpm0 \ +- -device spapr-vscsi,id=scsi0,reg=0x00002000 \ +- -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ +- -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 +- +- +-In case SeaBIOS is used as firmware, it should show the TPM menu item +-after entering the menu with 'ESC'. +- +-Select boot device: +-1. DVD/CD [ata1-0: QEMU DVD-ROM ATAPI-4 DVD/CD] +-[...] +-5. Legacy option rom +- +-t. TPM Configuration +- +- +-The following commands should result in similar output inside the VM with a +-Linux kernel that either has the TPM TIS driver built-in or available as a +-module: +- +-#> dmesg | grep -i tpm +-[ 0.711310] tpm_tis 00:06: 1.2 TPM (device=id 0x1, rev-id 1) +- +-#> dmesg | grep TCPA +-[ 0.000000] ACPI: TCPA 0x0000000003FFD191C 000032 (v02 BOCHS \ +- BXPCTCPA 0000001 BXPC 00000001) +- +-#> ls -l /dev/tpm* +-crw-------. 1 root root 10, 224 Jul 11 10:11 /dev/tpm0 +- +-#> find /sys/devices/ | grep pcrs$ | xargs cat +-PCR-00: 35 4E 3B CE 23 9F 38 59 ... +-... +-PCR-23: 00 00 00 00 00 00 00 00 ... +- +- +-=== Migration with the TPM emulator === +- +-The TPM emulator supports the following types of virtual machine migration: +- +-- VM save / restore (migration into a file) +-- Network migration +-- Snapshotting (migration into storage like QoW2 or QED) +- +-The following command sequences can be used to test VM save / restore. +- +- +-In a 1st terminal start an instance of a swtpm using the following command: +- +-mkdir /tmp/mytpm1 +-swtpm socket --tpmstate dir=/tmp/mytpm1 \ +- --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ +- --log level=20 --tpm2 +- +-In a 2nd terminal start the VM: +- +-qemu-system-x86_64 -display sdl -accel kvm \ +- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ +- -tpmdev emulator,id=tpm0,chardev=chrtpm \ +- -device tpm-tis,tpmdev=tpm0 \ +- -monitor stdio \ +- test.img +- +-Verify that the attached TPM is working as expected using applications inside +-the VM. +- +-To store the state of the VM use the following command in the QEMU monitor in +-the 2nd terminal: +- +-(qemu) migrate "exec:cat > testvm.bin" +-(qemu) quit +- +-At this point a file called 'testvm.bin' should exists and the swtpm and QEMU +-processes should have ended. +- +-To test 'VM restore' you have to start the swtpm with the same parameters +-as before. If previously a TPM 2 [--tpm2] was saved, --tpm2 must now be +-passed again on the command line. +- +-In the 1st terminal restart the swtpm with the same command line as before: +- +-swtpm socket --tpmstate dir=/tmp/mytpm1 \ +- --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock \ +- --log level=20 --tpm2 +- +-In the 2nd terminal restore the state of the VM using the additional +-'-incoming' option. +- +-qemu-system-x86_64 -display sdl -accel kvm \ +- -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +- -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ +- -tpmdev emulator,id=tpm0,chardev=chrtpm \ +- -device tpm-tis,tpmdev=tpm0 \ +- -incoming "exec:cat < testvm.bin" \ +- test.img +- +- +-Troubleshooting migration: +- +-There are several reasons why migration may fail. In case of problems, +-please ensure that the command lines adhere to the following rules and, +-if possible, that identical versions of QEMU and swtpm are used at all +-times. +- +-VM save and restore: +- - QEMU command line parameters should be identical apart from the +- '-incoming' option on VM restore +- - swtpm command line parameters should be identical +- +-VM migration to 'localhost': +- - QEMU command line parameters should be identical apart from the +- '-incoming' option on the destination side +- - swtpm command line parameters should point to two different +- directories on the source and destination swtpm (--tpmstate dir=...) +- (especially if different versions of libtpms were to be used on the +- same machine). +- +-VM migration across the network: +- - QEMU command line parameters should be identical apart from the +- '-incoming' option on the destination side +- - swtpm command line parameters should be identical +- +-VM Snapshotting: +- - QEMU command line parameters should be identical +- - swtpm command line parameters should be identical +- +- +-Besides that, migration failure reasons on the swtpm level may include +-the following: +- +- - the versions of the swtpm on the source and destination sides are +- incompatible +- - downgrading of TPM state may not be supported +- - the source and destination libtpms were compiled with different +- compile-time options and the destination side refuses to accept the +- state +- - different migration keys are used on the source and destination side +- and the destination side cannot decrypt the migrated state +- (swtpm ... --migration-key ... ) +-- +2.18.2 + diff --git a/hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch b/hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch new file mode 100644 index 0000000000000000000000000000000000000000..0c6a45edb73c6c82b67d2b53ac969590afd4cd5c --- /dev/null +++ b/hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch @@ -0,0 +1,35 @@ +From 942e7954c845a842b820b3cf6b7e7bb73d788284 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:34 -0500 +Subject: [PATCH 3421/5109] hw/ppc/Kconfig: Enable TPM_SPAPR as part of PSERIES + config +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Stefan Berger +Reviewed-by: Marc-André Lureau +Reviewed-by: David Gibson +Message-Id: <20200121152935.649898-6-stefanb@linux.ibm.com> +[dwg: Use default in Kconfig rather than select to avoid breaking + Windows host build] +Signed-off-by: David Gibson +--- + hw/tpm/Kconfig | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig +index 4d4ab0855c..9e67d990e8 100644 +--- a/hw/tpm/Kconfig ++++ b/hw/tpm/Kconfig +@@ -25,6 +25,6 @@ config TPM_EMULATOR + + config TPM_SPAPR + bool +- default n ++ default y + depends on TPM && PSERIES + select TPMDEV +-- +2.18.2 + diff --git a/hw-tpm-rename-Error-parameter-to-more-common-errp.patch b/hw-tpm-rename-Error-parameter-to-more-common-errp.patch new file mode 100644 index 0000000000000000000000000000000000000000..a97ecbc5316c9139353c022699b9ff6369852697 --- /dev/null +++ b/hw-tpm-rename-Error-parameter-to-more-common-errp.patch @@ -0,0 +1,58 @@ +From e04e33213477aec641cea1edffe82f180bf0abcf Mon Sep 17 00:00:00 2001 +From: Vladimir Sementsov-Ogievskiy +Date: Thu, 5 Dec 2019 20:46:30 +0300 +Subject: [PATCH 2603/5109] hw/tpm: rename Error ** parameter to more common + errp +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Vladimir Sementsov-Ogievskiy +Reviewed-by: Stefan Berger +Message-Id: <20191205174635.18758-17-vsementsov@virtuozzo.com> +Reviewed-by: Philippe Mathieu-Daudé +Signed-off-by: Markus Armbruster +--- + hw/tpm/tpm_emulator.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/tpm/tpm_emulator.c b/hw/tpm/tpm_emulator.c +index 22f9113432..10d587ed40 100644 +--- a/hw/tpm/tpm_emulator.c ++++ b/hw/tpm/tpm_emulator.c +@@ -155,7 +155,7 @@ static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu, + const uint8_t *in, uint32_t in_len, + uint8_t *out, uint32_t out_len, + bool *selftest_done, +- Error **err) ++ Error **errp) + { + ssize_t ret; + bool is_selftest = false; +@@ -165,20 +165,20 @@ static int tpm_emulator_unix_tx_bufs(TPMEmulator *tpm_emu, + is_selftest = tpm_util_is_selftest(in, in_len); + } + +- ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, err); ++ ret = qio_channel_write_all(tpm_emu->data_ioc, (char *)in, in_len, errp); + if (ret != 0) { + return -1; + } + + ret = qio_channel_read_all(tpm_emu->data_ioc, (char *)out, +- sizeof(struct tpm_resp_hdr), err); ++ sizeof(struct tpm_resp_hdr), errp); + if (ret != 0) { + return -1; + } + + ret = qio_channel_read_all(tpm_emu->data_ioc, + (char *)out + sizeof(struct tpm_resp_hdr), +- tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), err); ++ tpm_cmd_get_size(out) - sizeof(struct tpm_resp_hdr), errp); + if (ret != 0) { + return -1; + } +-- +2.18.2 + diff --git a/qemu.spec b/qemu.spec index 61d4cf47b7835920a47e87aae298315a36cadefd..a1342656c1a06793eee384ffaee25861ab94a7f2 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,6 +1,6 @@ Name: qemu Version: 4.1.0 -Release: 16 +Release: 17 Epoch: 2 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY @@ -183,6 +183,20 @@ Patch0170: megasas-use-unsigned-type-for-reply_queue_head-and-c.patch Patch0171: megasas-avoid-NULL-pointer-dereference.patch Patch0172: megasas-use-unsigned-type-for-positive-numeric-field.patch Patch0173: hw-scsi-megasas-Fix-possible-out-of-bounds-array-acc.patch +Patch0174: hw-tpm-rename-Error-parameter-to-more-common-errp.patch +Patch0175: tpm-ppi-page-align-PPI-RAM.patch +Patch0176: tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch +Patch0177: spapr-Implement-get_dt_compatible-callback.patch +Patch0178: delete-the-in-tpm.txt.patch +Patch0179: tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch +Patch0180: tpm_spapr-Support-suspend-and-resume.patch +Patch0181: hw-ppc-Kconfig-Enable-TPM_SPAPR-as-part-of-PSERIES-c.patch +Patch0182: docs-specs-tpm-reST-ify-TPM-documentation.patch +Patch0183: tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch +Patch0184: tpm-Use-TPMState-as-a-common-struct.patch.patch +Patch0185: tpm-Separate-tpm_tis-common-functions-from-isa-.patch +Patch0186: tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.pa.patch +Patch0187: test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.pat.patch BuildRequires: flex BuildRequires: bison @@ -325,6 +339,7 @@ buildldflags="VL_LDFLAGS=-Wl,--build-id" --enable-linux-aio \ --enable-cap-ng \ --enable-vhost-user \ + --enable-tpm \ %ifarch aarch64 --enable-fdt \ --enable-virglrenderer \ @@ -528,6 +543,9 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Wed Aug 5 2020 Huawei Technologies Co., Ltd +-target/arm: Aarch64 support vtpm + * Thu Aug 6 2020 Huawei Technologies Co., Ltd - es1370: check total frame count against current frame - exec: set map length to zero when returning NULL diff --git a/spapr-Implement-get_dt_compatible-callback.patch b/spapr-Implement-get_dt_compatible-callback.patch new file mode 100644 index 0000000000000000000000000000000000000000..6e947ad87b3de8d665ab2d652592ab89d79993e4 --- /dev/null +++ b/spapr-Implement-get_dt_compatible-callback.patch @@ -0,0 +1,67 @@ +From 864674fa29ab61681b8c72c3c41251e985daabed Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:31 -0500 +Subject: [PATCH 3418/5109] spapr: Implement get_dt_compatible() callback +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +For devices that cannot be statically initialized, implement a +get_dt_compatible() callback that allows us to ask the device for +the 'compatible' value. + +Signed-off-by: Stefan Berger +Reviewed-by: Marc-André Lureau +Reviewed-by: David Gibson +Message-Id: <20200121152935.649898-3-stefanb@linux.ibm.com> +Signed-off-by: David Gibson +--- + hw/ppc/spapr_vio.c | 11 +++++++++-- + include/hw/ppc/spapr_vio.h | 1 + + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c +index f14944e900..0b085eabe4 100644 +--- a/hw/ppc/spapr_vio.c ++++ b/hw/ppc/spapr_vio.c +@@ -87,6 +87,7 @@ static int vio_make_devnode(SpaprVioDevice *dev, + SpaprVioDeviceClass *pc = VIO_SPAPR_DEVICE_GET_CLASS(dev); + int vdevice_off, node_off, ret; + char *dt_name; ++ const char *dt_compatible; + + vdevice_off = fdt_path_offset(fdt, "/vdevice"); + if (vdevice_off < 0) { +@@ -113,9 +114,15 @@ static int vio_make_devnode(SpaprVioDevice *dev, + } + } + +- if (pc->dt_compatible) { ++ if (pc->get_dt_compatible) { ++ dt_compatible = pc->get_dt_compatible(dev); ++ } else { ++ dt_compatible = pc->dt_compatible; ++ } ++ ++ if (dt_compatible) { + ret = fdt_setprop_string(fdt, node_off, "compatible", +- pc->dt_compatible); ++ dt_compatible); + if (ret < 0) { + return ret; + } +diff --git a/include/hw/ppc/spapr_vio.h b/include/hw/ppc/spapr_vio.h +index ce6d9b0c66..bed7df60e3 100644 +--- a/include/hw/ppc/spapr_vio.h ++++ b/include/hw/ppc/spapr_vio.h +@@ -58,6 +58,7 @@ typedef struct SpaprVioDeviceClass { + void (*realize)(SpaprVioDevice *dev, Error **errp); + void (*reset)(SpaprVioDevice *dev); + int (*devnode)(SpaprVioDevice *dev, void *fdt, int node_off); ++ const char *(*get_dt_compatible)(SpaprVioDevice *dev); + } SpaprVioDeviceClass; + + struct SpaprVioDevice { +-- +2.18.2 + diff --git a/test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.pat.patch b/test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.pat.patch new file mode 100644 index 0000000000000000000000000000000000000000..c15e03a5e17ac42c572026f0c09d2373e78b65bf --- /dev/null +++ b/test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.pat.patch @@ -0,0 +1,1723 @@ +From 7b487a2bc2dc662532d4225088e4a9eb365bccce Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Thu, 30 Jul 2020 01:05:08 +0000 +Subject: [PATCH] 4302-test-tpm-tis-Add-Sysbus-TPM-TIS-device-test.patch + +--- + docs/specs/tpm.rst | 25 +- + hw/arm/Kconfig | 1 + + hw/arm/sysbus-fdt.c | 33 +++ + hw/arm/virt.c | 7 + + hw/tpm/Kconfig | 5 + + hw/tpm/Makefile.objs | 1 + + hw/tpm/tpm_tis_sysbus.c | 159 +++++++++++ + include/sysemu/tpm.h | 1 + + tests/Makefile.include | 9 +- + tests/tpm-crb-swtpm-test.c | 9 +- + tests/tpm-crb-test.c | 3 + + tests/tpm-tests.c | 10 +- + tests/tpm-tests.h | 5 +- + tests/tpm-tis-device-swtpm-test.c | 76 +++++ + tests/tpm-tis-device-test.c | 87 ++++++ + tests/tpm-tis-swtpm-test.c | 8 +- + tests/tpm-tis-test.c | 414 +-------------------------- + tests/tpm-tis-util.c | 451 ++++++++++++++++++++++++++++++ + tests/tpm-tis-util.h | 23 ++ + tests/tpm-util.c | 11 +- + tests/tpm-util.h | 8 +- + 21 files changed, 917 insertions(+), 429 deletions(-) + create mode 100644 hw/tpm/tpm_tis_sysbus.c + create mode 100644 tests/tpm-tis-device-swtpm-test.c + create mode 100644 tests/tpm-tis-device-test.c + create mode 100644 tests/tpm-tis-util.c + create mode 100644 tests/tpm-tis-util.h + +diff --git a/docs/specs/tpm.rst b/docs/specs/tpm.rst +index 2bdf637f..da9eb39c 100644 +--- a/docs/specs/tpm.rst ++++ b/docs/specs/tpm.rst +@@ -18,9 +18,15 @@ The TIS interface makes a memory mapped IO region in the area + 0xfed40000-0xfed44fff available to the guest operating system. + + QEMU files related to TPM TIS interface: +- - ``hw/tpm/tpm_tis.c`` ++ - ``hw/tpm/tpm_tis_common.c`` ++ - ``hw/tpm/tpm_tis_isa.c`` ++ - ``hw/tpm/tpm_tis_sysbus.c`` + - ``hw/tpm/tpm_tis.h`` + ++Both an ISA device and a sysbus device are available. The former is ++used with pc/q35 machine while the latter can be instantiated in the ++ARM virt machine. ++ + CRB interface + ------------- + +@@ -325,6 +331,23 @@ In case a pSeries machine is emulated, use the following command line: + -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ + -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 + ++In case an ARM virt machine is emulated, use the following command line: ++ ++.. code-block:: console ++ ++ qemu-system-aarch64 -machine virt,gic-version=3,accel=kvm \ ++ -cpu host -m 4G \ ++ -nographic -no-acpi \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-tis-device,tpmdev=tpm0 \ ++ -device virtio-blk-pci,drive=drv0 \ ++ -drive format=qcow2,file=hda.qcow2,if=none,id=drv0 \ ++ -drive if=pflash,format=raw,file=flash0.img,readonly \ ++ -drive if=pflash,format=raw,file=flash1.img ++ ++ On ARM, ACPI boot with TPM is not yet supported. ++ + In case SeaBIOS is used as firmware, it should show the TPM menu item + after entering the menu with 'ESC'. + +diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig +index 15e18b0a..06e49f26 100644 +--- a/hw/arm/Kconfig ++++ b/hw/arm/Kconfig +@@ -5,6 +5,7 @@ config ARM_VIRT + imply VFIO_AMD_XGBE + imply VFIO_PLATFORM + imply VFIO_XGMAC ++ imply TPM_TIS_SYSBUS + select A15MPCORE + select ACPI + select ARM_SMMUV3 +diff --git a/hw/arm/sysbus-fdt.c b/hw/arm/sysbus-fdt.c +index 57f94e65..c725d325 100644 +--- a/hw/arm/sysbus-fdt.c ++++ b/hw/arm/sysbus-fdt.c +@@ -30,6 +30,7 @@ + #include "hw/arm/sysbus-fdt.h" + #include "qemu/error-report.h" + #include "sysemu/device_tree.h" ++#include "sysemu/tpm.h" + #include "hw/platform-bus.h" + #include "sysemu/sysemu.h" + #include "hw/vfio/vfio-platform.h" +@@ -437,6 +438,37 @@ static bool vfio_platform_match(SysBusDevice *sbdev, + + #endif /* CONFIG_LINUX */ + ++/* ++ * add_tpm_tis_fdt_node: Create a DT node for TPM TIS ++ * ++ * See kernel documentation: ++ * Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt ++ * Optional interrupt for command completion is not exposed ++ */ ++static int add_tpm_tis_fdt_node(SysBusDevice *sbdev, void *opaque) ++{ ++ PlatformBusFDTData *data = opaque; ++ PlatformBusDevice *pbus = data->pbus; ++ void *fdt = data->fdt; ++ const char *parent_node = data->pbus_node_name; ++ char *nodename; ++ uint32_t reg_attr[2]; ++ uint64_t mmio_base; ++ ++ mmio_base = platform_bus_get_mmio_addr(pbus, sbdev, 0); ++ nodename = g_strdup_printf("%s/tpm_tis@%" PRIx64, parent_node, mmio_base); ++ qemu_fdt_add_subnode(fdt, nodename); ++ ++ qemu_fdt_setprop_string(fdt, nodename, "compatible", "tcg,tpm-tis-mmio"); ++ ++ reg_attr[0] = cpu_to_be32(mmio_base); ++ reg_attr[1] = cpu_to_be32(0x5000); ++ qemu_fdt_setprop(fdt, nodename, "reg", reg_attr, 2 * sizeof(uint32_t)); ++ ++ g_free(nodename); ++ return 0; ++} ++ + static int no_fdt_node(SysBusDevice *sbdev, void *opaque) + { + return 0; +@@ -457,6 +489,7 @@ static const BindingEntry bindings[] = { + TYPE_BINDING(TYPE_VFIO_AMD_XGBE, add_amd_xgbe_fdt_node), + VFIO_PLATFORM_BINDING("amd,xgbe-seattle-v1a", add_amd_xgbe_fdt_node), + #endif ++ TYPE_BINDING(TYPE_TPM_TIS_SYSBUS, add_tpm_tis_fdt_node), + TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node), + TYPE_BINDING("", NULL), /* last element */ + }; +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 133d36a4..7afc6c5e 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -47,6 +47,7 @@ + #include "sysemu/numa.h" + #include "sysemu/cpus.h" + #include "sysemu/sysemu.h" ++#include "sysemu/tpm.h" + #include "sysemu/kvm.h" + #include "sysemu/cpus.h" + #include "sysemu/hw_accel.h" +@@ -2368,6 +2369,7 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_AMD_XGBE); + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE); + machine_class_allow_dynamic_sysbus_dev(mc, TYPE_VFIO_PLATFORM); ++ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS); + mc->block_default_type = IF_VIRTIO; + mc->no_cdrom = 1; + mc->pci_allow_0_address = true; +@@ -2481,6 +2483,11 @@ type_init(machvirt_machine_init); + + static void virt_machine_4_1_options(MachineClass *mc) + { ++ static GlobalProperty compat[] = { ++ { TYPE_TPM_TIS_SYSBUS, "ppi", "false" }, ++ }; ++ ++ compat_props_add(mc->compat_props, compat, G_N_ELEMENTS(compat)); + } + DEFINE_VIRT_MACHINE_AS_LATEST(4, 1) + +diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig +index 686f8206..4794e7fe 100644 +--- a/hw/tpm/Kconfig ++++ b/hw/tpm/Kconfig +@@ -7,6 +7,11 @@ config TPM_TIS_ISA + depends on TPM && ISA_BUS + select TPM_TIS + ++config TPM_TIS_SYSBUS ++ bool ++ depends on TPM ++ select TPM_TIS ++ + config TPM_TIS + bool + depends on TPM +diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs +index 3ef2036c..f1ec4beb 100644 +--- a/hw/tpm/Makefile.objs ++++ b/hw/tpm/Makefile.objs +@@ -1,6 +1,7 @@ + common-obj-$(CONFIG_TPM) += tpm_util.o + obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o + common-obj-$(CONFIG_TPM_TIS_ISA) += tpm_tis_isa.o ++common-obj-$(CONFIG_TPM_TIS_SYSBUS) += tpm_tis_sysbus.o + common-obj-$(CONFIG_TPM_TIS) += tpm_tis_common.o + common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o + common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o +diff --git a/hw/tpm/tpm_tis_sysbus.c b/hw/tpm/tpm_tis_sysbus.c +new file mode 100644 +index 00000000..18c02aed +--- /dev/null ++++ b/hw/tpm/tpm_tis_sysbus.c +@@ -0,0 +1,159 @@ ++/* ++ * tpm_tis_sysbus.c - QEMU's TPM TIS SYSBUS Device ++ * ++ * Copyright (C) 2006,2010-2013 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * David Safford ++ * ++ * Xen 4 support: Andrease Niederl ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ * Implementation of the TIS interface according to specs found at ++ * http://www.trustedcomputinggroup.org. This implementation currently ++ * supports version 1.3, 21 March 2013 ++ * In the developers menu choose the PC Client section then find the TIS ++ * specification. ++ * ++ * TPM TIS for TPM 2 implementation following TCG PC Client Platform ++ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/qdev-properties.h" ++#include "migration/vmstate.h" ++#include "tpm_util.h" ++#include "hw/sysbus.h" ++#include "tpm_tis.h" ++ ++typedef struct TPMStateSysBus { ++ /*< private >*/ ++ SysBusDevice parent_obj; ++ ++ /*< public >*/ ++ TPMState state; /* not a QOM object */ ++} TPMStateSysBus; ++ ++#define TPM_TIS_SYSBUS(obj) OBJECT_CHECK(TPMStateSysBus, (obj), TYPE_TPM_TIS_SYSBUS) ++ ++static int tpm_tis_pre_save_sysbus(void *opaque) ++{ ++ TPMStateSysBus *sbdev = opaque; ++ ++ return tpm_tis_pre_save(&sbdev->state); ++} ++ ++static const VMStateDescription vmstate_tpm_tis_sysbus = { ++ .name = "tpm-tis", ++ .version_id = 0, ++ .pre_save = tpm_tis_pre_save_sysbus, ++ .fields = (VMStateField[]) { ++ VMSTATE_BUFFER(state.buffer, TPMStateSysBus), ++ VMSTATE_UINT16(state.rw_offset, TPMStateSysBus), ++ VMSTATE_UINT8(state.active_locty, TPMStateSysBus), ++ VMSTATE_UINT8(state.aborting_locty, TPMStateSysBus), ++ VMSTATE_UINT8(state.next_locty, TPMStateSysBus), ++ ++ VMSTATE_STRUCT_ARRAY(state.loc, TPMStateSysBus, TPM_TIS_NUM_LOCALITIES, ++ 0, vmstate_locty, TPMLocality), ++ ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static void tpm_tis_sysbus_request_completed(TPMIf *ti, int ret) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(ti); ++ TPMState *s = &sbdev->state; ++ ++ tpm_tis_request_completed(s, ret); ++} ++ ++static enum TPMVersion tpm_tis_sysbus_get_tpm_version(TPMIf *ti) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(ti); ++ TPMState *s = &sbdev->state; ++ ++ return tpm_tis_get_tpm_version(s); ++} ++ ++static void tpm_tis_sysbus_reset(DeviceState *dev) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(dev); ++ TPMState *s = &sbdev->state; ++ ++ return tpm_tis_reset(s); ++} ++ ++static Property tpm_tis_sysbus_properties[] = { ++ DEFINE_PROP_UINT32("irq", TPMStateSysBus, state.irq_num, TPM_TIS_IRQ), ++ DEFINE_PROP_TPMBE("tpmdev", TPMStateSysBus, state.be_driver), ++ DEFINE_PROP_BOOL("ppi", TPMStateSysBus, state.ppi_enabled, true), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static void tpm_tis_sysbus_initfn(Object *obj) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(obj); ++ TPMState *s = &sbdev->state; ++ ++ memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, ++ s, "tpm-tis-mmio", ++ TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); ++ ++ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); ++ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); ++} ++ ++static void tpm_tis_sysbus_realizefn(DeviceState *dev, Error **errp) ++{ ++ TPMStateSysBus *sbdev = TPM_TIS_SYSBUS(dev); ++ TPMState *s = &sbdev->state; ++ ++ if (!tpm_find()) { ++ error_setg(errp, "at most one TPM device is permitted"); ++ return; ++ } ++ ++ if (!s->be_driver) { ++ error_setg(errp, "'tpmdev' property is required"); ++ return; ++ } ++} ++ ++static void tpm_tis_sysbus_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ TPMIfClass *tc = TPM_IF_CLASS(klass); ++ ++ dc->props = tpm_tis_sysbus_properties; ++ dc->vmsd = &vmstate_tpm_tis_sysbus; ++ tc->model = TPM_MODEL_TPM_TIS; ++ dc->realize = tpm_tis_sysbus_realizefn; ++ dc->user_creatable = true; ++ dc->reset = tpm_tis_sysbus_reset; ++ tc->request_completed = tpm_tis_sysbus_request_completed; ++ tc->get_version = tpm_tis_sysbus_get_tpm_version; ++} ++ ++static const TypeInfo tpm_tis_sysbus_info = { ++ .name = TYPE_TPM_TIS_SYSBUS, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(TPMStateSysBus), ++ .instance_init = tpm_tis_sysbus_initfn, ++ .class_init = tpm_tis_sysbus_class_init, ++ .interfaces = (InterfaceInfo[]) { ++ { TYPE_TPM_IF }, ++ { } ++ } ++}; ++ ++static void tpm_tis_sysbus_register(void) ++{ ++ type_register_static(&tpm_tis_sysbus_info); ++} ++ ++type_init(tpm_tis_sysbus_register) +diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h +index 1691b92c..f37851b1 100644 +--- a/include/sysemu/tpm.h ++++ b/include/sysemu/tpm.h +@@ -44,6 +44,7 @@ typedef struct TPMIfClass { + } TPMIfClass; + + #define TYPE_TPM_TIS_ISA "tpm-tis" ++#define TYPE_TPM_TIS_SYSBUS "tpm-tis-device" + #define TYPE_TPM_CRB "tpm-crb" + #define TYPE_TPM_SPAPR "tpm-spapr" + +diff --git a/tests/Makefile.include b/tests/Makefile.include +index b9da8d3a..75042669 100644 +--- a/tests/Makefile.include ++++ b/tests/Makefile.include +@@ -264,6 +264,10 @@ check-qtest-arm-y += tests/boot-serial-test$(EXESUF) + check-qtest-arm-y += tests/hexloader-test$(EXESUF) + check-qtest-arm-$(CONFIG_PFLASH_CFI02) += tests/pflash-cfi02-test$(EXESUF) + ++ ++check-qtest-aarch64-y += arm-cpu-features ++check-qtest-aarch64-$(CONFIG_TPM_TIS_SYSBUS) += tpm-tis-device-test ++check-qtest-aarch64-$(CONFIG_TPM_TIS_SYSBUS) += tpm-tis-device-swtpm-test + check-qtest-aarch64-y = tests/numa-test$(EXESUF) + check-qtest-aarch64-y += tests/boot-serial-test$(EXESUF) + check-qtest-aarch64-y += tests/migration-test$(EXESUF) +@@ -670,7 +674,10 @@ tests/tpm-crb-swtpm-test$(EXESUF): tests/tpm-crb-swtpm-test.o tests/tpm-emu.o \ + tests/tpm-crb-test$(EXESUF): tests/tpm-crb-test.o tests/tpm-emu.o $(test-io-obj-y) + tests/tpm-tis-swtpm-test$(EXESUF): tests/tpm-tis-swtpm-test.o tests/tpm-emu.o \ + tests/tpm-util.o tests/tpm-tests.o $(test-io-obj-y) +-tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-emu.o $(test-io-obj-y) ++tests/tpm-tis-device-swtpm-test$(EXESUF): tests/tpm-tis-device-swtpm-test.o tests/tpm-emu.o \ ++ tests/tpm-util.o tests/tpm-tests.o $(test-io-obj-y) ++tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-tis-util.o tests/tpm-emu.o $(test-io-obj-y) ++tests/tpm-tis-device-test$(EXESUF): tests/tpm-tis-device-test.o tests/tpm-tis-util.o tests/tpm-emu.o $(test-io-obj-y) + tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \ + tests/io-channel-helpers.o $(test-io-obj-y) + tests/test-io-channel-tls$(EXESUF): tests/test-io-channel-tls.o \ +diff --git a/tests/tpm-crb-swtpm-test.c b/tests/tpm-crb-swtpm-test.c +index 2c4fb8ae..55fdb565 100644 +--- a/tests/tpm-crb-swtpm-test.c ++++ b/tests/tpm-crb-swtpm-test.c +@@ -18,6 +18,10 @@ + #include "libqtest.h" + #include "qemu/module.h" + #include "tpm-tests.h" ++#include "hw/acpi/tpm.h" ++ ++/* Not used but needed for linking */ ++uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; + + typedef struct TestState { + char *src_tpm_path; +@@ -29,7 +33,8 @@ static void tpm_crb_swtpm_test(const void *data) + { + const TestState *ts = data; + +- tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_transfer, "tpm-crb"); ++ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_crb_transfer, ++ "tpm-crb", NULL); + } + + static void tpm_crb_swtpm_migration_test(const void *data) +@@ -37,7 +42,7 @@ static void tpm_crb_swtpm_migration_test(const void *data) + const TestState *ts = data; + + tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri, +- tpm_util_crb_transfer, "tpm-crb"); ++ tpm_util_crb_transfer, "tpm-crb", NULL); + } + + int main(int argc, char **argv) +diff --git a/tests/tpm-crb-test.c b/tests/tpm-crb-test.c +index a139caa5..32695810 100644 +--- a/tests/tpm-crb-test.c ++++ b/tests/tpm-crb-test.c +@@ -19,6 +19,9 @@ + #include "qemu/module.h" + #include "tpm-emu.h" + ++/* Not used but needed for linking */ ++uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; ++ + #define TPM_CMD "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00" + + static void tpm_crb_test(const void *data) +diff --git a/tests/tpm-tests.c b/tests/tpm-tests.c +index e640777a..d823bda8 100644 +--- a/tests/tpm-tests.c ++++ b/tests/tpm-tests.c +@@ -30,7 +30,7 @@ tpm_test_swtpm_skip(void) + } + + void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, +- const char *ifmodel) ++ const char *ifmodel, const char *machine_options) + { + char *args = NULL; + QTestState *s; +@@ -47,10 +47,11 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, + g_assert_true(succ); + + args = g_strdup_printf( ++ "%s " + "-chardev socket,id=chr,path=%s " + "-tpmdev emulator,id=dev,chardev=chr " + "-device %s,tpmdev=dev", +- addr->u.q_unix.path, ifmodel); ++ machine_options ? : "", addr->u.q_unix.path, ifmodel); + + s = qtest_start(args); + g_free(args); +@@ -78,7 +79,8 @@ void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, + void tpm_test_swtpm_migration_test(const char *src_tpm_path, + const char *dst_tpm_path, + const char *uri, tx_func *tx, +- const char *ifmodel) ++ const char *ifmodel, ++ const char *machine_options) + { + gboolean succ; + GPid src_tpm_pid, dst_tpm_pid; +@@ -100,7 +102,7 @@ void tpm_test_swtpm_migration_test(const char *src_tpm_path, + + tpm_util_migration_start_qemu(&src_qemu, &dst_qemu, + src_tpm_addr, dst_tpm_addr, uri, +- ifmodel); ++ ifmodel, machine_options); + + tpm_util_startup(src_qemu, tx); + tpm_util_pcrextend(src_qemu, tx); +diff --git a/tests/tpm-tests.h b/tests/tpm-tests.h +index b97688fe..a5df35ab 100644 +--- a/tests/tpm-tests.h ++++ b/tests/tpm-tests.h +@@ -16,11 +16,12 @@ + #include "tpm-util.h" + + void tpm_test_swtpm_test(const char *src_tpm_path, tx_func *tx, +- const char *ifmodel); ++ const char *ifmodel, const char *machine_options); + + void tpm_test_swtpm_migration_test(const char *src_tpm_path, + const char *dst_tpm_path, + const char *uri, tx_func *tx, +- const char *ifmodel); ++ const char *ifmodel, ++ const char *machine_options); + + #endif /* TESTS_TPM_TESTS_H */ +diff --git a/tests/tpm-tis-device-swtpm-test.c b/tests/tpm-tis-device-swtpm-test.c +new file mode 100644 +index 00000000..7b200351 +--- /dev/null ++++ b/tests/tpm-tis-device-swtpm-test.c +@@ -0,0 +1,76 @@ ++/* ++ * QTest testcase for Sysbus TPM TIS talking to external swtpm and swtpm ++ * migration ++ * ++ * Copyright (c) 2018 IBM Corporation ++ * with parts borrowed from migration-test.c that is: ++ * Copyright (c) 2016-2018 Red Hat, Inc. and/or its affiliates ++ * ++ * Authors: ++ * Stefan Berger ++ * ++ * 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 ++ ++#include "libqtest.h" ++#include "qemu/module.h" ++#include "tpm-tests.h" ++#include "hw/acpi/tpm.h" ++ ++uint64_t tpm_tis_base_addr = 0xc000000; ++#define MACHINE_OPTIONS "-machine virt,gic-version=max -accel tcg" ++ ++typedef struct TestState { ++ char *src_tpm_path; ++ char *dst_tpm_path; ++ char *uri; ++} TestState; ++ ++static void tpm_tis_swtpm_test(const void *data) ++{ ++ const TestState *ts = data; ++ ++ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, ++ "tpm-tis-device", MACHINE_OPTIONS); ++} ++ ++static void tpm_tis_swtpm_migration_test(const void *data) ++{ ++ const TestState *ts = data; ++ ++ tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri, ++ tpm_util_tis_transfer, "tpm-tis-device", ++ MACHINE_OPTIONS); ++} ++ ++int main(int argc, char **argv) ++{ ++ int ret; ++ TestState ts = { 0 }; ++ ++ ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-tis-device-swtpm-test.XXXXXX", ++ NULL); ++ ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-tis-device-swtpm-test.XXXXXX", ++ NULL); ++ ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path); ++ ++ module_call_init(MODULE_INIT_QOM); ++ g_test_init(&argc, &argv, NULL); ++ ++ qtest_add_data_func("/tpm/tis-swtpm/test", &ts, tpm_tis_swtpm_test); ++ qtest_add_data_func("/tpm/tis-swtpm-migration/test", &ts, ++ tpm_tis_swtpm_migration_test); ++ ret = g_test_run(); ++ ++ g_rmdir(ts.dst_tpm_path); ++ g_free(ts.dst_tpm_path); ++ g_rmdir(ts.src_tpm_path); ++ g_free(ts.src_tpm_path); ++ g_free(ts.uri); ++ ++ return ret; ++} +diff --git a/tests/tpm-tis-device-test.c b/tests/tpm-tis-device-test.c +new file mode 100644 +index 00000000..63ed3644 +--- /dev/null ++++ b/tests/tpm-tis-device-test.c +@@ -0,0 +1,87 @@ ++/* ++ * QTest testcase for SYSBUS TPM TIS ++ * ++ * Copyright (c) 2018 Red Hat, Inc. ++ * Copyright (c) 2018 IBM Corporation ++ * ++ * Authors: ++ * Marc-André Lureau ++ * Stefan Berger ++ * ++ * 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 ++ ++#include "io/channel-socket.h" ++#include "libqtest.h" ++#include "qemu/module.h" ++#include "tpm-emu.h" ++#include "tpm-util.h" ++#include "tpm-tis-util.h" ++ ++/* ++ * As the Sysbus tpm-tis-device is instantiated on the ARM virt ++ * platform bus and it is the only sysbus device dynamically ++ * instantiated, it gets plugged at its base address ++ */ ++uint64_t tpm_tis_base_addr = 0xc000000; ++ ++int main(int argc, char **argv) ++{ ++ char *tmp_path = g_dir_make_tmp("qemu-tpm-tis-device-test.XXXXXX", NULL); ++ GThread *thread; ++ TestState test; ++ char *args; ++ int ret; ++ ++ module_call_init(MODULE_INIT_QOM); ++ g_test_init(&argc, &argv, NULL); ++ ++ test.addr = g_new0(SocketAddress, 1); ++ test.addr->type = SOCKET_ADDRESS_TYPE_UNIX; ++ test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL); ++ g_mutex_init(&test.data_mutex); ++ g_cond_init(&test.data_cond); ++ test.data_cond_signal = false; ++ ++ thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test); ++ tpm_emu_test_wait_cond(&test); ++ ++ args = g_strdup_printf( ++ "-machine virt,gic-version=max -accel tcg " ++ "-chardev socket,id=chr,path=%s " ++ "-tpmdev emulator,id=dev,chardev=chr " ++ "-device tpm-tis-device,tpmdev=dev", ++ test.addr->u.q_unix.path); ++ qtest_start(args); ++ ++ qtest_add_data_func("/tpm-tis/test_check_localities", &test, ++ tpm_tis_test_check_localities); ++ ++ qtest_add_data_func("/tpm-tis/test_check_access_reg", &test, ++ tpm_tis_test_check_access_reg); ++ ++ qtest_add_data_func("/tpm-tis/test_check_access_reg_seize", &test, ++ tpm_tis_test_check_access_reg_seize); ++ ++ qtest_add_data_func("/tpm-tis/test_check_access_reg_release", &test, ++ tpm_tis_test_check_access_reg_release); ++ ++ qtest_add_data_func("/tpm-tis/test_check_transmit", &test, ++ tpm_tis_test_check_transmit); ++ ++ ret = g_test_run(); ++ ++ qtest_end(); ++ ++ g_thread_join(thread); ++ g_unlink(test.addr->u.q_unix.path); ++ qapi_free_SocketAddress(test.addr); ++ g_rmdir(tmp_path); ++ g_free(tmp_path); ++ g_free(args); ++ return ret; ++} +diff --git a/tests/tpm-tis-swtpm-test.c b/tests/tpm-tis-swtpm-test.c +index 9f58a3a9..90131cb3 100644 +--- a/tests/tpm-tis-swtpm-test.c ++++ b/tests/tpm-tis-swtpm-test.c +@@ -18,6 +18,9 @@ + #include "libqtest.h" + #include "qemu/module.h" + #include "tpm-tests.h" ++#include "hw/acpi/tpm.h" ++ ++uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; + + typedef struct TestState { + char *src_tpm_path; +@@ -29,7 +32,8 @@ static void tpm_tis_swtpm_test(const void *data) + { + const TestState *ts = data; + +- tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, "tpm-tis"); ++ tpm_test_swtpm_test(ts->src_tpm_path, tpm_util_tis_transfer, ++ "tpm-tis", NULL); + } + + static void tpm_tis_swtpm_migration_test(const void *data) +@@ -37,7 +41,7 @@ static void tpm_tis_swtpm_migration_test(const void *data) + const TestState *ts = data; + + tpm_test_swtpm_migration_test(ts->src_tpm_path, ts->dst_tpm_path, ts->uri, +- tpm_util_tis_transfer, "tpm-tis"); ++ tpm_util_tis_transfer, "tpm-tis", NULL); + } + + int main(int argc, char **argv) +diff --git a/tests/tpm-tis-test.c b/tests/tpm-tis-test.c +index 92a7e95a..8042de13 100644 +--- a/tests/tpm-tis-test.c ++++ b/tests/tpm-tis-test.c +@@ -1,5 +1,5 @@ + /* +- * QTest testcase for TPM TIS ++ * QTest testcase for ISA TPM TIS + * + * Copyright (c) 2018 Red Hat, Inc. + * Copyright (c) 2018 IBM Corporation +@@ -20,417 +20,9 @@ + #include "libqtest.h" + #include "qemu/module.h" + #include "tpm-emu.h" ++#include "tpm-tis-util.h" + +-#define TIS_REG(LOCTY, REG) \ +- (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG) +- +-#define DEBUG_TIS_TEST 0 +- +-#define DPRINTF(fmt, ...) do { \ +- if (DEBUG_TIS_TEST) { \ +- printf(fmt, ## __VA_ARGS__); \ +- } \ +-} while (0) +- +-#define DPRINTF_ACCESS \ +- DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \ +- __func__, __LINE__, locty, l, access, pending_request_flag) +- +-#define DPRINTF_STS \ +- DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts) +- +-static const uint8_t TPM_CMD[12] = +- "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"; +- +-static void tpm_tis_test_check_localities(const void *data) +-{ +- uint8_t locty; +- uint8_t access; +- uint32_t ifaceid; +- uint32_t capability; +- uint32_t didvid; +- uint32_t rid; +- +- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) { +- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY)); +- g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0); +- +- ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID)); +- g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0); +- +- didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID)); +- g_assert_cmpint(didvid, !=, 0); +- g_assert_cmpint(didvid, !=, 0xffffffff); +- +- rid = readl(TIS_REG(locty, TPM_TIS_REG_RID)); +- g_assert_cmpint(rid, !=, 0); +- g_assert_cmpint(rid, !=, 0xffffffff); +- } +-} +- +-static void tpm_tis_test_check_access_reg(const void *data) +-{ +- uint8_t locty; +- uint8_t access; +- +- /* do not test locality 4 (hw only) */ +- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* request use of locality */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* release access */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- } +-} +- +-/* +- * Test case for seizing access by a higher number locality +- */ +-static void tpm_tis_test_check_access_reg_seize(const void *data) +-{ +- int locty, l; +- uint8_t access; +- uint8_t pending_request_flag; +- +- /* do not test locality 4 (hw only) */ +- for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { +- pending_request_flag = 0; +- +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* request use of locality */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* lower localities cannot seize access */ +- for (l = 0; l < locty; l++) { +- /* lower locality is not active */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* try to request use from 'l' */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- +- /* requesting use from 'l' was not possible; +- we must see REQUEST_USE and possibly PENDING_REQUEST */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_REQUEST_USE | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* locality 'locty' must be unchanged; +- we must see PENDING_REQUEST */ +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_PENDING_REQUEST | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* try to seize from 'l' */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); +- /* seize from 'l' was not possible */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_REQUEST_USE | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* locality 'locty' must be unchanged */ +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_PENDING_REQUEST | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* on the next loop we will have a PENDING_REQUEST flag +- set for locality 'l' */ +- pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; +- } +- +- /* higher localities can 'seize' access but not 'request use'; +- note: this will activate first l+1, then l+2 etc. */ +- for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { +- /* try to 'request use' from 'l' */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- +- /* requesting use from 'l' was not possible; we should see +- REQUEST_USE and may see PENDING_REQUEST */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_REQUEST_USE | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* locality 'l-1' must be unchanged; we should always +- see PENDING_REQUEST from 'l' requesting access */ +- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_PENDING_REQUEST | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* try to seize from 'l' */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); +- +- /* seize from 'l' was possible */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* l - 1 should show that it has BEEN_SEIZED */ +- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_BEEN_SEIZED | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* clear the BEEN_SEIZED flag and make sure it's gone */ +- writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_BEEN_SEIZED); +- +- access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- } +- +- /* PENDING_REQUEST will not be set if locty = 0 since all localities +- were active; in case of locty = 1, locality 0 will be active +- but no PENDING_REQUEST anywhere */ +- if (locty <= 1) { +- pending_request_flag = 0; +- } +- +- /* release access from l - 1; this activates locty - 1 */ +- l--; +- +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- +- DPRINTF("%s: %d: relinquishing control on l = %d\n", +- __func__, __LINE__, l); +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- for (l = locty - 1; l >= 0; l--) { +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* release this locality */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- +- if (l == 1) { +- pending_request_flag = 0; +- } +- } +- +- /* no locality may be active now */ +- for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- } +- } +-} +- +-/* +- * Test case for getting access when higher number locality relinquishes access +- */ +-static void tpm_tis_test_check_access_reg_release(const void *data) +-{ +- int locty, l; +- uint8_t access; +- uint8_t pending_request_flag; +- +- /* do not test locality 4 (hw only) */ +- for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) { +- pending_request_flag = 0; +- +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* request use of locality */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- /* request use of all other localities */ +- for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { +- if (l == locty) { +- continue; +- } +- /* request use of locality 'l' -- we MUST see REQUEST USE and +- may see PENDING_REQUEST */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_REQUEST_USE | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; +- } +- /* release locality 'locty' */ +- writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- /* highest locality should now be active; release it and make sure the +- next higest locality is active afterwards */ +- for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) { +- if (l == locty) { +- continue; +- } +- /* 'l' should be active now */ +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- /* 'l' relinquishes access */ +- writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), +- TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); +- DPRINTF_ACCESS; +- if (l == 1 || (locty <= 1 && l == 2)) { +- pending_request_flag = 0; +- } +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- pending_request_flag | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- } +- } +-} +- +-/* +- * Test case for transmitting packets +- */ +-static void tpm_tis_test_check_transmit(const void *data) +-{ +- const TestState *s = data; +- uint8_t access; +- uint32_t sts; +- uint16_t bcount; +- size_t i; +- +- /* request use of locality 0 */ +- writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); +- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); +- g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | +- TPM_TIS_ACCESS_ACTIVE_LOCALITY | +- TPM_TIS_ACCESS_TPM_ESTABLISHMENT); +- +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- +- g_assert_cmpint(sts & 0xff, ==, 0); +- g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==, +- TPM_TIS_STS_TPM_FAMILY2_0); +- +- bcount = (sts >> 8) & 0xffff; +- g_assert_cmpint(bcount, >=, 128); +- +- writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY); +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY); +- +- /* transmit command */ +- for (i = 0; i < sizeof(TPM_CMD); i++) { +- writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]); +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- if (i < sizeof(TPM_CMD) - 1) { +- g_assert_cmpint(sts & 0xff, ==, +- TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); +- } else { +- g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID); +- } +- g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); +- } +- /* start processing */ +- writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO); +- +- uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND; +- do { +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) { +- break; +- } +- } while (g_get_monotonic_time() < end_time); +- +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- g_assert_cmpint(sts & 0xff, == , +- TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); +- bcount = (sts >> 8) & 0xffff; +- +- /* read response */ +- uint8_t tpm_msg[sizeof(struct tpm_hdr)]; +- g_assert_cmpint(sizeof(tpm_msg), ==, bcount); +- +- for (i = 0; i < sizeof(tpm_msg); i++) { +- tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO)); +- sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); +- DPRINTF_STS; +- if (sts & TPM_TIS_STS_DATA_AVAILABLE) { +- g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); +- } +- } +- g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg)); +- +- /* relinquish use of locality 0 */ +- writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY); +- access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); +-} ++uint64_t tpm_tis_base_addr = TPM_TIS_ADDR_BASE; + + int main(int argc, char **argv) + { +diff --git a/tests/tpm-tis-util.c b/tests/tpm-tis-util.c +new file mode 100644 +index 00000000..9aff503f +--- /dev/null ++++ b/tests/tpm-tis-util.c +@@ -0,0 +1,451 @@ ++/* ++ * QTest testcase for TPM TIS: common test functions used for both ++ * the ISA and SYSBUS devices ++ * ++ * Copyright (c) 2018 Red Hat, Inc. ++ * Copyright (c) 2018 IBM Corporation ++ * ++ * Authors: ++ * Marc-André Lureau ++ * Stefan Berger ++ * ++ * 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 ++ ++#include "hw/acpi/tpm.h" ++#include "io/channel-socket.h" ++#include "libqtest.h" ++#include "qemu/module.h" ++#include "tpm-emu.h" ++#include "tpm-util.h" ++#include "tpm-tis-util.h" ++ ++#define DEBUG_TIS_TEST 0 ++ ++#define DPRINTF(fmt, ...) do { \ ++ if (DEBUG_TIS_TEST) { \ ++ printf(fmt, ## __VA_ARGS__); \ ++ } \ ++} while (0) ++ ++#define DPRINTF_ACCESS \ ++ DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \ ++ __func__, __LINE__, locty, l, access, pending_request_flag) ++ ++#define DPRINTF_STS \ ++ DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts) ++ ++static const uint8_t TPM_CMD[12] = ++ "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"; ++ ++void tpm_tis_test_check_localities(const void *data) ++{ ++ uint8_t locty; ++ uint8_t access; ++ uint32_t ifaceid; ++ uint32_t capability; ++ uint32_t didvid; ++ uint32_t rid; ++ ++ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) { ++ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY)); ++ g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0); ++ ++ ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID)); ++ g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0); ++ ++ didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID)); ++ g_assert_cmpint(didvid, !=, 0); ++ g_assert_cmpint(didvid, !=, 0xffffffff); ++ ++ rid = readl(TIS_REG(locty, TPM_TIS_REG_RID)); ++ g_assert_cmpint(rid, !=, 0); ++ g_assert_cmpint(rid, !=, 0xffffffff); ++ } ++} ++ ++void tpm_tis_test_check_access_reg(const void *data) ++{ ++ uint8_t locty; ++ uint8_t access; ++ ++ /* do not test locality 4 (hw only) */ ++ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* request use of locality */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* release access */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ } ++} ++ ++/* ++ * Test case for seizing access by a higher number locality ++ */ ++void tpm_tis_test_check_access_reg_seize(const void *data) ++{ ++ int locty, l; ++ uint8_t access; ++ uint8_t pending_request_flag; ++ ++ /* do not test locality 4 (hw only) */ ++ for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { ++ pending_request_flag = 0; ++ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* request use of locality */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* lower localities cannot seize access */ ++ for (l = 0; l < locty; l++) { ++ /* lower locality is not active */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* try to request use from 'l' */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ ++ /* ++ * requesting use from 'l' was not possible; ++ * we must see REQUEST_USE and possibly PENDING_REQUEST ++ */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_REQUEST_USE | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* ++ * locality 'locty' must be unchanged; ++ * we must see PENDING_REQUEST ++ */ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_PENDING_REQUEST | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* try to seize from 'l' */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); ++ /* seize from 'l' was not possible */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_REQUEST_USE | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* locality 'locty' must be unchanged */ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_PENDING_REQUEST | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* ++ * on the next loop we will have a PENDING_REQUEST flag ++ * set for locality 'l' ++ */ ++ pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; ++ } ++ ++ /* ++ * higher localities can 'seize' access but not 'request use'; ++ * note: this will activate first l+1, then l+2 etc. ++ */ ++ for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { ++ /* try to 'request use' from 'l' */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ ++ /* ++ * requesting use from 'l' was not possible; we should see ++ * REQUEST_USE and may see PENDING_REQUEST ++ */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_REQUEST_USE | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* ++ * locality 'l-1' must be unchanged; we should always ++ * see PENDING_REQUEST from 'l' requesting access ++ */ ++ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_PENDING_REQUEST | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* try to seize from 'l' */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); ++ ++ /* seize from 'l' was possible */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* l - 1 should show that it has BEEN_SEIZED */ ++ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_BEEN_SEIZED | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* clear the BEEN_SEIZED flag and make sure it's gone */ ++ writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_BEEN_SEIZED); ++ ++ access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ } ++ ++ /* ++ * PENDING_REQUEST will not be set if locty = 0 since all localities ++ * were active; in case of locty = 1, locality 0 will be active ++ * but no PENDING_REQUEST anywhere ++ */ ++ if (locty <= 1) { ++ pending_request_flag = 0; ++ } ++ ++ /* release access from l - 1; this activates locty - 1 */ ++ l--; ++ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ ++ DPRINTF("%s: %d: relinquishing control on l = %d\n", ++ __func__, __LINE__, l); ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ for (l = locty - 1; l >= 0; l--) { ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* release this locality */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ ++ if (l == 1) { ++ pending_request_flag = 0; ++ } ++ } ++ ++ /* no locality may be active now */ ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ } ++ } ++} ++ ++/* ++ * Test case for getting access when higher number locality relinquishes access ++ */ ++void tpm_tis_test_check_access_reg_release(const void *data) ++{ ++ int locty, l; ++ uint8_t access; ++ uint8_t pending_request_flag; ++ ++ /* do not test locality 4 (hw only) */ ++ for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) { ++ pending_request_flag = 0; ++ ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* request use of locality */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ /* request use of all other localities */ ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { ++ if (l == locty) { ++ continue; ++ } ++ /* ++ * request use of locality 'l' -- we MUST see REQUEST USE and ++ * may see PENDING_REQUEST ++ */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_REQUEST_USE | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; ++ } ++ /* release locality 'locty' */ ++ writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ /* ++ * highest locality should now be active; release it and make sure the ++ * next higest locality is active afterwards ++ */ ++ for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) { ++ if (l == locty) { ++ continue; ++ } ++ /* 'l' should be active now */ ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ /* 'l' relinquishes access */ ++ writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); ++ DPRINTF_ACCESS; ++ if (l == 1 || (locty <= 1 && l == 2)) { ++ pending_request_flag = 0; ++ } ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ pending_request_flag | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ } ++ } ++} ++ ++/* ++ * Test case for transmitting packets ++ */ ++void tpm_tis_test_check_transmit(const void *data) ++{ ++ const TestState *s = data; ++ uint8_t access; ++ uint32_t sts; ++ uint16_t bcount; ++ size_t i; ++ ++ /* request use of locality 0 */ ++ writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); ++ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); ++ g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY | ++ TPM_TIS_ACCESS_TPM_ESTABLISHMENT); ++ ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ ++ g_assert_cmpint(sts & 0xff, ==, 0); ++ g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==, ++ TPM_TIS_STS_TPM_FAMILY2_0); ++ ++ bcount = (sts >> 8) & 0xffff; ++ g_assert_cmpint(bcount, >=, 128); ++ ++ writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY); ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY); ++ ++ /* transmit command */ ++ for (i = 0; i < sizeof(TPM_CMD); i++) { ++ writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]); ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ if (i < sizeof(TPM_CMD) - 1) { ++ g_assert_cmpint(sts & 0xff, ==, ++ TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); ++ } else { ++ g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID); ++ } ++ g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); ++ } ++ /* start processing */ ++ writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO); ++ ++ uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND; ++ do { ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) { ++ break; ++ } ++ } while (g_get_monotonic_time() < end_time); ++ ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ g_assert_cmpint(sts & 0xff, == , ++ TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); ++ bcount = (sts >> 8) & 0xffff; ++ ++ /* read response */ ++ uint8_t tpm_msg[sizeof(struct tpm_hdr)]; ++ g_assert_cmpint(sizeof(tpm_msg), ==, bcount); ++ ++ for (i = 0; i < sizeof(tpm_msg); i++) { ++ tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO)); ++ sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); ++ DPRINTF_STS; ++ if (sts & TPM_TIS_STS_DATA_AVAILABLE) { ++ g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); ++ } ++ } ++ g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg)); ++ ++ /* relinquish use of locality 0 */ ++ writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); ++} +diff --git a/tests/tpm-tis-util.h b/tests/tpm-tis-util.h +new file mode 100644 +index 00000000..d10efe86 +--- /dev/null ++++ b/tests/tpm-tis-util.h +@@ -0,0 +1,23 @@ ++/* ++ * QTest TPM TIS: Common test functions used for both the ++ * ISA and SYSBUS devices ++ * ++ * Copyright (c) 2018 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ */ ++ ++#ifndef TESTS_TPM_TIS_UTIL_H ++#define TESTS_TPM_TIS_UTIL_H ++ ++void tpm_tis_test_check_localities(const void *data); ++void tpm_tis_test_check_access_reg(const void *data); ++void tpm_tis_test_check_access_reg_seize(const void *data); ++void tpm_tis_test_check_access_reg_release(const void *data); ++void tpm_tis_test_check_transmit(const void *data); ++ ++#endif /* TESTS_TPM_TIS_UTIL_H */ +diff --git a/tests/tpm-util.c b/tests/tpm-util.c +index e08b1376..34efae8f 100644 +--- a/tests/tpm-util.c ++++ b/tests/tpm-util.c +@@ -19,9 +19,6 @@ + #include "tpm-util.h" + #include "qapi/qmp/qdict.h" + +-#define TIS_REG(LOCTY, REG) \ +- (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG) +- + void tpm_util_crb_transfer(QTestState *s, + const unsigned char *req, size_t req_size, + unsigned char *rsp, size_t rsp_size) +@@ -258,23 +255,27 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu, + SocketAddress *src_tpm_addr, + SocketAddress *dst_tpm_addr, + const char *miguri, +- const char *ifmodel) ++ const char *ifmodel, ++ const char *machine_options) + { + char *src_qemu_args, *dst_qemu_args; + + src_qemu_args = g_strdup_printf( ++ "%s " + "-chardev socket,id=chr,path=%s " + "-tpmdev emulator,id=dev,chardev=chr " + "-device %s,tpmdev=dev ", +- src_tpm_addr->u.q_unix.path, ifmodel); ++ machine_options ? : "", src_tpm_addr->u.q_unix.path, ifmodel); + + *src_qemu = qtest_init(src_qemu_args); + + dst_qemu_args = g_strdup_printf( ++ "%s " + "-chardev socket,id=chr,path=%s " + "-tpmdev emulator,id=dev,chardev=chr " + "-device %s,tpmdev=dev " + "-incoming %s", ++ machine_options ? : "", + dst_tpm_addr->u.q_unix.path, + ifmodel, miguri); + +diff --git a/tests/tpm-util.h b/tests/tpm-util.h +index 5755698a..3b97d690 100644 +--- a/tests/tpm-util.h ++++ b/tests/tpm-util.h +@@ -15,6 +15,11 @@ + + #include "io/channel-socket.h" + ++extern uint64_t tpm_tis_base_addr; ++ ++#define TIS_REG(LOCTY, REG) \ ++ (tpm_tis_base_addr + ((LOCTY) << 12) + REG) ++ + typedef void (tx_func)(QTestState *s, + const unsigned char *req, size_t req_size, + unsigned char *rsp, size_t rsp_size); +@@ -44,7 +49,8 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu, + SocketAddress *src_tpm_addr, + SocketAddress *dst_tpm_addr, + const char *miguri, +- const char *ifmodel); ++ const char *ifmodel, ++ const char *machine_options); + + void tpm_util_wait_for_migration_complete(QTestState *who); + +-- +2.23.0 + diff --git a/tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch b/tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch new file mode 100644 index 0000000000000000000000000000000000000000..22dd7a50b2b7102c85db434bebddb929dca05094 --- /dev/null +++ b/tpm-Move-tpm_tis_show_buffer-to-tpm_util.c.patch @@ -0,0 +1,145 @@ +From 3688d73b6e2b7b3fb71ed9fb6e38fd05d39de05b Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:30 -0500 +Subject: [PATCH 3417/5109] tpm: Move tpm_tis_show_buffer to tpm_util.c +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Stefan Berger +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: David Gibson +Message-Id: <20200121152935.649898-2-stefanb@linux.ibm.com> +Signed-off-by: David Gibson +--- + hw/tpm/tpm_tis.c | 32 ++++---------------------------- + hw/tpm/tpm_util.c | 25 +++++++++++++++++++++++++ + hw/tpm/tpm_util.h | 3 +++ + hw/tpm/trace-events | 2 +- + 4 files changed, 33 insertions(+), 29 deletions(-) + +diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c +index 5362df2711..31facb896d 100644 +--- a/hw/tpm/tpm_tis.c ++++ b/hw/tpm/tpm_tis.c +@@ -107,30 +107,6 @@ static uint8_t tpm_tis_locality_from_addr(hwaddr addr) + return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); + } + +-static void tpm_tis_show_buffer(const unsigned char *buffer, +- size_t buffer_size, const char *string) +-{ +- size_t len, i; +- char *line_buffer, *p; +- +- len = MIN(tpm_cmd_get_size(buffer), buffer_size); +- +- /* +- * allocate enough room for 3 chars per buffer entry plus a +- * newline after every 16 chars and a final null terminator. +- */ +- line_buffer = g_malloc(len * 3 + (len / 16) + 1); +- +- for (i = 0, p = line_buffer; i < len; i++) { +- if (i && !(i % 16)) { +- p += sprintf(p, "\n"); +- } +- p += sprintf(p, "%.2X ", buffer[i]); +- } +- trace_tpm_tis_show_buffer(string, len, line_buffer); +- +- g_free(line_buffer); +-} + + /* + * Set the given flags in the STS register by clearing the register but +@@ -156,8 +132,8 @@ static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags) + */ + static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) + { +- if (trace_event_get_state_backends(TRACE_TPM_TIS_SHOW_BUFFER)) { +- tpm_tis_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); ++ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); + } + + /* +@@ -325,8 +301,8 @@ static void tpm_tis_request_completed(TPMIf *ti, int ret) + s->loc[locty].state = TPM_TIS_STATE_COMPLETION; + s->rw_offset = 0; + +- if (trace_event_get_state_backends(TRACE_TPM_TIS_SHOW_BUFFER)) { +- tpm_tis_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); ++ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); + } + + if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) { +diff --git a/hw/tpm/tpm_util.c b/hw/tpm/tpm_util.c +index 62b091f0c0..c0a0f3d71f 100644 +--- a/hw/tpm/tpm_util.c ++++ b/hw/tpm/tpm_util.c +@@ -350,3 +350,28 @@ void tpm_sized_buffer_reset(TPMSizedBuffer *tsb) + tsb->buffer = NULL; + tsb->size = 0; + } ++ ++void tpm_util_show_buffer(const unsigned char *buffer, ++ size_t buffer_size, const char *string) ++{ ++ size_t len, i; ++ char *line_buffer, *p; ++ ++ len = MIN(tpm_cmd_get_size(buffer), buffer_size); ++ ++ /* ++ * allocate enough room for 3 chars per buffer entry plus a ++ * newline after every 16 chars and a final null terminator. ++ */ ++ line_buffer = g_malloc(len * 3 + (len / 16) + 1); ++ ++ for (i = 0, p = line_buffer; i < len; i++) { ++ if (i && !(i % 16)) { ++ p += sprintf(p, "\n"); ++ } ++ p += sprintf(p, "%.2X ", buffer[i]); ++ } ++ trace_tpm_util_show_buffer(string, len, line_buffer); ++ ++ g_free(line_buffer); ++} +diff --git a/hw/tpm/tpm_util.h b/hw/tpm/tpm_util.h +index f397ac21b8..7889081fba 100644 +--- a/hw/tpm/tpm_util.h ++++ b/hw/tpm/tpm_util.h +@@ -79,4 +79,7 @@ typedef struct TPMSizedBuffer { + + void tpm_sized_buffer_reset(TPMSizedBuffer *tsb); + ++void tpm_util_show_buffer(const unsigned char *buffer, ++ size_t buffer_size, const char *string); ++ + #endif /* TPM_TPM_UTIL_H */ +diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events +index 89804bcd64..357c9e9a84 100644 +--- a/hw/tpm/trace-events ++++ b/hw/tpm/trace-events +@@ -14,6 +14,7 @@ tpm_util_get_buffer_size_len(uint32_t len, size_t expected) "tpm_resp->len = %u, + tpm_util_get_buffer_size_hdr_len2(uint32_t len, size_t expected) "tpm2_resp->hdr.len = %u, expected = %zu" + tpm_util_get_buffer_size_len2(uint32_t len, size_t expected) "tpm2_resp->len = %u, expected = %zu" + tpm_util_get_buffer_size(size_t len) "buffersize of device: %zu" ++tpm_util_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s" + + # tpm_emulator.c + tpm_emulator_set_locality(uint8_t locty) "setting locality to %d" +@@ -36,7 +37,6 @@ tpm_emulator_pre_save(void) "" + tpm_emulator_inst_init(void) "" + + # tpm_tis.c +-tpm_tis_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\nbuf: %s" + tpm_tis_raise_irq(uint32_t irqmask) "Raising IRQ for flag 0x%08x" + tpm_tis_new_active_locality(uint8_t locty) "Active locality is now %d" + tpm_tis_abort(uint8_t locty) "New active locality is %d" +-- +2.18.2 + diff --git a/tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.pa.patch b/tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.pa.patch new file mode 100644 index 0000000000000000000000000000000000000000..8ec89fdcf152ff84cd8ad0c65eafb73055590d2b --- /dev/null +++ b/tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.pa.patch @@ -0,0 +1,90 @@ +From bb7c12054b4bdcb559cce828dfc9382c97b6eeff Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Wed, 29 Jul 2020 13:44:49 +0000 +Subject: [PATCH] 4296-tpm-Separate-TPM_TIS-and-TPM_TIS_ISA-configs.patch + +--- + default-configs/i386-softmmu.mak | 2 +- + hw/i386/Kconfig | 2 +- + hw/tpm/Kconfig | 7 ++++++- + hw/tpm/Makefile.objs | 3 ++- + tests/Makefile.include | 4 ++-- + 5 files changed, 12 insertions(+), 6 deletions(-) + +diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak +index cd5ea391..bdeef670 100644 +--- a/default-configs/i386-softmmu.mak ++++ b/default-configs/i386-softmmu.mak +@@ -17,7 +17,7 @@ + #CONFIG_SGA=n + #CONFIG_TEST_DEVICES=n + #CONFIG_TPM_CRB=n +-#CONFIG_TPM_TIS=n ++#CONFIG_TPM_TIS_ISA=n + #CONFIG_VTD=n + + # Boards: +diff --git a/hw/i386/Kconfig b/hw/i386/Kconfig +index 63504380..60334504 100644 +--- a/hw/i386/Kconfig ++++ b/hw/i386/Kconfig +@@ -17,7 +17,7 @@ config PC + imply SGA + imply TEST_DEVICES + imply TPM_CRB +- imply TPM_TIS ++ imply TPM_TIS_ISA + imply VGA_PCI + imply VIRTIO_VGA + select FDC +diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig +index 9e67d990..686f8206 100644 +--- a/hw/tpm/Kconfig ++++ b/hw/tpm/Kconfig +@@ -2,9 +2,14 @@ config TPMDEV + bool + depends on TPM + +-config TPM_TIS ++config TPM_TIS_ISA + bool + depends on TPM && ISA_BUS ++ select TPM_TIS ++ ++config TPM_TIS ++ bool ++ depends on TPM + select TPMDEV + + config TPM_CRB +diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs +index fcc4c2f2..3ef2036c 100644 +--- a/hw/tpm/Makefile.objs ++++ b/hw/tpm/Makefile.objs +@@ -1,6 +1,7 @@ + common-obj-$(CONFIG_TPM) += tpm_util.o + obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o +-common-obj-$(CONFIG_TPM_TIS) += tpm_tis_isa.o tpm_tis_common.o ++common-obj-$(CONFIG_TPM_TIS_ISA) += tpm_tis_isa.o ++common-obj-$(CONFIG_TPM_TIS) += tpm_tis_common.o + common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o + common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o + common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o +diff --git a/tests/Makefile.include b/tests/Makefile.include +index d8cf00c1..b9da8d3a 100644 +--- a/tests/Makefile.include ++++ b/tests/Makefile.include +@@ -191,8 +191,8 @@ check-qtest-i386-y += tests/q35-test$(EXESUF) + check-qtest-i386-y += tests/vmgenid-test$(EXESUF) + check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-swtpm-test$(EXESUF) + check-qtest-i386-$(CONFIG_TPM_CRB) += tests/tpm-crb-test$(EXESUF) +-check-qtest-i386-$(CONFIG_TPM_TIS) += tests/tpm-tis-swtpm-test$(EXESUF) +-check-qtest-i386-$(CONFIG_TPM_TIS) += tests/tpm-tis-test$(EXESUF) ++check-qtest-i386-$(CONFIG_TPM_TIS_ISA) += tests/tpm-tis-swtpm-test$(EXESUF) ++check-qtest-i386-$(CONFIG_TPM_TIS_ISA) += tests/tpm-tis-test$(EXESUF) + check-qtest-i386-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) + check-qtest-i386-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) + check-qtest-i386-$(CONFIG_RTL8139_PCI) += tests/test-filter-redirector$(EXESUF) +-- +2.23.0 + diff --git a/tpm-Separate-tpm_tis-common-functions-from-isa-.patch b/tpm-Separate-tpm_tis-common-functions-from-isa-.patch new file mode 100644 index 0000000000000000000000000000000000000000..7f18933d0ee063ac4c12712933969ff8a4fef3c6 --- /dev/null +++ b/tpm-Separate-tpm_tis-common-functions-from-isa-.patch @@ -0,0 +1,1335 @@ +From 9342cca35d5fe0ff0eafb29589e4482ce7597f3d Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Wed, 29 Jul 2020 12:49:23 +0000 +Subject: [PATCH] + 4295-tpm-Separate-tpm_tis-common-functions-from-isa-code.patch + +--- + hw/tpm/Makefile.objs | 2 +- + hw/tpm/{tpm_tis.c => tpm_tis.c.orig} | 0 + hw/tpm/tpm_tis.h | 91 +++ + hw/tpm/tpm_tis_common.c | 869 +++++++++++++++++++++++++++ + hw/tpm/tpm_tis_common.c.orig | 0 + hw/tpm/tpm_tis_common.c.rej | 137 +++++ + hw/tpm/tpm_tis_isa.c | 170 ++++++ + 7 files changed, 1268 insertions(+), 1 deletion(-) + rename hw/tpm/{tpm_tis.c => tpm_tis.c.orig} (100%) + create mode 100644 hw/tpm/tpm_tis.h + create mode 100644 hw/tpm/tpm_tis_common.c + create mode 100644 hw/tpm/tpm_tis_common.c.orig + create mode 100644 hw/tpm/tpm_tis_common.c.rej + create mode 100644 hw/tpm/tpm_tis_isa.c + +diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs +index 85eb99ae..fcc4c2f2 100644 +--- a/hw/tpm/Makefile.objs ++++ b/hw/tpm/Makefile.objs +@@ -1,6 +1,6 @@ + common-obj-$(CONFIG_TPM) += tpm_util.o + obj-$(call lor,$(CONFIG_TPM_TIS),$(CONFIG_TPM_CRB)) += tpm_ppi.o +-common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o ++common-obj-$(CONFIG_TPM_TIS) += tpm_tis_isa.o tpm_tis_common.o + common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o + common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o + common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o +diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c.orig +similarity index 100% +rename from hw/tpm/tpm_tis.c +rename to hw/tpm/tpm_tis.c.orig +diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h +new file mode 100644 +index 00000000..55549893 +--- /dev/null ++++ b/hw/tpm/tpm_tis.h +@@ -0,0 +1,91 @@ ++/* ++ * tpm_tis.h - QEMU's TPM TIS common header ++ * ++ * Copyright (C) 2006,2010-2013 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * David Safford ++ * ++ * Xen 4 support: Andrease Niederl ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ * Implementation of the TIS interface according to specs found at ++ * http://www.trustedcomputinggroup.org. This implementation currently ++ * supports version 1.3, 21 March 2013 ++ * In the developers menu choose the PC Client section then find the TIS ++ * specification. ++ * ++ * TPM TIS for TPM 2 implementation following TCG PC Client Platform ++ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 ++ */ ++#ifndef TPM_TPM_TIS_H ++#define TPM_TPM_TIS_H ++ ++#include "qemu/osdep.h" ++#include "sysemu/tpm_backend.h" ++#include "tpm_ppi.h" ++ ++#define TPM_TIS_NUM_LOCALITIES 5 /* per spec */ ++#define TPM_TIS_LOCALITY_SHIFT 12 ++#define TPM_TIS_NO_LOCALITY 0xff ++ ++#define TPM_TIS_IS_VALID_LOCTY(x) ((x) < TPM_TIS_NUM_LOCALITIES) ++ ++#define TPM_TIS_BUFFER_MAX 4096 ++ ++typedef enum { ++ TPM_TIS_STATE_IDLE = 0, ++ TPM_TIS_STATE_READY, ++ TPM_TIS_STATE_COMPLETION, ++ TPM_TIS_STATE_EXECUTION, ++ TPM_TIS_STATE_RECEPTION, ++} TPMTISState; ++ ++/* locality data -- all fields are persisted */ ++typedef struct TPMLocality { ++ TPMTISState state; ++ uint8_t access; ++ uint32_t sts; ++ uint32_t iface_id; ++ uint32_t inte; ++ uint32_t ints; ++} TPMLocality; ++ ++typedef struct TPMState { ++ MemoryRegion mmio; ++ ++ unsigned char buffer[TPM_TIS_BUFFER_MAX]; ++ uint16_t rw_offset; ++ ++ uint8_t active_locty; ++ uint8_t aborting_locty; ++ uint8_t next_locty; ++ ++ TPMLocality loc[TPM_TIS_NUM_LOCALITIES]; ++ ++ qemu_irq irq; ++ uint32_t irq_num; ++ ++ TPMBackendCmd cmd; ++ ++ TPMBackend *be_driver; ++ TPMVersion be_tpm_version; ++ ++ size_t be_buffer_size; ++ ++ bool ppi_enabled; ++ TPMPPI ppi; ++} TPMState; ++ ++extern const VMStateDescription vmstate_locty; ++extern const MemoryRegionOps tpm_tis_memory_ops; ++ ++int tpm_tis_pre_save(TPMState *s); ++void tpm_tis_reset(TPMState *s); ++enum TPMVersion tpm_tis_get_tpm_version(TPMState *s); ++void tpm_tis_request_completed(TPMState *s, int ret); ++ ++#endif /* TPM_TPM_TIS_H */ +diff --git a/hw/tpm/tpm_tis_common.c b/hw/tpm/tpm_tis_common.c +new file mode 100644 +index 00000000..9a51c71e +--- /dev/null ++++ b/hw/tpm/tpm_tis_common.c +@@ -0,0 +1,869 @@ ++/* ++ * tpm_tis_common.c - QEMU's TPM TIS interface emulator ++ * device agnostic functions ++ * ++ * Copyright (C) 2006,2010-2013 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * David Safford ++ * ++ * Xen 4 support: Andrease Niederl ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ * Implementation of the TIS interface according to specs found at ++ * http://www.trustedcomputinggroup.org. This implementation currently ++ * supports version 1.3, 21 March 2013 ++ * In the developers menu choose the PC Client section then find the TIS ++ * specification. ++ * ++ * TPM TIS for TPM 2 implementation following TCG PC Client Platform ++ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 ++ */ ++#include "qemu/osdep.h" ++#include "hw/isa/isa.h" ++#include "qapi/error.h" ++#include "qemu/module.h" ++ ++#include "hw/acpi/tpm.h" ++#include "hw/pci/pci_ids.h" ++#include "sysemu/tpm_backend.h" ++#include "tpm_int.h" ++#include "tpm_util.h" ++#include "tpm_ppi.h" ++#include "trace.h" ++ ++#include "tpm_tis.h" ++ ++#define DEBUG_TIS 0 ++ ++/* local prototypes */ ++ ++static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, ++ unsigned size); ++ ++/* utility functions */ ++ ++static uint8_t tpm_tis_locality_from_addr(hwaddr addr) ++{ ++ return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); ++} ++ ++ ++/* ++ * Set the given flags in the STS register by clearing the register but ++ * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting ++ * the new flags. ++ * ++ * The SELFTEST_DONE flag is acquired from the backend that determines it by ++ * peeking into TPM commands. ++ * ++ * A VM suspend/resume will preserve the flag by storing it into the VM ++ * device state, but the backend will not remember it when QEMU is started ++ * again. Therefore, we cache the flag here. Once set, it will not be unset ++ * except by a reset. ++ */ ++static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags) ++{ ++ l->sts &= TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK; ++ l->sts |= flags; ++} ++ ++/* ++ * Send a request to the TPM. ++ */ ++static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) ++{ ++ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); ++ } ++ ++ /* ++ * rw_offset serves as length indicator for length of data; ++ * it's reset when the response comes back ++ */ ++ s->loc[locty].state = TPM_TIS_STATE_EXECUTION; ++ ++ s->cmd = (TPMBackendCmd) { ++ .locty = locty, ++ .in = s->buffer, ++ .in_len = s->rw_offset, ++ .out = s->buffer, ++ .out_len = s->be_buffer_size, ++ }; ++ ++ tpm_backend_deliver_request(s->be_driver, &s->cmd); ++} ++ ++/* raise an interrupt if allowed */ ++static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask) ++{ ++ if (!TPM_TIS_IS_VALID_LOCTY(locty)) { ++ return; ++ } ++ ++ if ((s->loc[locty].inte & TPM_TIS_INT_ENABLED) && ++ (s->loc[locty].inte & irqmask)) { ++ trace_tpm_tis_raise_irq(irqmask); ++ qemu_irq_raise(s->irq); ++ s->loc[locty].ints |= irqmask; ++ } ++} ++ ++static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty) ++{ ++ uint8_t l; ++ ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { ++ if (l == locty) { ++ continue; ++ } ++ if ((s->loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) { ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty) ++{ ++ bool change = (s->active_locty != new_active_locty); ++ bool is_seize; ++ uint8_t mask; ++ ++ if (change && TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { ++ is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) && ++ s->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE; ++ ++ if (is_seize) { ++ mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ } else { ++ mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY| ++ TPM_TIS_ACCESS_REQUEST_USE); ++ } ++ /* reset flags on the old active locality */ ++ s->loc[s->active_locty].access &= mask; ++ ++ if (is_seize) { ++ s->loc[s->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED; ++ } ++ } ++ ++ s->active_locty = new_active_locty; ++ ++ trace_tpm_tis_new_active_locality(s->active_locty); ++ ++ if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) { ++ /* set flags on the new active locality */ ++ s->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY; ++ s->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE | ++ TPM_TIS_ACCESS_SEIZE); ++ } ++ ++ if (change) { ++ tpm_tis_raise_irq(s, s->active_locty, TPM_TIS_INT_LOCALITY_CHANGED); ++ } ++} ++ ++/* abort -- this function switches the locality */ ++static void tpm_tis_abort(TPMState *s) ++{ ++ s->rw_offset = 0; ++ ++ trace_tpm_tis_abort(s->next_locty); ++ ++ /* ++ * Need to react differently depending on who's aborting now and ++ * which locality will become active afterwards. ++ */ ++ if (s->aborting_locty == s->next_locty) { ++ s->loc[s->aborting_locty].state = TPM_TIS_STATE_READY; ++ tpm_tis_sts_set(&s->loc[s->aborting_locty], ++ TPM_TIS_STS_COMMAND_READY); ++ tpm_tis_raise_irq(s, s->aborting_locty, TPM_TIS_INT_COMMAND_READY); ++ } ++ ++ /* locality after abort is another one than the current one */ ++ tpm_tis_new_active_locality(s, s->next_locty); ++ ++ s->next_locty = TPM_TIS_NO_LOCALITY; ++ /* nobody's aborting a command anymore */ ++ s->aborting_locty = TPM_TIS_NO_LOCALITY; ++} ++ ++/* prepare aborting current command */ ++static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty) ++{ ++ uint8_t busy_locty; ++ ++ assert(TPM_TIS_IS_VALID_LOCTY(newlocty)); ++ ++ s->aborting_locty = locty; /* may also be TPM_TIS_NO_LOCALITY */ ++ s->next_locty = newlocty; /* locality after successful abort */ ++ ++ /* ++ * only abort a command using an interrupt if currently executing ++ * a command AND if there's a valid connection to the vTPM. ++ */ ++ for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) { ++ if (s->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) { ++ /* ++ * request the backend to cancel. Some backends may not ++ * support it ++ */ ++ tpm_backend_cancel_cmd(s->be_driver); ++ return; ++ } ++ } ++ ++ tpm_tis_abort(s); ++} ++ ++/* ++ * Callback from the TPM to indicate that the response was received. ++ */ ++void tpm_tis_request_completed(TPMState *s, int ret) ++{ ++ uint8_t locty = s->cmd.locty; ++ uint8_t l; ++ ++ assert(TPM_TIS_IS_VALID_LOCTY(locty)); ++ ++ if (s->cmd.selftest_done) { ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { ++ s->loc[l].sts |= TPM_TIS_STS_SELFTEST_DONE; ++ } ++ } ++ ++ /* FIXME: report error if ret != 0 */ ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); ++ s->loc[locty].state = TPM_TIS_STATE_COMPLETION; ++ s->rw_offset = 0; ++ ++ if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); ++ } ++ ++ if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) { ++ tpm_tis_abort(s); ++ } ++ ++ tpm_tis_raise_irq(s, locty, ++ TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID); ++} ++ ++/* ++ * Read a byte of response data ++ */ ++static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) ++{ ++ uint32_t ret = TPM_TIS_NO_DATA_BYTE; ++ uint16_t len; ++ ++ if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { ++ len = MIN(tpm_cmd_get_size(&s->buffer), ++ s->be_buffer_size); ++ ++ ret = s->buffer[s->rw_offset++]; ++ if (s->rw_offset >= len) { ++ /* got last byte */ ++ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); ++ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); ++ } ++ trace_tpm_tis_data_read(ret, s->rw_offset - 1); ++ } ++ ++ return ret; ++} ++ ++#ifdef DEBUG_TIS ++static void tpm_tis_dump_state(TPMState *s, hwaddr addr) ++{ ++ static const unsigned regs[] = { ++ TPM_TIS_REG_ACCESS, ++ TPM_TIS_REG_INT_ENABLE, ++ TPM_TIS_REG_INT_VECTOR, ++ TPM_TIS_REG_INT_STATUS, ++ TPM_TIS_REG_INTF_CAPABILITY, ++ TPM_TIS_REG_STS, ++ TPM_TIS_REG_DID_VID, ++ TPM_TIS_REG_RID, ++ 0xfff}; ++ int idx; ++ uint8_t locty = tpm_tis_locality_from_addr(addr); ++ hwaddr base = addr & ~0xfff; ++ ++ printf("tpm_tis: active locality : %d\n" ++ "tpm_tis: state of locality %d : %d\n" ++ "tpm_tis: register dump:\n", ++ s->active_locty, ++ locty, s->loc[locty].state); ++ ++ for (idx = 0; regs[idx] != 0xfff; idx++) { ++ printf("tpm_tis: 0x%04x : 0x%08x\n", regs[idx], ++ (int)tpm_tis_mmio_read(s, base + regs[idx], 4)); ++ } ++ ++ printf("tpm_tis: r/w offset : %d\n" ++ "tpm_tis: result buffer : ", ++ s->rw_offset); ++ for (idx = 0; ++ idx < MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size); ++ idx++) { ++ printf("%c%02x%s", ++ s->rw_offset == idx ? '>' : ' ', ++ s->buffer[idx], ++ ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); ++ } ++ printf("\n"); ++} ++#endif ++ ++/* ++ * Read a register of the TIS interface ++ * See specs pages 33-63 for description of the registers ++ */ ++static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, ++ unsigned size) ++{ ++ TPMState *s = opaque; ++ uint16_t offset = addr & 0xffc; ++ uint8_t shift = (addr & 0x3) * 8; ++ uint32_t val = 0xffffffff; ++ uint8_t locty = tpm_tis_locality_from_addr(addr); ++ uint32_t avail; ++ uint8_t v; ++ ++ if (tpm_backend_had_startup_error(s->be_driver)) { ++ return 0; ++ } ++ ++ switch (offset) { ++ case TPM_TIS_REG_ACCESS: ++ /* never show the SEIZE flag even though we use it internally */ ++ val = s->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE; ++ /* the pending flag is always calculated */ ++ if (tpm_tis_check_request_use_except(s, locty)) { ++ val |= TPM_TIS_ACCESS_PENDING_REQUEST; ++ } ++ val |= !tpm_backend_get_tpm_established_flag(s->be_driver); ++ break; ++ case TPM_TIS_REG_INT_ENABLE: ++ val = s->loc[locty].inte; ++ break; ++ case TPM_TIS_REG_INT_VECTOR: ++ val = s->irq_num; ++ break; ++ case TPM_TIS_REG_INT_STATUS: ++ val = s->loc[locty].ints; ++ break; ++ case TPM_TIS_REG_INTF_CAPABILITY: ++ switch (s->be_tpm_version) { ++ case TPM_VERSION_UNSPEC: ++ val = 0; ++ break; ++ case TPM_VERSION_1_2: ++ val = TPM_TIS_CAPABILITIES_SUPPORTED1_3; ++ break; ++ case TPM_VERSION_2_0: ++ val = TPM_TIS_CAPABILITIES_SUPPORTED2_0; ++ break; ++ } ++ break; ++ case TPM_TIS_REG_STS: ++ if (s->active_locty == locty) { ++ if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { ++ val = TPM_TIS_BURST_COUNT( ++ MIN(tpm_cmd_get_size(&s->buffer), ++ s->be_buffer_size) ++ - s->rw_offset) | s->loc[locty].sts; ++ } else { ++ avail = s->be_buffer_size - s->rw_offset; ++ /* ++ * byte-sized reads should not return 0x00 for 0x100 ++ * available bytes. ++ */ ++ if (size == 1 && avail > 0xff) { ++ avail = 0xff; ++ } ++ val = TPM_TIS_BURST_COUNT(avail) | s->loc[locty].sts; ++ } ++ } ++ break; ++ case TPM_TIS_REG_DATA_FIFO: ++ case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END: ++ if (s->active_locty == locty) { ++ if (size > 4 - (addr & 0x3)) { ++ /* prevent access beyond FIFO */ ++ size = 4 - (addr & 0x3); ++ } ++ val = 0; ++ shift = 0; ++ while (size > 0) { ++ switch (s->loc[locty].state) { ++ case TPM_TIS_STATE_COMPLETION: ++ v = tpm_tis_data_read(s, locty); ++ break; ++ default: ++ v = TPM_TIS_NO_DATA_BYTE; ++ break; ++ } ++ val |= (v << shift); ++ shift += 8; ++ size--; ++ } ++ shift = 0; /* no more adjustments */ ++ } ++ break; ++ case TPM_TIS_REG_INTERFACE_ID: ++ val = s->loc[locty].iface_id; ++ break; ++ case TPM_TIS_REG_DID_VID: ++ val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID; ++ break; ++ case TPM_TIS_REG_RID: ++ val = TPM_TIS_TPM_RID; ++ break; ++#ifdef DEBUG_TIS ++ case TPM_TIS_REG_DEBUG: ++ tpm_tis_dump_state(s, addr); ++ break; ++#endif ++ } ++ ++ if (shift) { ++ val >>= shift; ++ } ++ ++ trace_tpm_tis_mmio_read(size, addr, val); ++ ++ return val; ++} ++ ++/* ++ * Write a value to a register of the TIS interface ++ * See specs pages 33-63 for description of the registers ++ */ ++static void tpm_tis_mmio_write(void *opaque, hwaddr addr, ++ uint64_t val, unsigned size) ++{ ++ TPMState *s = opaque; ++ uint16_t off = addr & 0xffc; ++ uint8_t shift = (addr & 0x3) * 8; ++ uint8_t locty = tpm_tis_locality_from_addr(addr); ++ uint8_t active_locty, l; ++ int c, set_new_locty = 1; ++ uint16_t len; ++ uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0); ++ ++ trace_tpm_tis_mmio_write(size, addr, val); ++ ++ if (locty == 4) { ++ trace_tpm_tis_mmio_write_locty4(); ++ return; ++ } ++ ++ if (tpm_backend_had_startup_error(s->be_driver)) { ++ return; ++ } ++ ++ val &= mask; ++ ++ if (shift) { ++ val <<= shift; ++ mask <<= shift; ++ } ++ ++ mask ^= 0xffffffff; ++ ++ switch (off) { ++ case TPM_TIS_REG_ACCESS: ++ ++ if ((val & TPM_TIS_ACCESS_SEIZE)) { ++ val &= ~(TPM_TIS_ACCESS_REQUEST_USE | ++ TPM_TIS_ACCESS_ACTIVE_LOCALITY); ++ } ++ ++ active_locty = s->active_locty; ++ ++ if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) { ++ /* give up locality if currently owned */ ++ if (s->active_locty == locty) { ++ trace_tpm_tis_mmio_write_release_locty(locty); ++ ++ uint8_t newlocty = TPM_TIS_NO_LOCALITY; ++ /* anybody wants the locality ? */ ++ for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) { ++ if ((s->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) { ++ trace_tpm_tis_mmio_write_locty_req_use(c); ++ newlocty = c; ++ break; ++ } ++ } ++ trace_tpm_tis_mmio_write_next_locty(newlocty); ++ ++ if (TPM_TIS_IS_VALID_LOCTY(newlocty)) { ++ set_new_locty = 0; ++ tpm_tis_prep_abort(s, locty, newlocty); ++ } else { ++ active_locty = TPM_TIS_NO_LOCALITY; ++ } ++ } else { ++ /* not currently the owner; clear a pending request */ ++ s->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE; ++ } ++ } ++ ++ if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) { ++ s->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED; ++ } ++ ++ if ((val & TPM_TIS_ACCESS_SEIZE)) { ++ /* ++ * allow seize if a locality is active and the requesting ++ * locality is higher than the one that's active ++ * OR ++ * allow seize for requesting locality if no locality is ++ * active ++ */ ++ while ((TPM_TIS_IS_VALID_LOCTY(s->active_locty) && ++ locty > s->active_locty) || ++ !TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { ++ bool higher_seize = FALSE; ++ ++ /* already a pending SEIZE ? */ ++ if ((s->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) { ++ break; ++ } ++ ++ /* check for ongoing seize by a higher locality */ ++ for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) { ++ if ((s->loc[l].access & TPM_TIS_ACCESS_SEIZE)) { ++ higher_seize = TRUE; ++ break; ++ } ++ } ++ ++ if (higher_seize) { ++ break; ++ } ++ ++ /* cancel any seize by a lower locality */ ++ for (l = 0; l < locty; l++) { ++ s->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE; ++ } ++ ++ s->loc[locty].access |= TPM_TIS_ACCESS_SEIZE; ++ ++ trace_tpm_tis_mmio_write_locty_seized(locty, s->active_locty); ++ trace_tpm_tis_mmio_write_init_abort(); ++ ++ set_new_locty = 0; ++ tpm_tis_prep_abort(s, s->active_locty, locty); ++ break; ++ } ++ } ++ ++ if ((val & TPM_TIS_ACCESS_REQUEST_USE)) { ++ if (s->active_locty != locty) { ++ if (TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { ++ s->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE; ++ } else { ++ /* no locality active -> make this one active now */ ++ active_locty = locty; ++ } ++ } ++ } ++ ++ if (set_new_locty) { ++ tpm_tis_new_active_locality(s, active_locty); ++ } ++ ++ break; ++ case TPM_TIS_REG_INT_ENABLE: ++ if (s->active_locty != locty) { ++ break; ++ } ++ ++ s->loc[locty].inte &= mask; ++ s->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED | ++ TPM_TIS_INT_POLARITY_MASK | ++ TPM_TIS_INTERRUPTS_SUPPORTED)); ++ break; ++ case TPM_TIS_REG_INT_VECTOR: ++ /* hard wired -- ignore */ ++ break; ++ case TPM_TIS_REG_INT_STATUS: ++ if (s->active_locty != locty) { ++ break; ++ } ++ ++ /* clearing of interrupt flags */ ++ if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) && ++ (s->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) { ++ s->loc[locty].ints &= ~val; ++ if (s->loc[locty].ints == 0) { ++ qemu_irq_lower(s->irq); ++ trace_tpm_tis_mmio_write_lowering_irq(); ++ } ++ } ++ s->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED); ++ break; ++ case TPM_TIS_REG_STS: ++ if (s->active_locty != locty) { ++ break; ++ } ++ ++ if (s->be_tpm_version == TPM_VERSION_2_0) { ++ /* some flags that are only supported for TPM 2 */ ++ if (val & TPM_TIS_STS_COMMAND_CANCEL) { ++ if (s->loc[locty].state == TPM_TIS_STATE_EXECUTION) { ++ /* ++ * request the backend to cancel. Some backends may not ++ * support it ++ */ ++ tpm_backend_cancel_cmd(s->be_driver); ++ } ++ } ++ ++ if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) { ++ if (locty == 3 || locty == 4) { ++ tpm_backend_reset_tpm_established_flag(s->be_driver, locty); ++ } ++ } ++ } ++ ++ val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO | ++ TPM_TIS_STS_RESPONSE_RETRY); ++ ++ if (val == TPM_TIS_STS_COMMAND_READY) { ++ switch (s->loc[locty].state) { ++ ++ case TPM_TIS_STATE_READY: ++ s->rw_offset = 0; ++ break; ++ ++ case TPM_TIS_STATE_IDLE: ++ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_COMMAND_READY); ++ s->loc[locty].state = TPM_TIS_STATE_READY; ++ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY); ++ break; ++ ++ case TPM_TIS_STATE_EXECUTION: ++ case TPM_TIS_STATE_RECEPTION: ++ /* abort currently running command */ ++ trace_tpm_tis_mmio_write_init_abort(); ++ tpm_tis_prep_abort(s, locty, locty); ++ break; ++ ++ case TPM_TIS_STATE_COMPLETION: ++ s->rw_offset = 0; ++ /* shortcut to ready state with C/R set */ ++ s->loc[locty].state = TPM_TIS_STATE_READY; ++ if (!(s->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) { ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_COMMAND_READY); ++ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY); ++ } ++ s->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE); ++ break; ++ ++ } ++ } else if (val == TPM_TIS_STS_TPM_GO) { ++ switch (s->loc[locty].state) { ++ case TPM_TIS_STATE_RECEPTION: ++ if ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) { ++ tpm_tis_tpm_send(s, locty); ++ } ++ break; ++ default: ++ /* ignore */ ++ break; ++ } ++ } else if (val == TPM_TIS_STS_RESPONSE_RETRY) { ++ switch (s->loc[locty].state) { ++ case TPM_TIS_STATE_COMPLETION: ++ s->rw_offset = 0; ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_VALID| ++ TPM_TIS_STS_DATA_AVAILABLE); ++ break; ++ default: ++ /* ignore */ ++ break; ++ } ++ } ++ break; ++ case TPM_TIS_REG_DATA_FIFO: ++ case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END: ++ /* data fifo */ ++ if (s->active_locty != locty) { ++ break; ++ } ++ ++ if (s->loc[locty].state == TPM_TIS_STATE_IDLE || ++ s->loc[locty].state == TPM_TIS_STATE_EXECUTION || ++ s->loc[locty].state == TPM_TIS_STATE_COMPLETION) { ++ /* drop the byte */ ++ } else { ++ trace_tpm_tis_mmio_write_data2send(val, size); ++ if (s->loc[locty].state == TPM_TIS_STATE_READY) { ++ s->loc[locty].state = TPM_TIS_STATE_RECEPTION; ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); ++ } ++ ++ val >>= shift; ++ if (size > 4 - (addr & 0x3)) { ++ /* prevent access beyond FIFO */ ++ size = 4 - (addr & 0x3); ++ } ++ ++ while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) { ++ if (s->rw_offset < s->be_buffer_size) { ++ s->buffer[s->rw_offset++] = ++ (uint8_t)val; ++ val >>= 8; ++ size--; ++ } else { ++ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); ++ } ++ } ++ ++ /* check for complete packet */ ++ if (s->rw_offset > 5 && ++ (s->loc[locty].sts & TPM_TIS_STS_EXPECT)) { ++ /* we have a packet length - see if we have all of it */ ++ bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID); ++ ++ len = tpm_cmd_get_size(&s->buffer); ++ if (len > s->rw_offset) { ++ tpm_tis_sts_set(&s->loc[locty], ++ TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); ++ } else { ++ /* packet complete */ ++ tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); ++ } ++ if (need_irq) { ++ tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); ++ } ++ } ++ } ++ break; ++ case TPM_TIS_REG_INTERFACE_ID: ++ if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) { ++ for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { ++ s->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK; ++ } ++ } ++ break; ++ } ++} ++ ++const MemoryRegionOps tpm_tis_memory_ops = { ++ .read = tpm_tis_mmio_read, ++ .write = tpm_tis_mmio_write, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++ .valid = { ++ .min_access_size = 1, ++ .max_access_size = 4, ++ }, ++}; ++ ++/* ++ * Get the TPMVersion of the backend device being used ++ */ ++enum TPMVersion tpm_tis_get_tpm_version(TPMState *s) ++{ ++ if (tpm_backend_had_startup_error(s->be_driver)) { ++ return TPM_VERSION_UNSPEC; ++ } ++ ++ return tpm_backend_get_tpm_version(s->be_driver); ++} ++ ++/* ++ * This function is called when the machine starts, resets or due to ++ * S3 resume. ++ */ ++void tpm_tis_reset(TPMState *s) ++{ ++ int c; ++ ++ s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); ++ s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver), ++ TPM_TIS_BUFFER_MAX); ++ ++ if (s->ppi_enabled) { ++ tpm_ppi_reset(&s->ppi); ++ } ++ tpm_backend_reset(s->be_driver); ++ ++ s->active_locty = TPM_TIS_NO_LOCALITY; ++ s->next_locty = TPM_TIS_NO_LOCALITY; ++ s->aborting_locty = TPM_TIS_NO_LOCALITY; ++ ++ for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) { ++ s->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS; ++ switch (s->be_tpm_version) { ++ case TPM_VERSION_UNSPEC: ++ break; ++ case TPM_VERSION_1_2: ++ s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2; ++ s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3; ++ break; ++ case TPM_VERSION_2_0: ++ s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0; ++ s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0; ++ break; ++ } ++ s->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL; ++ s->loc[c].ints = 0; ++ s->loc[c].state = TPM_TIS_STATE_IDLE; ++ ++ s->rw_offset = 0; ++ } ++ ++ if (tpm_backend_startup_tpm(s->be_driver, s->be_buffer_size) < 0) { ++ exit(1); ++ } ++} ++ ++/* persistent state handling */ ++ ++int tpm_tis_pre_save(TPMState *s) ++{ ++ uint8_t locty = s->active_locty; ++ ++ trace_tpm_tis_pre_save(locty, s->rw_offset); ++ ++ if (DEBUG_TIS) { ++ tpm_tis_dump_state(s, 0); ++ } ++ ++ /* ++ * Synchronize with backend completion. ++ */ ++ tpm_backend_finish_sync(s->be_driver); ++ ++ return 0; ++} ++ ++const VMStateDescription vmstate_locty = { ++ .name = "tpm-tis/locty", ++ .version_id = 0, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT32(state, TPMLocality), ++ VMSTATE_UINT32(inte, TPMLocality), ++ VMSTATE_UINT32(ints, TPMLocality), ++ VMSTATE_UINT8(access, TPMLocality), ++ VMSTATE_UINT32(sts, TPMLocality), ++ VMSTATE_UINT32(iface_id, TPMLocality), ++ VMSTATE_END_OF_LIST(), ++ } ++}; ++ +diff --git a/hw/tpm/tpm_tis_common.c.orig b/hw/tpm/tpm_tis_common.c.orig +new file mode 100644 +index 00000000..e69de29b +diff --git a/hw/tpm/tpm_tis_common.c.rej b/hw/tpm/tpm_tis_common.c.rej +new file mode 100644 +index 00000000..e6d08007 +--- /dev/null ++++ b/hw/tpm/tpm_tis_common.c.rej +@@ -0,0 +1,137 @@ ++--- hw/tpm/tpm_tis.c +++++ hw/tpm/tpm_tis_common.c ++@@ -870,134 +810,3 @@ static const VMStateDescription vmstate_locty = { ++ } ++ }; ++ ++-/* ISA */ ++- ++-static int tpm_tis_pre_save_isa(void *opaque) ++-{ ++- TPMStateISA *isadev = opaque; ++- ++- return tpm_tis_pre_save(&isadev->state); ++-} ++- ++-static const VMStateDescription vmstate_tpm_tis_isa = { ++- .name = "tpm-tis", ++- .version_id = 0, ++- .pre_save = tpm_tis_pre_save_isa, ++- .fields = (VMStateField[]) { ++- VMSTATE_BUFFER(state.buffer, TPMStateISA), ++- VMSTATE_UINT16(state.rw_offset, TPMStateISA), ++- VMSTATE_UINT8(state.active_locty, TPMStateISA), ++- VMSTATE_UINT8(state.aborting_locty, TPMStateISA), ++- VMSTATE_UINT8(state.next_locty, TPMStateISA), ++- ++- VMSTATE_STRUCT_ARRAY(state.loc, TPMStateISA, TPM_TIS_NUM_LOCALITIES, 0, ++- vmstate_locty, TPMLocality), ++- ++- VMSTATE_END_OF_LIST() ++- } ++-}; ++- ++-static void tpm_tis_isa_request_completed(TPMIf *ti, int ret) ++-{ ++- TPMStateISA *isadev = TPM_TIS_ISA(ti); ++- TPMState *s = &isadev->state; ++- ++- tpm_tis_request_completed(s, ret); ++-} ++- ++-static enum TPMVersion tpm_tis_isa_get_tpm_version(TPMIf *ti) ++-{ ++- TPMStateISA *isadev = TPM_TIS_ISA(ti); ++- TPMState *s = &isadev->state; ++- ++- return tpm_tis_get_tpm_version(s); ++-} ++- ++-static void tpm_tis_isa_reset(DeviceState *dev) ++-{ ++- TPMStateISA *isadev = TPM_TIS_ISA(dev); ++- TPMState *s = &isadev->state; ++- ++- return tpm_tis_reset(s); ++-} ++- ++-static Property tpm_tis_isa_properties[] = { ++- DEFINE_PROP_UINT32("irq", TPMStateISA, state.irq_num, TPM_TIS_IRQ), ++- DEFINE_PROP_TPMBE("tpmdev", TPMStateISA, state.be_driver), ++- DEFINE_PROP_BOOL("ppi", TPMStateISA, state.ppi_enabled, true), ++- DEFINE_PROP_END_OF_LIST(), ++-}; ++- ++-static void tpm_tis_isa_initfn(Object *obj) ++-{ ++- TPMStateISA *isadev = TPM_TIS_ISA(obj); ++- TPMState *s = &isadev->state; ++- ++- memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, ++- s, "tpm-tis-mmio", ++- TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); ++-} ++- ++-static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp) ++-{ ++- TPMStateISA *isadev = TPM_TIS_ISA(dev); ++- TPMState *s = &isadev->state; ++- ++- if (!tpm_find()) { ++- error_setg(errp, "at most one TPM device is permitted"); ++- return; ++- } ++- ++- if (!s->be_driver) { ++- error_setg(errp, "'tpmdev' property is required"); ++- return; ++- } ++- if (s->irq_num > 15) { ++- error_setg(errp, "IRQ %d is outside valid range of 0 to 15", ++- s->irq_num); ++- return; ++- } ++- ++- isa_init_irq(ISA_DEVICE(dev), &s->irq, s->irq_num); ++- ++- memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), ++- TPM_TIS_ADDR_BASE, &s->mmio); ++- ++- if (s->ppi_enabled) { ++- tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)), ++- TPM_PPI_ADDR_BASE, OBJECT(dev)); ++- } ++-} ++- ++-static void tpm_tis_isa_class_init(ObjectClass *klass, void *data) ++-{ ++- DeviceClass *dc = DEVICE_CLASS(klass); ++- TPMIfClass *tc = TPM_IF_CLASS(klass); ++- ++- dc->props = tpm_tis_isa_properties; ++- dc->vmsd = &vmstate_tpm_tis_isa; ++- tc->model = TPM_MODEL_TPM_TIS; ++- dc->realize = tpm_tis_isa_realizefn; ++- dc->reset = tpm_tis_isa_reset; ++- tc->request_completed = tpm_tis_isa_request_completed; ++- tc->get_version = tpm_tis_isa_get_tpm_version; ++-} ++- ++-static const TypeInfo tpm_tis_isa_info = { ++- .name = TYPE_TPM_TIS_ISA, ++- .parent = TYPE_ISA_DEVICE, ++- .instance_size = sizeof(TPMStateISA), ++- .instance_init = tpm_tis_isa_initfn, ++- .class_init = tpm_tis_isa_class_init, ++- .interfaces = (InterfaceInfo[]) { ++- { TYPE_TPM_IF }, ++- { } ++- } ++-}; ++- ++-static void tpm_tis_isa_register(void) ++-{ ++- type_register_static(&tpm_tis_isa_info); ++-} ++- ++-type_init(tpm_tis_isa_register) +diff --git a/hw/tpm/tpm_tis_isa.c b/hw/tpm/tpm_tis_isa.c +new file mode 100644 +index 00000000..30ba3707 +--- /dev/null ++++ b/hw/tpm/tpm_tis_isa.c +@@ -0,0 +1,170 @@ ++/* ++ * tpm_tis_isa.c - QEMU's TPM TIS ISA Device ++ * ++ * Copyright (C) 2006,2010-2013 IBM Corporation ++ * ++ * Authors: ++ * Stefan Berger ++ * David Safford ++ * ++ * Xen 4 support: Andrease Niederl ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ * Implementation of the TIS interface according to specs found at ++ * http://www.trustedcomputinggroup.org. This implementation currently ++ * supports version 1.3, 21 March 2013 ++ * In the developers menu choose the PC Client section then find the TIS ++ * specification. ++ * ++ * TPM TIS for TPM 2 implementation following TCG PC Client Platform ++ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 ++ */ ++ ++#include "qemu/osdep.h" ++#include "hw/isa/isa.h" ++#include "hw/qdev-properties.h" ++#include "migration/vmstate.h" ++#include "tpm_util.h" ++#include "tpm_tis.h" ++ ++typedef struct TPMStateISA { ++ /*< private >*/ ++ ISADevice parent_obj; ++ ++ /*< public >*/ ++ TPMState state; /* not a QOM object */ ++} TPMStateISA; ++ ++#define TPM_TIS_ISA(obj) OBJECT_CHECK(TPMStateISA, (obj), TYPE_TPM_TIS_ISA) ++ ++static int tpm_tis_pre_save_isa(void *opaque) ++{ ++ TPMStateISA *isadev = opaque; ++ ++ return tpm_tis_pre_save(&isadev->state); ++} ++ ++static const VMStateDescription vmstate_tpm_tis_isa = { ++ .name = "tpm-tis", ++ .version_id = 0, ++ .pre_save = tpm_tis_pre_save_isa, ++ .fields = (VMStateField[]) { ++ VMSTATE_BUFFER(state.buffer, TPMStateISA), ++ VMSTATE_UINT16(state.rw_offset, TPMStateISA), ++ VMSTATE_UINT8(state.active_locty, TPMStateISA), ++ VMSTATE_UINT8(state.aborting_locty, TPMStateISA), ++ VMSTATE_UINT8(state.next_locty, TPMStateISA), ++ ++ VMSTATE_STRUCT_ARRAY(state.loc, TPMStateISA, TPM_TIS_NUM_LOCALITIES, 0, ++ vmstate_locty, TPMLocality), ++ ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static void tpm_tis_isa_request_completed(TPMIf *ti, int ret) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(ti); ++ TPMState *s = &isadev->state; ++ ++ tpm_tis_request_completed(s, ret); ++} ++ ++static enum TPMVersion tpm_tis_isa_get_tpm_version(TPMIf *ti) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(ti); ++ TPMState *s = &isadev->state; ++ ++ return tpm_tis_get_tpm_version(s); ++} ++ ++static void tpm_tis_isa_reset(DeviceState *dev) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(dev); ++ TPMState *s = &isadev->state; ++ ++ return tpm_tis_reset(s); ++} ++ ++static Property tpm_tis_isa_properties[] = { ++ DEFINE_PROP_UINT32("irq", TPMStateISA, state.irq_num, TPM_TIS_IRQ), ++ DEFINE_PROP_TPMBE("tpmdev", TPMStateISA, state.be_driver), ++ DEFINE_PROP_BOOL("ppi", TPMStateISA, state.ppi_enabled, true), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static void tpm_tis_isa_initfn(Object *obj) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(obj); ++ TPMState *s = &isadev->state; ++ ++ memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, ++ s, "tpm-tis-mmio", ++ TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); ++} ++ ++static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(dev); ++ TPMState *s = &isadev->state; ++ ++ if (!tpm_find()) { ++ error_setg(errp, "at most one TPM device is permitted"); ++ return; ++ } ++ ++ if (!s->be_driver) { ++ error_setg(errp, "'tpmdev' property is required"); ++ return; ++ } ++ if (s->irq_num > 15) { ++ error_setg(errp, "IRQ %d is outside valid range of 0 to 15", ++ s->irq_num); ++ return; ++ } ++ ++ isa_init_irq(ISA_DEVICE(dev), &s->irq, s->irq_num); ++ ++ memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), ++ TPM_TIS_ADDR_BASE, &s->mmio); ++ ++ if (s->ppi_enabled) { ++ tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)), ++ TPM_PPI_ADDR_BASE, OBJECT(dev)); ++ } ++} ++ ++static void tpm_tis_isa_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ TPMIfClass *tc = TPM_IF_CLASS(klass); ++ ++ dc->props = tpm_tis_isa_properties; ++ dc->vmsd = &vmstate_tpm_tis_isa; ++ tc->model = TPM_MODEL_TPM_TIS; ++ dc->realize = tpm_tis_isa_realizefn; ++ dc->reset = tpm_tis_isa_reset; ++ tc->request_completed = tpm_tis_isa_request_completed; ++ tc->get_version = tpm_tis_isa_get_tpm_version; ++} ++ ++static const TypeInfo tpm_tis_isa_info = { ++ .name = TYPE_TPM_TIS_ISA, ++ .parent = TYPE_ISA_DEVICE, ++ .instance_size = sizeof(TPMStateISA), ++ .instance_init = tpm_tis_isa_initfn, ++ .class_init = tpm_tis_isa_class_init, ++ .interfaces = (InterfaceInfo[]) { ++ { TYPE_TPM_IF }, ++ { } ++ } ++}; ++ ++static void tpm_tis_isa_register(void) ++{ ++ type_register_static(&tpm_tis_isa_info); ++} ++ ++type_init(tpm_tis_isa_register) +-- +2.23.0 + diff --git a/tpm-Use-TPMState-as-a-common-struct.patch.patch b/tpm-Use-TPMState-as-a-common-struct.patch.patch new file mode 100644 index 0000000000000000000000000000000000000000..8bc80837434554fc44fe581f66a26fe348bb1b2a --- /dev/null +++ b/tpm-Use-TPMState-as-a-common-struct.patch.patch @@ -0,0 +1,294 @@ +From 6a462e50852e6afca4f0623654212ea09112aaee Mon Sep 17 00:00:00 2001 +From: jiangfangjie +Date: Wed, 29 Jul 2020 12:20:09 +0000 +Subject: [PATCH] 4294-tpm-Use-TPMState-as-a-common-struct.patch + +--- + hw/tpm/tpm_tis.c | 147 +++++++++++++++++++++++++++++------------------ + 1 file changed, 92 insertions(+), 55 deletions(-) + +diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c +index 49d44652..5fa96f40 100644 +--- a/hw/tpm/tpm_tis.c ++++ b/hw/tpm/tpm_tis.c +@@ -62,7 +62,6 @@ typedef struct TPMLocality { + } TPMLocality; + + typedef struct TPMState { +- ISADevice busdev; + MemoryRegion mmio; + + unsigned char buffer[TPM_TIS_BUFFER_MAX]; +@@ -88,7 +87,15 @@ typedef struct TPMState { + TPMPPI ppi; + } TPMState; + +-#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS_ISA) ++typedef struct TPMStateISA { ++ /*< private >*/ ++ ISADevice parent_obj; ++ ++ /*< public >*/ ++ TPMState state; /* not a QOM object */ ++} TPMStateISA; ++ ++#define TPM_TIS_ISA(obj) OBJECT_CHECK(TPMStateISA, (obj), TYPE_TPM_TIS_ISA) + + #define DEBUG_TIS 0 + +@@ -278,9 +285,8 @@ static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty) + /* + * Callback from the TPM to indicate that the response was received. + */ +-static void tpm_tis_request_completed(TPMIf *ti, int ret) ++static void tpm_tis_request_completed(TPMState *s, int ret) + { +- TPMState *s = TPM(ti); + uint8_t locty = s->cmd.locty; + uint8_t l; + +@@ -335,7 +341,7 @@ static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) + } + + #ifdef DEBUG_TIS +-static void tpm_tis_dump_state(void *opaque, hwaddr addr) ++static void tpm_tis_dump_state(TPMState *s, hwaddr addr) + { + static const unsigned regs[] = { + TPM_TIS_REG_ACCESS, +@@ -350,7 +356,6 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) + int idx; + uint8_t locty = tpm_tis_locality_from_addr(addr); + hwaddr base = addr & ~0xfff; +- TPMState *s = opaque; + + printf("tpm_tis: active locality : %d\n" + "tpm_tis: state of locality %d : %d\n" +@@ -360,7 +365,7 @@ static void tpm_tis_dump_state(void *opaque, hwaddr addr) + + for (idx = 0; regs[idx] != 0xfff; idx++) { + printf("tpm_tis: 0x%04x : 0x%08x\n", regs[idx], +- (int)tpm_tis_mmio_read(opaque, base + regs[idx], 4)); ++ (int)tpm_tis_mmio_read(s, base + regs[idx], 4)); + } + + printf("tpm_tis: r/w offset : %d\n" +@@ -485,7 +490,7 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, + break; + #ifdef DEBUG_TIS + case TPM_TIS_REG_DEBUG: +- tpm_tis_dump_state(opaque, addr); ++ tpm_tis_dump_state(s, addr); + break; + #endif + } +@@ -832,10 +837,8 @@ static const MemoryRegionOps tpm_tis_memory_ops = { + /* + * Get the TPMVersion of the backend device being used + */ +-static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti) ++static enum TPMVersion tpm_tis_get_tpm_version(TPMState *s) + { +- TPMState *s = TPM(ti); +- + if (tpm_backend_had_startup_error(s->be_driver)) { + return TPM_VERSION_UNSPEC; + } +@@ -847,9 +850,8 @@ static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti) + * This function is called when the machine starts, resets or due to + * S3 resume. + */ +-static void tpm_tis_reset(DeviceState *dev) ++static void tpm_tis_reset(TPMState *s) + { +- TPMState *s = TPM(dev); + int c; + + s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); +@@ -893,15 +895,14 @@ static void tpm_tis_reset(DeviceState *dev) + + /* persistent state handling */ + +-static int tpm_tis_pre_save(void *opaque) ++static int tpm_tis_pre_save(TPMState *s) + { +- TPMState *s = opaque; + uint8_t locty = s->active_locty; + + trace_tpm_tis_pre_save(locty, s->rw_offset); + + if (DEBUG_TIS) { +- tpm_tis_dump_state(opaque, 0); ++ tpm_tis_dump_state(s, 0); + } + + /* +@@ -926,34 +927,78 @@ static const VMStateDescription vmstate_locty = { + } + }; + +-static const VMStateDescription vmstate_tpm_tis = { ++/* ISA */ ++ ++static int tpm_tis_pre_save_isa(void *opaque) ++{ ++ TPMStateISA *isadev = opaque; ++ ++ return tpm_tis_pre_save(&isadev->state); ++} ++ ++static const VMStateDescription vmstate_tpm_tis_isa = { + .name = "tpm-tis", + .version_id = 0, +- .pre_save = tpm_tis_pre_save, ++ .pre_save = tpm_tis_pre_save_isa, + .fields = (VMStateField[]) { +- VMSTATE_BUFFER(buffer, TPMState), +- VMSTATE_UINT16(rw_offset, TPMState), +- VMSTATE_UINT8(active_locty, TPMState), +- VMSTATE_UINT8(aborting_locty, TPMState), +- VMSTATE_UINT8(next_locty, TPMState), ++ VMSTATE_BUFFER(state.buffer, TPMStateISA), ++ VMSTATE_UINT16(state.rw_offset, TPMStateISA), ++ VMSTATE_UINT8(state.active_locty, TPMStateISA), ++ VMSTATE_UINT8(state.aborting_locty, TPMStateISA), ++ VMSTATE_UINT8(state.next_locty, TPMStateISA), + +- VMSTATE_STRUCT_ARRAY(loc, TPMState, TPM_TIS_NUM_LOCALITIES, 0, ++ VMSTATE_STRUCT_ARRAY(state.loc, TPMStateISA, TPM_TIS_NUM_LOCALITIES, 0, + vmstate_locty, TPMLocality), + + VMSTATE_END_OF_LIST() + } + }; + +-static Property tpm_tis_properties[] = { +- DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ), +- DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver), +- DEFINE_PROP_BOOL("ppi", TPMState, ppi_enabled, true), ++static void tpm_tis_isa_request_completed(TPMIf *ti, int ret) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(ti); ++ TPMState *s = &isadev->state; ++ ++ tpm_tis_request_completed(s, ret); ++} ++ ++static enum TPMVersion tpm_tis_isa_get_tpm_version(TPMIf *ti) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(ti); ++ TPMState *s = &isadev->state; ++ ++ return tpm_tis_get_tpm_version(s); ++} ++ ++static void tpm_tis_isa_reset(DeviceState *dev) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(dev); ++ TPMState *s = &isadev->state; ++ ++ return tpm_tis_reset(s); ++} ++ ++static Property tpm_tis_isa_properties[] = { ++ DEFINE_PROP_UINT32("irq", TPMStateISA, state.irq_num, TPM_TIS_IRQ), ++ DEFINE_PROP_TPMBE("tpmdev", TPMStateISA, state.be_driver), ++ DEFINE_PROP_BOOL("ppi", TPMStateISA, state.ppi_enabled, true), + DEFINE_PROP_END_OF_LIST(), + }; + +-static void tpm_tis_realizefn(DeviceState *dev, Error **errp) ++static void tpm_tis_isa_initfn(Object *obj) + { +- TPMState *s = TPM(dev); ++ TPMStateISA *isadev = TPM_TIS_ISA(obj); ++ TPMState *s = &isadev->state; ++ ++ memory_region_init_io(&s->mmio, obj, &tpm_tis_memory_ops, ++ s, "tpm-tis-mmio", ++ TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); ++} ++ ++static void tpm_tis_isa_realizefn(DeviceState *dev, Error **errp) ++{ ++ TPMStateISA *isadev = TPM_TIS_ISA(dev); ++ TPMState *s = &isadev->state; + + if (!tpm_find()) { + error_setg(errp, "at most one TPM device is permitted"); +@@ -970,55 +1015,47 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp) + return; + } + +- isa_init_irq(&s->busdev, &s->irq, s->irq_num); ++ isa_init_irq(ISA_DEVICE(dev), &s->irq, s->irq_num); + + memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)), + TPM_TIS_ADDR_BASE, &s->mmio); + + if (s->ppi_enabled) { + tpm_ppi_init(&s->ppi, isa_address_space(ISA_DEVICE(dev)), +- TPM_PPI_ADDR_BASE, OBJECT(s)); ++ TPM_PPI_ADDR_BASE, OBJECT(dev)); + } + } + +-static void tpm_tis_initfn(Object *obj) +-{ +- TPMState *s = TPM(obj); +- +- memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops, +- s, "tpm-tis-mmio", +- TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT); +-} +- +-static void tpm_tis_class_init(ObjectClass *klass, void *data) ++static void tpm_tis_isa_class_init(ObjectClass *klass, void *data) + { + DeviceClass *dc = DEVICE_CLASS(klass); + TPMIfClass *tc = TPM_IF_CLASS(klass); + +- dc->realize = tpm_tis_realizefn; +- dc->props = tpm_tis_properties; +- dc->reset = tpm_tis_reset; +- dc->vmsd = &vmstate_tpm_tis; ++ dc->props = tpm_tis_isa_properties; ++ dc->vmsd = &vmstate_tpm_tis_isa; + tc->model = TPM_MODEL_TPM_TIS; +- tc->get_version = tpm_tis_get_tpm_version; +- tc->request_completed = tpm_tis_request_completed; ++ dc->realize = tpm_tis_isa_realizefn; ++ dc->reset = tpm_tis_isa_reset; ++ tc->request_completed = tpm_tis_isa_request_completed; ++ tc->get_version = tpm_tis_isa_get_tpm_version; ++ + } + +-static const TypeInfo tpm_tis_info = { ++static const TypeInfo tpm_tis_isa_info = { + .name = TYPE_TPM_TIS_ISA, + .parent = TYPE_ISA_DEVICE, +- .instance_size = sizeof(TPMState), +- .instance_init = tpm_tis_initfn, +- .class_init = tpm_tis_class_init, ++ .instance_size = sizeof(TPMStateISA), ++ .instance_init = tpm_tis_isa_initfn, ++ .class_init = tpm_tis_isa_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_TPM_IF }, + { } + } + }; + +-static void tpm_tis_register(void) ++static void tpm_tis_isa_register(void) + { +- type_register_static(&tpm_tis_info); ++ type_register_static(&tpm_tis_isa_info); + } + +-type_init(tpm_tis_register) ++type_init(tpm_tis_isa_register) +-- +2.23.0 + diff --git a/tpm-ppi-page-align-PPI-RAM.patch b/tpm-ppi-page-align-PPI-RAM.patch new file mode 100644 index 0000000000000000000000000000000000000000..5863db211ffab4ac22463d41b170d8603c955d2e --- /dev/null +++ b/tpm-ppi-page-align-PPI-RAM.patch @@ -0,0 +1,42 @@ +From 71e415c8a75c130875f14d6b2136825789feb297 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Fri, 3 Jan 2020 11:39:59 +0400 +Subject: [PATCH 3339/5109] tpm-ppi: page-align PPI RAM +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +post-copy migration fails on destination with error such as: +2019-12-26T10:22:44.714644Z qemu-kvm: ram_block_discard_range: +Unaligned start address: 0x559d2afae9a0 + +Use qemu_memalign() to constrain the PPI RAM memory alignment. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Marc-André Lureau +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Dr. David Alan Gilbert +Reviewed-by: Stefan Berger +Signed-off-by: Stefan Berger +Message-id: 20200103074000.1006389-3-marcandre.lureau@redhat.com +--- + hw/tpm/tpm_ppi.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/tpm/tpm_ppi.c b/hw/tpm/tpm_ppi.c +index ff314592b4..6d9c1a3e40 100644 +--- a/hw/tpm/tpm_ppi.c ++++ b/hw/tpm/tpm_ppi.c +@@ -43,7 +43,8 @@ void tpm_ppi_reset(TPMPPI *tpmppi) + void tpm_ppi_init(TPMPPI *tpmppi, struct MemoryRegion *m, + hwaddr addr, Object *obj) + { +- tpmppi->buf = g_malloc0(HOST_PAGE_ALIGN(TPM_PPI_ADDR_SIZE)); ++ tpmppi->buf = qemu_memalign(qemu_real_host_page_size, ++ HOST_PAGE_ALIGN(TPM_PPI_ADDR_SIZE)); + memory_region_init_ram_device_ptr(&tpmppi->ram, obj, "tpm-ppi", + TPM_PPI_ADDR_SIZE, tpmppi->buf); + vmstate_register_ram(&tpmppi->ram, DEVICE(obj)); +-- +2.18.2 + diff --git a/tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch b/tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch new file mode 100644 index 0000000000000000000000000000000000000000..4c07bd79670b5dc627a7b4e21c04e328ab01b486 --- /dev/null +++ b/tpm-rename-TPM_TIS-into-TPM_TIS_ISA.patch @@ -0,0 +1,100 @@ +From 43bc7f84e14083eda3959127a2346c0f7e31a7ae Mon Sep 17 00:00:00 2001 +From: Eric Auger +Date: Thu, 5 Mar 2020 17:51:40 +0100 +Subject: [PATCH 4293/5109] tpm: rename TPM_TIS into TPM_TIS_ISA +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As we plan to introduce a sysbus TPM_TIS, let's rename +TPM_TIS into TPM_TIS_ISA. + +Signed-off-by: Eric Auger +Reviewed-by: Stefan Berger +Reviewed-by: Philippe Mathieu-Daudé +Tested-by: Ard Biesheuvel +Acked-by: Ard Biesheuvel +Message-id: 20200305165149.618-2-eric.auger@redhat.com +Signed-off-by: Stefan Berger +--- + hw/i386/acpi-build.c | 6 +++--- + hw/tpm/tpm_tis.c | 4 ++-- + include/sysemu/tpm.h | 6 +++--- + 3 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c +index 9c4e46f..26777f8 100644 +--- a/hw/i386/acpi-build.c ++++ b/hw/i386/acpi-build.c +@@ -2026,7 +2026,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, + } + } + +- if (TPM_IS_TIS(tpm_find())) { ++ if (TPM_IS_TIS_ISA(tpm_find())) { + aml_append(crs, aml_memory32_fixed(TPM_TIS_ADDR_BASE, + TPM_TIS_ADDR_SIZE, AML_READ_WRITE)); + } +@@ -2197,7 +2197,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker, + /* Scan all PCI buses. Generate tables to support hotplug. */ + build_append_pci_bus_devices(scope, bus, pm->pcihp_bridge_en); + +- if (TPM_IS_TIS(tpm)) { ++ if (TPM_IS_TIS_ISA(tpm)) { + if (misc->tpm_version == TPM_VERSION_2_0) { + dev = aml_device("TPM"); + aml_append(dev, aml_name_decl("_HID", +@@ -2304,7 +2304,7 @@ build_tpm2(GArray *table_data, BIOSLinker *linker, GArray *tcpalog) + (char *)&tpm2_ptr->log_area_start_address - table_data->data; + + tpm2_ptr->platform_class = cpu_to_le16(TPM2_ACPI_CLASS_CLIENT); +- if (TPM_IS_TIS(tpm_find())) { ++ if (TPM_IS_TIS_ISA(tpm_find())) { + tpm2_ptr->control_area_address = cpu_to_le64(0); + tpm2_ptr->start_method = cpu_to_le32(TPM2_START_METHOD_MMIO); + } else if (TPM_IS_CRB(tpm_find())) { +diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c +index 31facb8..c609737 100644 +--- a/hw/tpm/tpm_tis.c ++++ b/hw/tpm/tpm_tis.c +@@ -91,7 +91,7 @@ typedef struct TPMState { + TPMPPI ppi; + } TPMState; + +-#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS) ++#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS_ISA) + + #define DEBUG_TIS 0 + +@@ -1008,7 +1008,7 @@ static void tpm_tis_class_init(ObjectClass *klass, void *data) + } + + static const TypeInfo tpm_tis_info = { +- .name = TYPE_TPM_TIS, ++ .name = TYPE_TPM_TIS_ISA, + .parent = TYPE_ISA_DEVICE, + .instance_size = sizeof(TPMState), + .instance_init = tpm_tis_initfn, +diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h +index 15979a3..1691b92 100644 +--- a/include/sysemu/tpm.h ++++ b/include/sysemu/tpm.h +@@ -43,12 +43,12 @@ typedef struct TPMIfClass { + enum TPMVersion (*get_version)(TPMIf *obj); + } TPMIfClass; + +-#define TYPE_TPM_TIS "tpm-tis" ++#define TYPE_TPM_TIS_ISA "tpm-tis" + #define TYPE_TPM_CRB "tpm-crb" + #define TYPE_TPM_SPAPR "tpm-spapr" + +-#define TPM_IS_TIS(chr) \ +- object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS) ++#define TPM_IS_TIS_ISA(chr) \ ++ object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS_ISA) + #define TPM_IS_CRB(chr) \ + object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB) + #define TPM_IS_SPAPR(chr) \ +-- +1.8.3.1 + diff --git a/tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch b/tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch new file mode 100644 index 0000000000000000000000000000000000000000..45dca3466facb453e3bbc47af1f9cc4ba875fbc7 --- /dev/null +++ b/tpm_spapr-Support-TPM-for-ppc64-using-CRQ-based-inte.patch @@ -0,0 +1,552 @@ +From 3676bc69b358d84a6b32d9cd44325048659a32a2 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:32 -0500 +Subject: [PATCH 3419/5109] tpm_spapr: Support TPM for ppc64 using CRQ based + interface + +Implement support for TPM on ppc64 by implementing the vTPM CRQ interface +as a frontend. It can use the tpm_emulator driver backend with the external +swtpm. + +The Linux vTPM driver for ppc64 works with this emulation. + +This TPM emulator also handles the TPM 2 case. + +Signed-off-by: Stefan Berger +Reviewed-by: David Gibson +Message-Id: <20200121152935.649898-4-stefanb@linux.ibm.com> +[dwg: Use device_class_set_props(), tweak Kconfig] +Signed-off-by: David Gibson +--- + docs/specs/tpm.txt | 20 ++- + hw/tpm/Kconfig | 6 + + hw/tpm/Makefile.objs | 1 + + hw/tpm/tpm_spapr.c | 379 +++++++++++++++++++++++++++++++++++++++++++ + hw/tpm/trace-events | 12 ++ + include/sysemu/tpm.h | 3 + + qapi/tpm.json | 6 +- + 7 files changed, 423 insertions(+), 4 deletions(-) + create mode 100644 hw/tpm/tpm_spapr.c + +diff --git a/docs/specs/tpm.txt b/docs/specs/tpm.txt +index 9c8cca042d..9c3e67d8a7 100644 +--- a/docs/specs/tpm.txt ++++ b/docs/specs/tpm.txt +@@ -34,6 +34,12 @@ The CRB interface makes a memory mapped IO region in the area 0xfed40000 - + QEMU files related to TPM CRB interface: + - hw/tpm/tpm_crb.c + ++ ++pSeries (ppc64) machines offer a tpm-spapr device model. ++ ++QEMU files related to the SPAPR interface: ++ - hw/tpm/tpm_spapr.c ++ + = fw_cfg interface = + + The bios/firmware may read the "etc/tpm/config" fw_cfg entry for +@@ -281,7 +287,7 @@ swtpm socket --tpmstate dir=/tmp/mytpm1 \ + --log level=20 + + Command line to start QEMU with the TPM emulator device communicating with +-the swtpm: ++the swtpm (x86): + + qemu-system-x86_64 -display sdl -accel kvm \ + -m 1024 -boot d -bios bios-256k.bin -boot menu=on \ +@@ -289,6 +295,18 @@ qemu-system-x86_64 -display sdl -accel kvm \ + -tpmdev emulator,id=tpm0,chardev=chrtpm \ + -device tpm-tis,tpmdev=tpm0 test.img + ++In case a pSeries machine is emulated, use the following command line: ++ ++qemu-system-ppc64 -display sdl -machine pseries,accel=kvm \ ++ -m 1024 -bios slof.bin -boot menu=on \ ++ -nodefaults -device VGA -device pci-ohci -device usb-kbd \ ++ -chardev socket,id=chrtpm,path=/tmp/mytpm1/swtpm-sock \ ++ -tpmdev emulator,id=tpm0,chardev=chrtpm \ ++ -device tpm-spapr,tpmdev=tpm0 \ ++ -device spapr-vscsi,id=scsi0,reg=0x00002000 \ ++ -device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x3,drive=drive-virtio-disk0,id=virtio-disk0 \ ++ -drive file=test.img,format=raw,if=none,id=drive-virtio-disk0 ++ + + In case SeaBIOS is used as firmware, it should show the TPM menu item + after entering the menu with 'ESC'. +diff --git a/hw/tpm/Kconfig b/hw/tpm/Kconfig +index 4c8ee87d67..4d4ab0855c 100644 +--- a/hw/tpm/Kconfig ++++ b/hw/tpm/Kconfig +@@ -22,3 +22,9 @@ config TPM_EMULATOR + bool + default y + depends on TPMDEV ++ ++config TPM_SPAPR ++ bool ++ default n ++ depends on TPM && PSERIES ++ select TPMDEV +diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs +index de0b85d02a..85eb99ae05 100644 +--- a/hw/tpm/Makefile.objs ++++ b/hw/tpm/Makefile.objs +@@ -4,3 +4,4 @@ common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o + common-obj-$(CONFIG_TPM_CRB) += tpm_crb.o + common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o + common-obj-$(CONFIG_TPM_EMULATOR) += tpm_emulator.o ++obj-$(CONFIG_TPM_SPAPR) += tpm_spapr.o +diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c +new file mode 100644 +index 0000000000..2ac4cb061c +--- /dev/null ++++ b/hw/tpm/tpm_spapr.c +@@ -0,0 +1,379 @@ ++/* ++ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator ++ * ++ * PAPR Virtual TPM ++ * ++ * Copyright (c) 2015, 2017, 2019 IBM Corporation. ++ * ++ * Authors: ++ * Stefan Berger ++ * ++ * This code is licensed under the GPL version 2 or later. See the ++ * COPYING file in the top-level directory. ++ * ++ */ ++ ++#include "qemu/osdep.h" ++#include "qemu/error-report.h" ++#include "qapi/error.h" ++#include "hw/qdev-properties.h" ++#include "migration/vmstate.h" ++ ++#include "sysemu/tpm_backend.h" ++#include "tpm_int.h" ++#include "tpm_util.h" ++ ++#include "hw/ppc/spapr.h" ++#include "hw/ppc/spapr_vio.h" ++#include "trace.h" ++ ++#define DEBUG_SPAPR 0 ++ ++#define VIO_SPAPR_VTPM(obj) \ ++ OBJECT_CHECK(SpaprTpmState, (obj), TYPE_TPM_SPAPR) ++ ++typedef struct TpmCrq { ++ uint8_t valid; /* 0x80: cmd; 0xc0: init crq */ ++ /* 0x81-0x83: CRQ message response */ ++ uint8_t msg; /* see below */ ++ uint16_t len; /* len of TPM request; len of TPM response */ ++ uint32_t data; /* rtce_dma_handle when sending TPM request */ ++ uint64_t reserved; ++} TpmCrq; ++ ++#define SPAPR_VTPM_VALID_INIT_CRQ_COMMAND 0xC0 ++#define SPAPR_VTPM_VALID_COMMAND 0x80 ++#define SPAPR_VTPM_MSG_RESULT 0x80 ++ ++/* msg types for valid = SPAPR_VTPM_VALID_INIT_CRQ */ ++#define SPAPR_VTPM_INIT_CRQ_RESULT 0x1 ++#define SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT 0x2 ++ ++/* msg types for valid = SPAPR_VTPM_VALID_CMD */ ++#define SPAPR_VTPM_GET_VERSION 0x1 ++#define SPAPR_VTPM_TPM_COMMAND 0x2 ++#define SPAPR_VTPM_GET_RTCE_BUFFER_SIZE 0x3 ++#define SPAPR_VTPM_PREPARE_TO_SUSPEND 0x4 ++ ++/* response error messages */ ++#define SPAPR_VTPM_VTPM_ERROR 0xff ++ ++/* error codes */ ++#define SPAPR_VTPM_ERR_COPY_IN_FAILED 0x3 ++#define SPAPR_VTPM_ERR_COPY_OUT_FAILED 0x4 ++ ++#define TPM_SPAPR_BUFFER_MAX 4096 ++ ++typedef struct { ++ SpaprVioDevice vdev; ++ ++ TpmCrq crq; /* track single TPM command */ ++ ++ uint8_t state; ++#define SPAPR_VTPM_STATE_NONE 0 ++#define SPAPR_VTPM_STATE_EXECUTION 1 ++#define SPAPR_VTPM_STATE_COMPLETION 2 ++ ++ unsigned char *buffer; ++ ++ TPMBackendCmd cmd; ++ ++ TPMBackend *be_driver; ++ TPMVersion be_tpm_version; ++ ++ size_t be_buffer_size; ++} SpaprTpmState; ++ ++/* ++ * Send a request to the TPM. ++ */ ++static void tpm_spapr_tpm_send(SpaprTpmState *s) ++{ ++ if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); ++ } ++ ++ s->state = SPAPR_VTPM_STATE_EXECUTION; ++ s->cmd = (TPMBackendCmd) { ++ .locty = 0, ++ .in = s->buffer, ++ .in_len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size), ++ .out = s->buffer, ++ .out_len = s->be_buffer_size, ++ }; ++ ++ tpm_backend_deliver_request(s->be_driver, &s->cmd); ++} ++ ++static int tpm_spapr_process_cmd(SpaprTpmState *s, uint64_t dataptr) ++{ ++ long rc; ++ ++ /* a max. of be_buffer_size bytes can be transported */ ++ rc = spapr_vio_dma_read(&s->vdev, dataptr, ++ s->buffer, s->be_buffer_size); ++ if (rc) { ++ error_report("tpm_spapr_got_payload: DMA read failure"); ++ } ++ /* let vTPM handle any malformed request */ ++ tpm_spapr_tpm_send(s); ++ ++ return rc; ++} ++ ++static inline int spapr_tpm_send_crq(struct SpaprVioDevice *dev, TpmCrq *crq) ++{ ++ return spapr_vio_send_crq(dev, (uint8_t *)crq); ++} ++ ++static int tpm_spapr_do_crq(struct SpaprVioDevice *dev, uint8_t *crq_data) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); ++ TpmCrq local_crq; ++ TpmCrq *crq = &s->crq; /* requests only */ ++ int rc; ++ uint8_t valid = crq_data[0]; ++ uint8_t msg = crq_data[1]; ++ ++ trace_tpm_spapr_do_crq(valid, msg); ++ ++ switch (valid) { ++ case SPAPR_VTPM_VALID_INIT_CRQ_COMMAND: /* Init command/response */ ++ ++ /* Respond to initialization request */ ++ switch (msg) { ++ case SPAPR_VTPM_INIT_CRQ_RESULT: ++ trace_tpm_spapr_do_crq_crq_result(); ++ memset(&local_crq, 0, sizeof(local_crq)); ++ local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND; ++ local_crq.msg = SPAPR_VTPM_INIT_CRQ_RESULT; ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ ++ case SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT: ++ trace_tpm_spapr_do_crq_crq_complete_result(); ++ memset(&local_crq, 0, sizeof(local_crq)); ++ local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND; ++ local_crq.msg = SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT; ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ } ++ ++ break; ++ case SPAPR_VTPM_VALID_COMMAND: /* Payloads */ ++ switch (msg) { ++ case SPAPR_VTPM_TPM_COMMAND: ++ trace_tpm_spapr_do_crq_tpm_command(); ++ if (s->state == SPAPR_VTPM_STATE_EXECUTION) { ++ return H_BUSY; ++ } ++ memcpy(crq, crq_data, sizeof(*crq)); ++ ++ rc = tpm_spapr_process_cmd(s, be32_to_cpu(crq->data)); ++ ++ if (rc == H_SUCCESS) { ++ crq->valid = be16_to_cpu(0); ++ } else { ++ local_crq.valid = SPAPR_VTPM_MSG_RESULT; ++ local_crq.msg = SPAPR_VTPM_VTPM_ERROR; ++ local_crq.len = cpu_to_be16(0); ++ local_crq.data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_IN_FAILED); ++ spapr_tpm_send_crq(dev, &local_crq); ++ } ++ break; ++ ++ case SPAPR_VTPM_GET_RTCE_BUFFER_SIZE: ++ trace_tpm_spapr_do_crq_tpm_get_rtce_buffer_size(s->be_buffer_size); ++ local_crq.valid = SPAPR_VTPM_VALID_COMMAND; ++ local_crq.msg = SPAPR_VTPM_GET_RTCE_BUFFER_SIZE | ++ SPAPR_VTPM_MSG_RESULT; ++ local_crq.len = cpu_to_be16(s->be_buffer_size); ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ ++ case SPAPR_VTPM_GET_VERSION: ++ local_crq.valid = SPAPR_VTPM_VALID_COMMAND; ++ local_crq.msg = SPAPR_VTPM_GET_VERSION | SPAPR_VTPM_MSG_RESULT; ++ local_crq.len = cpu_to_be16(0); ++ switch (s->be_tpm_version) { ++ case TPM_VERSION_1_2: ++ local_crq.data = cpu_to_be32(1); ++ break; ++ case TPM_VERSION_2_0: ++ local_crq.data = cpu_to_be32(2); ++ break; ++ default: ++ g_assert_not_reached(); ++ break; ++ } ++ trace_tpm_spapr_do_crq_get_version(be32_to_cpu(local_crq.data)); ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ ++ case SPAPR_VTPM_PREPARE_TO_SUSPEND: ++ trace_tpm_spapr_do_crq_prepare_to_suspend(); ++ local_crq.valid = SPAPR_VTPM_VALID_COMMAND; ++ local_crq.msg = SPAPR_VTPM_PREPARE_TO_SUSPEND | ++ SPAPR_VTPM_MSG_RESULT; ++ spapr_tpm_send_crq(dev, &local_crq); ++ break; ++ ++ default: ++ trace_tpm_spapr_do_crq_unknown_msg_type(crq->msg); ++ } ++ break; ++ default: ++ trace_tpm_spapr_do_crq_unknown_crq(valid, msg); ++ }; ++ ++ return H_SUCCESS; ++} ++ ++static void tpm_spapr_request_completed(TPMIf *ti, int ret) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(ti); ++ TpmCrq *crq = &s->crq; ++ uint32_t len; ++ int rc; ++ ++ s->state = SPAPR_VTPM_STATE_COMPLETION; ++ ++ /* a max. of be_buffer_size bytes can be transported */ ++ len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size); ++ rc = spapr_vio_dma_write(&s->vdev, be32_to_cpu(crq->data), ++ s->buffer, len); ++ ++ if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) { ++ tpm_util_show_buffer(s->buffer, len, "From TPM"); ++ } ++ ++ crq->valid = SPAPR_VTPM_MSG_RESULT; ++ if (rc == H_SUCCESS) { ++ crq->msg = SPAPR_VTPM_TPM_COMMAND | SPAPR_VTPM_MSG_RESULT; ++ crq->len = cpu_to_be16(len); ++ } else { ++ error_report("%s: DMA write failure", __func__); ++ crq->msg = SPAPR_VTPM_VTPM_ERROR; ++ crq->len = cpu_to_be16(0); ++ crq->data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_OUT_FAILED); ++ } ++ ++ rc = spapr_tpm_send_crq(&s->vdev, crq); ++ if (rc) { ++ error_report("%s: Error sending response", __func__); ++ } ++} ++ ++static int tpm_spapr_do_startup_tpm(SpaprTpmState *s, size_t buffersize) ++{ ++ return tpm_backend_startup_tpm(s->be_driver, buffersize); ++} ++ ++static const char *tpm_spapr_get_dt_compatible(SpaprVioDevice *dev) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); ++ ++ switch (s->be_tpm_version) { ++ case TPM_VERSION_1_2: ++ return "IBM,vtpm"; ++ case TPM_VERSION_2_0: ++ return "IBM,vtpm20"; ++ default: ++ g_assert_not_reached(); ++ } ++} ++ ++static void tpm_spapr_reset(SpaprVioDevice *dev) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); ++ ++ s->state = SPAPR_VTPM_STATE_NONE; ++ ++ s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); ++ ++ s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver), ++ TPM_SPAPR_BUFFER_MAX); ++ ++ tpm_backend_reset(s->be_driver); ++ tpm_spapr_do_startup_tpm(s, s->be_buffer_size); ++} ++ ++static enum TPMVersion tpm_spapr_get_version(TPMIf *ti) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(ti); ++ ++ if (tpm_backend_had_startup_error(s->be_driver)) { ++ return TPM_VERSION_UNSPEC; ++ } ++ ++ return tpm_backend_get_tpm_version(s->be_driver); ++} ++ ++static const VMStateDescription vmstate_spapr_vtpm = { ++ .name = "tpm-spapr", ++ .unmigratable = 1, ++}; ++ ++static Property tpm_spapr_properties[] = { ++ DEFINE_SPAPR_PROPERTIES(SpaprTpmState, vdev), ++ DEFINE_PROP_TPMBE("tpmdev", SpaprTpmState, be_driver), ++ DEFINE_PROP_END_OF_LIST(), ++}; ++ ++static void tpm_spapr_realizefn(SpaprVioDevice *dev, Error **errp) ++{ ++ SpaprTpmState *s = VIO_SPAPR_VTPM(dev); ++ ++ if (!tpm_find()) { ++ error_setg(errp, "at most one TPM device is permitted"); ++ return; ++ } ++ ++ dev->crq.SendFunc = tpm_spapr_do_crq; ++ ++ if (!s->be_driver) { ++ error_setg(errp, "'tpmdev' property is required"); ++ return; ++ } ++ s->buffer = g_malloc(TPM_SPAPR_BUFFER_MAX); ++} ++ ++static void tpm_spapr_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass); ++ TPMIfClass *tc = TPM_IF_CLASS(klass); ++ ++ k->realize = tpm_spapr_realizefn; ++ k->reset = tpm_spapr_reset; ++ k->dt_name = "vtpm"; ++ k->dt_type = "IBM,vtpm"; ++ k->get_dt_compatible = tpm_spapr_get_dt_compatible; ++ k->signal_mask = 0x00000001; ++ set_bit(DEVICE_CATEGORY_MISC, dc->categories); ++ dc->props = tpm_spapr_properties; ++ k->rtce_window_size = 0x10000000; ++ dc->vmsd = &vmstate_spapr_vtpm; ++ ++ tc->model = TPM_MODEL_TPM_SPAPR; ++ tc->get_version = tpm_spapr_get_version; ++ tc->request_completed = tpm_spapr_request_completed; ++} ++ ++static const TypeInfo tpm_spapr_info = { ++ .name = TYPE_TPM_SPAPR, ++ .parent = TYPE_VIO_SPAPR_DEVICE, ++ .instance_size = sizeof(SpaprTpmState), ++ .class_init = tpm_spapr_class_init, ++ .interfaces = (InterfaceInfo[]) { ++ { TYPE_TPM_IF }, ++ { } ++ } ++}; ++ ++static void tpm_spapr_register_types(void) ++{ ++ type_register_static(&tpm_spapr_info); ++} ++ ++type_init(tpm_spapr_register_types) +diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events +index 357c9e9a84..9143a8eaa3 100644 +--- a/hw/tpm/trace-events ++++ b/hw/tpm/trace-events +@@ -55,3 +55,15 @@ tpm_tis_pre_save(uint8_t locty, uint32_t rw_offset) "locty: %d, rw_offset = %u" + + # tpm_ppi.c + tpm_ppi_memset(uint8_t *ptr, size_t size) "memset: %p %zu" ++ ++# hw/tpm/tpm_spapr.c ++tpm_spapr_show_buffer(const char *direction, size_t len, const char *buf) "direction: %s len: %zu\n%s" ++tpm_spapr_do_crq(uint8_t raw1, uint8_t raw2) "1st 2 bytes in CRQ: 0x%02x 0x%02x" ++tpm_spapr_do_crq_crq_result(void) "SPAPR_VTPM_INIT_CRQ_RESULT" ++tpm_spapr_do_crq_crq_complete_result(void) "SPAPR_VTPM_INIT_CRQ_COMP_RESULT" ++tpm_spapr_do_crq_tpm_command(void) "got TPM command payload" ++tpm_spapr_do_crq_tpm_get_rtce_buffer_size(size_t buffersize) "response: buffer size is %zu" ++tpm_spapr_do_crq_get_version(uint32_t version) "response: version %u" ++tpm_spapr_do_crq_prepare_to_suspend(void) "response: preparing to suspend" ++tpm_spapr_do_crq_unknown_msg_type(uint8_t type) "Unknown message type 0x%02x" ++tpm_spapr_do_crq_unknown_crq(uint8_t raw1, uint8_t raw2) "unknown CRQ 0x%02x 0x%02x ..." +diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h +index 5b541a71c8..15979a3647 100644 +--- a/include/sysemu/tpm.h ++++ b/include/sysemu/tpm.h +@@ -45,11 +45,14 @@ typedef struct TPMIfClass { + + #define TYPE_TPM_TIS "tpm-tis" + #define TYPE_TPM_CRB "tpm-crb" ++#define TYPE_TPM_SPAPR "tpm-spapr" + + #define TPM_IS_TIS(chr) \ + object_dynamic_cast(OBJECT(chr), TYPE_TPM_TIS) + #define TPM_IS_CRB(chr) \ + object_dynamic_cast(OBJECT(chr), TYPE_TPM_CRB) ++#define TPM_IS_SPAPR(chr) \ ++ object_dynamic_cast(OBJECT(chr), TYPE_TPM_SPAPR) + + /* returns NULL unless there is exactly one TPM device */ + static inline TPMIf *tpm_find(void) +diff --git a/qapi/tpm.json b/qapi/tpm.json +index b30323bb6b..63878aa0f4 100644 +--- a/qapi/tpm.json ++++ b/qapi/tpm.json +@@ -12,11 +12,11 @@ + # + # @tpm-tis: TPM TIS model + # @tpm-crb: TPM CRB model (since 2.12) ++# @tpm-spapr: TPM SPAPR model (since 5.0) + # + # Since: 1.5 + ## +-{ 'enum': 'TpmModel', 'data': [ 'tpm-tis', 'tpm-crb' ] } +- ++{ 'enum': 'TpmModel', 'data': [ 'tpm-tis', 'tpm-crb', 'tpm-spapr' ] } + ## + # @query-tpm-models: + # +@@ -29,7 +29,7 @@ + # Example: + # + # -> { "execute": "query-tpm-models" } +-# <- { "return": [ "tpm-tis", "tpm-crb" ] } ++# <- { "return": [ "tpm-tis", "tpm-crb", "tpm-spapr" ] } + # + ## + { 'command': 'query-tpm-models', 'returns': ['TpmModel'] } +-- +2.18.2 + diff --git a/tpm_spapr-Support-suspend-and-resume.patch b/tpm_spapr-Support-suspend-and-resume.patch new file mode 100644 index 0000000000000000000000000000000000000000..b8e7044bd36ca261e647df25bd144affaf20a5f4 --- /dev/null +++ b/tpm_spapr-Support-suspend-and-resume.patch @@ -0,0 +1,118 @@ +From ee9a8129d3d975271d4efed1b37b7dac956e7bf5 Mon Sep 17 00:00:00 2001 +From: Stefan Berger +Date: Tue, 21 Jan 2020 10:29:33 -0500 +Subject: [PATCH 3420/5109] tpm_spapr: Support suspend and resume +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Extend the tpm_spapr frontend with VM suspend and resume support. + +Signed-off-by: Stefan Berger +Message-Id: <20200121152935.649898-5-stefanb@linux.ibm.com> +Reviewed-by: Marc-André Lureau +Signed-off-by: David Gibson +--- + hw/tpm/tpm_spapr.c | 52 ++++++++++++++++++++++++++++++++++++++++++++- + hw/tpm/trace-events | 2 ++ + 2 files changed, 53 insertions(+), 1 deletion(-) + +diff --git a/hw/tpm/tpm_spapr.c b/hw/tpm/tpm_spapr.c +index 2ac4cb061c..ce65eb2e45 100644 +--- a/hw/tpm/tpm_spapr.c ++++ b/hw/tpm/tpm_spapr.c +@@ -76,6 +76,8 @@ typedef struct { + + unsigned char *buffer; + ++ uint32_t numbytes; /* number of bytes to deliver on resume */ ++ + TPMBackendCmd cmd; + + TPMBackend *be_driver; +@@ -240,6 +242,14 @@ static void tpm_spapr_request_completed(TPMIf *ti, int ret) + + /* a max. of be_buffer_size bytes can be transported */ + len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size); ++ ++ if (runstate_check(RUN_STATE_FINISH_MIGRATE)) { ++ trace_tpm_spapr_caught_response(len); ++ /* defer delivery of response until .post_load */ ++ s->numbytes = len; ++ return; ++ } ++ + rc = spapr_vio_dma_write(&s->vdev, be32_to_cpu(crq->data), + s->buffer, len); + +@@ -288,6 +298,7 @@ static void tpm_spapr_reset(SpaprVioDevice *dev) + SpaprTpmState *s = VIO_SPAPR_VTPM(dev); + + s->state = SPAPR_VTPM_STATE_NONE; ++ s->numbytes = 0; + + s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); + +@@ -309,9 +320,48 @@ static enum TPMVersion tpm_spapr_get_version(TPMIf *ti) + return tpm_backend_get_tpm_version(s->be_driver); + } + ++/* persistent state handling */ ++ ++static int tpm_spapr_pre_save(void *opaque) ++{ ++ SpaprTpmState *s = opaque; ++ ++ tpm_backend_finish_sync(s->be_driver); ++ /* ++ * we cannot deliver the results to the VM since DMA would touch VM memory ++ */ ++ ++ return 0; ++} ++ ++static int tpm_spapr_post_load(void *opaque, int version_id) ++{ ++ SpaprTpmState *s = opaque; ++ ++ if (s->numbytes) { ++ trace_tpm_spapr_post_load(); ++ /* deliver the results to the VM via DMA */ ++ tpm_spapr_request_completed(TPM_IF(s), 0); ++ s->numbytes = 0; ++ } ++ ++ return 0; ++} ++ + static const VMStateDescription vmstate_spapr_vtpm = { + .name = "tpm-spapr", +- .unmigratable = 1, ++ .pre_save = tpm_spapr_pre_save, ++ .post_load = tpm_spapr_post_load, ++ .fields = (VMStateField[]) { ++ VMSTATE_SPAPR_VIO(vdev, SpaprTpmState), ++ ++ VMSTATE_UINT8(state, SpaprTpmState), ++ VMSTATE_UINT32(numbytes, SpaprTpmState), ++ VMSTATE_VBUFFER_UINT32(buffer, SpaprTpmState, 0, NULL, numbytes), ++ /* remember DMA address */ ++ VMSTATE_UINT32(crq.data, SpaprTpmState), ++ VMSTATE_END_OF_LIST(), ++ } + }; + + static Property tpm_spapr_properties[] = { +diff --git a/hw/tpm/trace-events b/hw/tpm/trace-events +index 9143a8eaa3..439e514787 100644 +--- a/hw/tpm/trace-events ++++ b/hw/tpm/trace-events +@@ -67,3 +67,5 @@ tpm_spapr_do_crq_get_version(uint32_t version) "response: version %u" + tpm_spapr_do_crq_prepare_to_suspend(void) "response: preparing to suspend" + tpm_spapr_do_crq_unknown_msg_type(uint8_t type) "Unknown message type 0x%02x" + tpm_spapr_do_crq_unknown_crq(uint8_t raw1, uint8_t raw2) "unknown CRQ 0x%02x 0x%02x ..." ++tpm_spapr_post_load(void) "Delivering TPM response after resume" ++tpm_spapr_caught_response(uint32_t v) "Caught response to deliver after resume: %u bytes" +-- +2.18.2 +